Bug 1091575: Implement Bluetooth Core module for Bluetooth daemon (under bluetooth2/), r=btian
authorThomas Zimmermann <tdz@users.sourceforge.net>
Fri, 14 Nov 2014 10:04:34 +0100
changeset 215639 e4cfdcae2f80c160c941158e1cb4aac21ba300a3
parent 215638 c91863c880df6a7032131012475e30269ab5d5e0
child 215640 9b8fec58f964597e19f1b884a7b516a3d113c465
push id12159
push usertdz@users.sourceforge.net
push dateFri, 14 Nov 2014 09:05:57 +0000
treeherderb2g-inbound@b133c8460ea0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbtian
bugs1091575
milestone36.0a1
Bug 1091575: Implement Bluetooth Core module for Bluetooth daemon (under bluetooth2/), r=btian This patch adds support for the Bluetooth daemon's Core module. It provides the basic Bluetooth functionality, such as searching and pairing with devices, and accessing device properties.
dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.cpp
@@ -1,23 +1,179 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothDaemonHelpers.h"
 
+#define MAX_UUID_SIZE 16
+
 BEGIN_BLUETOOTH_NAMESPACE
 
 //
 // Conversion
 //
 
 nsresult
+Convert(bool aIn, uint8_t& aOut)
+{
+  static const bool sValue[] = {
+    CONVERT(false, 0x00),
+    CONVERT(true, 0x01)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
+    aOut = 0;
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sValue[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(bool aIn, BluetoothScanMode& aOut)
+{
+  static const BluetoothScanMode sScanMode[] = {
+    CONVERT(false, SCAN_MODE_CONNECTABLE),
+    CONVERT(true, SCAN_MODE_CONNECTABLE_DISCOVERABLE)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sScanMode))) {
+    aOut = SCAN_MODE_NONE; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sScanMode[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, bool& aOut)
+{
+  static const bool sBool[] = {
+    CONVERT(0x00, false),
+    CONVERT(0x01, true)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBool))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sBool[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothAclState& aOut)
+{
+  static const BluetoothAclState sAclState[] = {
+    CONVERT(0x00, ACL_STATE_CONNECTED),
+    CONVERT(0x01, ACL_STATE_DISCONNECTED),
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAclState))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAclState[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothBondState& aOut)
+{
+  static const BluetoothBondState sBondState[] = {
+    CONVERT(0x00, BOND_STATE_NONE),
+    CONVERT(0x01, BOND_STATE_BONDING),
+    CONVERT(0x02, BOND_STATE_BONDED)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBondState))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sBondState[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(int32_t aIn, BluetoothTypeOfDevice& aOut)
+{
+  static const BluetoothTypeOfDevice sTypeOfDevice[] = {
+    CONVERT(0x00, static_cast<BluetoothTypeOfDevice>(0)), // invalid, required by gcc
+    CONVERT(0x01, TYPE_OF_DEVICE_BREDR),
+    CONVERT(0x02, TYPE_OF_DEVICE_BLE),
+    CONVERT(0x03, TYPE_OF_DEVICE_DUAL)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(static_cast<size_t>(aIn) >= MOZ_ARRAY_LENGTH(sTypeOfDevice))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sTypeOfDevice[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothPropertyType& aOut)
+{
+  static const BluetoothPropertyType sPropertyType[] = {
+    CONVERT(0x00, static_cast<BluetoothPropertyType>(0)), // invalid, required by gcc
+    CONVERT(0x01, PROPERTY_BDNAME),
+    CONVERT(0x02, PROPERTY_BDADDR),
+    CONVERT(0x03, PROPERTY_UUIDS),
+    CONVERT(0x04, PROPERTY_CLASS_OF_DEVICE),
+    CONVERT(0x05, PROPERTY_TYPE_OF_DEVICE),
+    CONVERT(0x06, PROPERTY_SERVICE_RECORD),
+    CONVERT(0x07, PROPERTY_ADAPTER_SCAN_MODE),
+    CONVERT(0x08, PROPERTY_ADAPTER_BONDED_DEVICES),
+    CONVERT(0x09, PROPERTY_ADAPTER_DISCOVERY_TIMEOUT),
+    CONVERT(0x0a, PROPERTY_REMOTE_FRIENDLY_NAME),
+    CONVERT(0x0b, PROPERTY_REMOTE_RSSI),
+    CONVERT(0x0c, PROPERTY_REMOTE_VERSION_INFO)
+  };
+  if (aIn == 0xff) {
+    /* This case is handled separately to not populate
+     * |sPropertyType| with empty entries. */
+    aOut = PROPERTY_REMOTE_DEVICE_TIMESTAMP;
+    return NS_OK;
+  }
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sPropertyType))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sPropertyType[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(int32_t aIn, BluetoothScanMode& aOut)
+{
+  static const BluetoothScanMode sScanMode[] = {
+    CONVERT(0x00, SCAN_MODE_NONE),
+    CONVERT(0x01, SCAN_MODE_CONNECTABLE),
+    CONVERT(0x02, SCAN_MODE_CONNECTABLE_DISCOVERABLE)
+  };
+  if (NS_WARN_IF(aIn < 0) ||
+      NS_WARN_IF(static_cast<size_t>(aIn) >= MOZ_ARRAY_LENGTH(sScanMode))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sScanMode[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothSspVariant& aOut)
+{
+  static const BluetoothSspVariant sSspVariant[] = {
+    CONVERT(0x00, SSP_VARIANT_PASSKEY_CONFIRMATION),
+    CONVERT(0x01, SSP_VARIANT_PASSKEY_ENTRY),
+    CONVERT(0x02, SSP_VARIANT_CONSENT),
+    CONVERT(0x03, SSP_VARIANT_PASSKEY_NOTIFICATION)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sSspVariant))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sSspVariant[aIn];
+  return NS_OK;
+}
+
+nsresult
 Convert(uint8_t aIn, BluetoothStatus& aOut)
 {
   static const BluetoothStatus sStatus[] = {
     CONVERT(0x00, STATUS_SUCCESS),
     CONVERT(0x01, STATUS_FAIL),
     CONVERT(0x02, STATUS_NOT_READY),
     CONVERT(0x03, STATUS_NOMEM),
     CONVERT(0x04, STATUS_BUSY),
@@ -30,36 +186,509 @@ Convert(uint8_t aIn, BluetoothStatus& aO
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sStatus))) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sStatus[aIn];
   return NS_OK;
 }
 
+nsresult
+Convert(uint32_t aIn, int& aOut)
+{
+  aOut = static_cast<int>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(size_t aIn, uint16_t& aOut)
+{
+  if (NS_WARN_IF(aIn >= (1ul << 16))) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<uint16_t>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(const nsAString& aIn, BluetoothAddress& aOut)
+{
+  NS_ConvertUTF16toUTF8 bdAddressUTF8(aIn);
+  const char* str = bdAddressUTF8.get();
+
+  for (size_t i = 0; i < MOZ_ARRAY_LENGTH(aOut.mAddr); ++i, ++str) {
+    aOut.mAddr[i] =
+      static_cast<uint8_t>(strtoul(str, const_cast<char**>(&str), 16));
+  }
+
+  return NS_OK;
+}
+
+nsresult
+Convert(const nsAString& aIn, BluetoothPinCode& aOut)
+{
+  if (NS_WARN_IF(aIn.Length() > MOZ_ARRAY_LENGTH(aOut.mPinCode))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  NS_ConvertUTF16toUTF8 pinCodeUTF8(aIn);
+  const char* str = pinCodeUTF8.get();
+
+  nsAString::size_type i;
+
+  // Fill pin into aOut
+  for (i = 0; i < aIn.Length(); ++i, ++str) {
+    aOut.mPinCode[i] = static_cast<uint8_t>(*str);
+  }
+
+  // Clear remaining bytes in aOut
+  size_t ntrailing = (MOZ_ARRAY_LENGTH(aOut.mPinCode) - aIn.Length()) *
+                     sizeof(aOut.mPinCode[0]);
+  memset(aOut.mPinCode + aIn.Length(), 0, ntrailing);
+
+  aOut.mLength = aIn.Length();
+
+  return NS_OK;
+}
+
+nsresult
+Convert(const nsAString& aIn, BluetoothPropertyType& aOut)
+{
+  if (aIn.EqualsLiteral("Name")) {
+    aOut = PROPERTY_BDNAME;
+  } else if (aIn.EqualsLiteral("Discoverable")) {
+    aOut = PROPERTY_ADAPTER_SCAN_MODE;
+  } else if (aIn.EqualsLiteral("DiscoverableTimeout")) {
+    aOut = PROPERTY_ADAPTER_DISCOVERY_TIMEOUT;
+  } else {
+    BT_LOGR("Invalid property name: %s", NS_ConvertUTF16toUTF8(aIn).get());
+    aOut = static_cast<BluetoothPropertyType>(0); // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  return NS_OK;
+}
+
+nsresult
+Convert(const nsAString& aIn, BluetoothSspVariant& aOut)
+{
+  if (aIn.EqualsLiteral("PasskeyConfirmation")) {
+    aOut = SSP_VARIANT_PASSKEY_CONFIRMATION;
+  } else if (aIn.EqualsLiteral("PasskeyEntry")) {
+    aOut = SSP_VARIANT_PASSKEY_ENTRY;
+  } else if (aIn.EqualsLiteral("Consent")) {
+    aOut = SSP_VARIANT_CONSENT;
+  } else if (aIn.EqualsLiteral("PasskeyNotification")) {
+    aOut = SSP_VARIANT_PASSKEY_NOTIFICATION;
+  } else {
+    BT_LOGR("Invalid SSP variant name: %s", NS_ConvertUTF16toUTF8(aIn).get());
+    aOut = SSP_VARIANT_PASSKEY_CONFIRMATION; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  return NS_OK;
+}
+
+nsresult
+Convert(BluetoothAclState aIn, bool& aOut)
+{
+  static const bool sBool[] = {
+    CONVERT(ACL_STATE_CONNECTED, true),
+    CONVERT(ACL_STATE_DISCONNECTED, false)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBool))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sBool[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(const BluetoothAddress& aIn, nsAString& aOut)
+{
+  char str[BLUETOOTH_ADDRESS_LENGTH + 1];
+
+  int res = snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x",
+                     static_cast<int>(aIn.mAddr[0]),
+                     static_cast<int>(aIn.mAddr[1]),
+                     static_cast<int>(aIn.mAddr[2]),
+                     static_cast<int>(aIn.mAddr[3]),
+                     static_cast<int>(aIn.mAddr[4]),
+                     static_cast<int>(aIn.mAddr[5]));
+  if (NS_WARN_IF(res < 0)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  } else if (NS_WARN_IF((size_t)res >= sizeof(str))) {
+    return NS_ERROR_OUT_OF_MEMORY; /* string buffer too small */
+  }
+
+  aOut = NS_ConvertUTF8toUTF16(str);
+
+  return NS_OK;
+}
+
+nsresult
+Convert(BluetoothPropertyType aIn, uint8_t& aOut)
+{
+  static const uint8_t sPropertyType[] = {
+    CONVERT(PROPERTY_UNKNOWN, 0x00),
+    CONVERT(PROPERTY_BDNAME, 0x01),
+    CONVERT(PROPERTY_BDADDR, 0x02),
+    CONVERT(PROPERTY_UUIDS, 0x03),
+    CONVERT(PROPERTY_CLASS_OF_DEVICE, 0x04),
+    CONVERT(PROPERTY_TYPE_OF_DEVICE, 0x05),
+    CONVERT(PROPERTY_SERVICE_RECORD, 0x06),
+    CONVERT(PROPERTY_ADAPTER_SCAN_MODE, 0x07),
+    CONVERT(PROPERTY_ADAPTER_BONDED_DEVICES, 0x08),
+    CONVERT(PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, 0x09),
+    CONVERT(PROPERTY_REMOTE_FRIENDLY_NAME, 0x0a),
+    CONVERT(PROPERTY_REMOTE_RSSI, 0x0b),
+    CONVERT(PROPERTY_REMOTE_VERSION_INFO, 0x0c),
+    CONVERT(PROPERTY_REMOTE_DEVICE_TIMESTAMP, 0xff)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sPropertyType))) {
+    aOut = 0x00; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sPropertyType[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(const BluetoothRemoteName& aIn, nsAString& aOut)
+{
+  // We construct an nsCString here because the string
+  // returned from the PDU is not 0-terminated.
+  aOut = NS_ConvertUTF8toUTF16(
+    nsCString(reinterpret_cast<const char*>(aIn.mName), sizeof(aIn.mName)));
+  return NS_OK;
+}
+
+nsresult
+Convert(BluetoothScanMode aIn, int32_t& aOut)
+{
+  static const int32_t sScanMode[] = {
+    CONVERT(SCAN_MODE_NONE, 0x00),
+    CONVERT(SCAN_MODE_CONNECTABLE, 0x01),
+    CONVERT(SCAN_MODE_CONNECTABLE_DISCOVERABLE, 0x02)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sScanMode))) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sScanMode[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(BluetoothSspVariant aIn, uint8_t& aOut)
+{
+  static const uint8_t sValue[] = {
+    CONVERT(SSP_VARIANT_PASSKEY_CONFIRMATION, 0x00),
+    CONVERT(SSP_VARIANT_PASSKEY_ENTRY, 0x01),
+    CONVERT(SSP_VARIANT_CONSENT, 0x02),
+    CONVERT(SSP_VARIANT_PASSKEY_NOTIFICATION, 0x03)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sValue[aIn];
+  return NS_OK;
+}
+
+/* |ConvertArray| is a helper for converting arrays. Pass an
+ * instance of this structure as the first argument to |Convert|
+ * to convert an array. The output type has to support the array
+ * subscript operator.
+ */
+template <typename T>
+struct ConvertArray
+{
+  ConvertArray(const T* aData, unsigned long aLength)
+  : mData(aData)
+  , mLength(aLength)
+  { }
+
+  const T* mData;
+  unsigned long mLength;
+};
+
+/* This implementation of |Convert| converts the elements of an
+ * array one-by-one. The result data structures must have enough
+ * memory allocated.
+ */
+template<typename Tin, typename Tout>
+inline nsresult
+Convert(const ConvertArray<Tin>& aIn, Tout& aOut)
+{
+  for (unsigned long i = 0; i < aIn.mLength; ++i) {
+    nsresult rv = Convert(aIn.mData[i], aOut[i]);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
 //
 // Packing
 //
 
 nsresult
+PackPDU(bool aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<bool, uint8_t>(aIn), aPDU);
+}
+
+nsresult
+PackPDU(const BluetoothAddress& aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackArray<uint8_t>(aIn.mAddr, sizeof(aIn.mAddr)), aPDU);
+}
+
+nsresult
 PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(aIn.mType, aIn.mLength,
                  PackArray<uint8_t>(aIn.mValue.get(), aIn.mLength), aPDU);
 }
 
 nsresult
 PackPDU(const BluetoothDaemonPDUHeader& aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(aIn.mService, aIn.mOpcode, aIn.mLength, aPDU);
 }
 
+nsresult
+PackPDU(const BluetoothNamedValue& aIn, BluetoothDaemonPDU& aPDU)
+{
+  nsresult rv = PackPDU(
+    PackConversion<nsString, BluetoothPropertyType>(aIn.name()), aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  if (aIn.value().type() == BluetoothValue::Tuint32_t) {
+    // Set discoverable timeout
+    rv = PackPDU(static_cast<uint16_t>(sizeof(uint32_t)),
+                 aIn.value().get_uint32_t(), aPDU);
+  } else if (aIn.value().type() == BluetoothValue::TnsString) {
+    // Set name
+    const nsCString value =
+      NS_ConvertUTF16toUTF8(aIn.value().get_nsString());
+
+    rv = PackPDU(PackConversion<size_t, uint16_t>(value.Length()),
+                 PackArray<uint8_t>(
+                   reinterpret_cast<const uint8_t*>(value.get()),
+                   value.Length()),
+                 aPDU);
+  } else if (aIn.value().type() == BluetoothValue::Tbool) {
+    // Set scan mode
+    bool value = aIn.value().get_bool();
+
+    rv = PackPDU(static_cast<uint16_t>(sizeof(int32_t)),
+                 PackConversion<bool, BluetoothScanMode>(value), aPDU);
+  } else {
+    BT_LOGR("Invalid property value type");
+    rv = NS_ERROR_ILLEGAL_VALUE;
+  }
+  return rv;
+}
+
+nsresult
+PackPDU(const BluetoothPinCode& aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(aIn.mLength,
+                 PackArray<uint8_t>(aIn.mPinCode, sizeof(aIn.mPinCode)),
+                 aPDU);
+}
+
+nsresult
+PackPDU(BluetoothPropertyType aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<BluetoothPropertyType, uint8_t>(aIn), aPDU);
+}
+
+nsresult
+PackPDU(BluetoothSspVariant aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<BluetoothSspVariant, uint8_t>(aIn),
+                 aPDU);
+}
+
+nsresult
+PackPDU(BluetoothScanMode aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<BluetoothScanMode, int32_t>(aIn), aPDU);
+}
+
 //
 // Unpacking
 //
 
 nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, bool& aOut)
+{
+  return UnpackPDU(aPDU, UnpackConversion<uint8_t, bool>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAclState& aOut)
+{
+  return UnpackPDU(aPDU, UnpackConversion<uint8_t, BluetoothAclState>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothBondState& aOut)
+{
+  return UnpackPDU(aPDU, UnpackConversion<uint8_t, BluetoothBondState>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothTypeOfDevice& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<int32_t, BluetoothTypeOfDevice>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothProperty& aOut)
+{
+  nsresult rv = UnpackPDU(aPDU, aOut.mType);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  uint16_t len;
+  rv = UnpackPDU(aPDU, len);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  switch (aOut.mType) {
+    case PROPERTY_BDNAME:
+      /* fall through */
+    case PROPERTY_REMOTE_FRIENDLY_NAME: {
+        const uint8_t* data = aPDU.Consume(len);
+        if (NS_WARN_IF(!data)) {
+          return NS_ERROR_ILLEGAL_VALUE;
+        }
+        // We construct an nsCString here because the string
+        // returned from the PDU is not 0-terminated.
+        aOut.mString = NS_ConvertUTF8toUTF16(
+          nsCString(reinterpret_cast<const char*>(data), len));
+      }
+      break;
+    case PROPERTY_BDADDR:
+      rv = UnpackPDU<BluetoothAddress>(
+        aPDU, UnpackConversion<BluetoothAddress, nsAString>(aOut.mString));
+      break;
+    case PROPERTY_UUIDS: {
+        size_t numUuids = len / MAX_UUID_SIZE;
+        aOut.mUuidArray.SetLength(numUuids);
+        rv = UnpackPDU(aPDU, aOut.mUuidArray);
+      }
+      break;
+    case PROPERTY_CLASS_OF_DEVICE:
+      /* fall through */
+    case PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+      rv = UnpackPDU(aPDU, aOut.mUint32);
+      break;
+    case PROPERTY_TYPE_OF_DEVICE:
+      rv = UnpackPDU(aPDU, aOut.mTypeOfDevice);
+      break;
+    case PROPERTY_SERVICE_RECORD:
+      rv = UnpackPDU(aPDU, aOut.mServiceRecord);
+      break;
+    case PROPERTY_ADAPTER_SCAN_MODE:
+      rv = UnpackPDU(aPDU, aOut.mScanMode);
+      break;
+    case PROPERTY_ADAPTER_BONDED_DEVICES: {
+        /* unpack addresses */
+        size_t numAddresses = len / BLUETOOTH_ADDRESS_BYTES;
+        nsAutoArrayPtr<BluetoothAddress> addresses;
+        UnpackArray<BluetoothAddress> addressArray(addresses, numAddresses);
+        rv = UnpackPDU(aPDU, addressArray);
+        if (NS_FAILED(rv)) {
+          return rv;
+        }
+        /* convert addresses to strings */
+        aOut.mStringArray.SetLength(numAddresses);
+        ConvertArray<BluetoothAddress> convertArray(addressArray.mData,
+                                                    addressArray.mLength);
+        rv = Convert(convertArray, aOut.mStringArray);
+      }
+      break;
+    case PROPERTY_REMOTE_RSSI: {
+        int8_t rssi;
+        rv = UnpackPDU(aPDU, rssi);
+        aOut.mInt32 = rssi;
+      }
+      break;
+    case PROPERTY_REMOTE_VERSION_INFO:
+      rv = UnpackPDU(aPDU, aOut.mRemoteInfo);
+      break;
+    case PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+      /* nothing to do */
+      break;
+    default:
+      break;
+  }
+  return rv;
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothPropertyType& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothPropertyType>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothRemoteInfo& aOut)
+{
+  nsresult rv = UnpackPDU(aPDU,
+                          UnpackConversion<uint32_t, int>(aOut.mVerMajor));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = UnpackPDU(aPDU, UnpackConversion<uint32_t, int>(aOut.mVerMinor));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return UnpackPDU(aPDU, UnpackConversion<uint32_t, int>(aOut.mManufacturer));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothScanMode& aOut)
+{
+  return UnpackPDU(aPDU, UnpackConversion<int32_t, BluetoothScanMode>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothServiceRecord& aOut)
+{
+  /* unpack UUID */
+  nsresult rv = UnpackPDU(aPDU, aOut.mUuid);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* unpack channel */
+  rv = UnpackPDU(aPDU, aOut.mChannel);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* unpack name */
+  return aPDU.Read(aOut.mName, sizeof(aOut.mName));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothSspVariant& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothSspVariant>(aOut));
+}
+
+nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothStatus& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, BluetoothStatus>(aOut));
 }
 
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHelpers.h
@@ -4,23 +4,37 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluedroid_bluetoothdaemonhelpers_h__
 #define mozilla_dom_bluetooth_bluedroid_bluetoothdaemonhelpers_h__
 
 #include "BluetoothCommon.h"
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/ipc/BluetoothDaemonConnection.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla::ipc;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
+//
+// Helper structures
+//
+
+enum BluetoothAclState {
+  ACL_STATE_CONNECTED,
+  ACL_STATE_DISCONNECTED
+};
+
+struct BluetoothAddress {
+  uint8_t mAddr[6];
+};
+
 struct BluetoothConfigurationParameter {
   uint8_t mType;
   uint16_t mLength;
   nsAutoArrayPtr<uint8_t> mValue;
 };
 
 struct BluetoothDaemonPDUHeader {
   BluetoothDaemonPDUHeader()
@@ -35,51 +49,182 @@ struct BluetoothDaemonPDUHeader {
   , mLength(aLength)
   { }
 
   uint8_t mService;
   uint8_t mOpcode;
   uint16_t mLength;
 };
 
+struct BluetoothPinCode {
+  uint8_t mPinCode[16];
+  uint8_t mLength;
+};
+
+struct BluetoothRemoteName {
+  uint8_t mName[249];
+};
+
 //
 // Conversion
 //
 // PDUs can only store primitive data types, such as integers or
 // strings. Gecko often uses more complex data types, such as
 // enumerators or structures. Conversion functions convert between
 // primitive data and internal Gecko's data types during a PDU's
 // packing and unpacking.
 //
 
 nsresult
+Convert(bool aIn, uint8_t& aOut);
+
+nsresult
+Convert(bool aIn, BluetoothScanMode& aOut);
+
+nsresult
+Convert(uint8_t aIn, bool& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothAclState& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothBondState& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothTypeOfDevice& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothPropertyType& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothScanMode& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothSspVariant& aOut);
+
+nsresult
 Convert(uint8_t aIn, BluetoothStatus& aOut);
 
+nsresult
+Convert(uint32_t aIn, int& aOut);
+
+nsresult
+Convert(size_t aIn, uint16_t& aOut);
+
+nsresult
+Convert(const nsAString& aIn, BluetoothAddress& aOut);
+
+nsresult
+Convert(const nsAString& aIn, BluetoothPinCode& aOut);
+
+nsresult
+Convert(const nsAString& aIn, BluetoothPropertyType& aOut);
+
+nsresult
+Convert(const nsAString& aIn, BluetoothSspVariant& aOut);
+
+nsresult
+Convert(BluetoothAclState aIn, bool& aOut);
+
+nsresult
+Convert(const BluetoothAddress& aIn, nsAString& aOut);
+
+nsresult
+Convert(BluetoothPropertyType aIn, uint8_t& aOut);
+
+nsresult
+Convert(const BluetoothRemoteName& aIn, nsAString& aOut);
+
+nsresult
+Convert(BluetoothScanMode aIn, uint8_t& aOut);
+
+nsresult
+Convert(BluetoothSspVariant aIn, uint8_t& aOut);
+
 //
 // Packing
 //
 
+nsresult
+PackPDU(bool aIn, BluetoothDaemonPDU& aPDU);
+
 inline nsresult
 PackPDU(uint8_t aIn, BluetoothDaemonPDU& aPDU)
 {
   return aPDU.Write(aIn);
 }
 
 inline nsresult
 PackPDU(uint16_t aIn, BluetoothDaemonPDU& aPDU)
 {
   return aPDU.Write(aIn);
 }
 
+inline nsresult
+PackPDU(int32_t aIn, BluetoothDaemonPDU& aPDU)
+{
+  return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(uint32_t aIn, BluetoothDaemonPDU& aPDU)
+{
+  return aPDU.Write(aIn);
+}
+
+nsresult
+PackPDU(const BluetoothAddress& aIn, BluetoothDaemonPDU& aPDU);
+
 nsresult
 PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(const BluetoothDaemonPDUHeader& aIn, BluetoothDaemonPDU& aPDU);
 
+nsresult
+PackPDU(const BluetoothNamedValue& aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(const BluetoothPinCode& aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothPropertyType aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothSspVariant aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothScanMode aIn, BluetoothDaemonPDU& aPDU);
+
+/* |PackConversion| is a helper for packing converted values. Pass
+ * an instance of this structure to |PackPDU| to convert a value from
+ * the input type to the output type and and write it to the PDU.
+ */
+template<typename Tin, typename Tout>
+struct PackConversion {
+  PackConversion(const Tin& aIn)
+  : mIn(aIn)
+  { }
+
+  const Tin& mIn;
+};
+
+template<typename Tin, typename Tout>
+inline nsresult
+PackPDU(const PackConversion<Tin, Tout>& aIn, BluetoothDaemonPDU& aPDU)
+{
+  Tout out;
+
+  nsresult rv = Convert(aIn.mIn, out);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return PackPDU(out, aPDU);
+}
+
 /* |PackArray| is a helper for packing arrays. Pass an instance
  * of this structure as the first argument to |PackPDU| to pack
  * an array. The array's maximum default length is 255 elements.
  */
 template <typename T>
 struct PackArray
 {
   PackArray(const T* aData, size_t aLength)
@@ -102,16 +247,24 @@ PackPDU(const PackArray<T>& aIn, Bluetoo
     nsresult rv = PackPDU(aIn.mData[i], aPDU);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
   return NS_OK;
 }
 
+template<>
+inline nsresult
+PackPDU<uint8_t>(const PackArray<uint8_t>& aIn, BluetoothDaemonPDU& aPDU)
+{
+  /* Write raw bytes in one pass */
+  return aPDU.Write(aIn.mData, aIn.mLength);
+}
+
 template <typename T1, typename T2>
 inline nsresult
 PackPDU(const T1& aIn1, const T2& aIn2, BluetoothDaemonPDU& aPDU)
 {
   nsresult rv = PackPDU(aIn1, aPDU);
   if (NS_FAILED(rv)) {
     return rv;
   }
@@ -154,44 +307,110 @@ PackPDU(const T1& aIn1, const T2& aIn2, 
   return PackPDU(aIn4, aPDU);
 }
 
 //
 // Unpacking
 //
 
 inline nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, int8_t& aOut)
+{
+  return aPDU.Read(aOut);
+}
+
+inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, uint8_t& aOut)
 {
   return aPDU.Read(aOut);
 }
 
 inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, uint16_t& aOut)
 {
   return aPDU.Read(aOut);
 }
 
 inline nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, int32_t& aOut)
+{
+  return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, uint32_t& aOut)
+{
+  return aPDU.Read(aOut);
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, bool& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAclState& aOut);
+
+inline nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAddress& aOut)
+{
+  return aPDU.Read(aOut.mAddr, sizeof(aOut.mAddr));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothBondState& aOut);
+
+inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothDaemonPDUHeader& aOut)
 {
   nsresult rv = UnpackPDU(aPDU, aOut.mService);
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = UnpackPDU(aPDU, aOut.mOpcode);
   if (NS_FAILED(rv)) {
     return rv;
   }
   return UnpackPDU(aPDU, aOut.mLength);
 }
 
 nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothTypeOfDevice& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothRemoteInfo& aOut);
+
+inline nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothRemoteName& aOut)
+{
+  return aPDU.Read(aOut.mName, sizeof(aOut.mName));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothProperty& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothPropertyType& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothScanMode& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothServiceRecord& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothSspVariant& aOut);
+
+nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothStatus& aOut);
 
+inline nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothUuid& aOut)
+{
+  return aPDU.Read(aOut.mUuid, sizeof(aOut.mUuid));
+}
+
 /* |UnpackConversion| is a helper for convering unpacked values. Pass
  * an instance of this structure to |UnpackPDU| to read a value from
  * the PDU in the input type and convert it to the output type.
  */
 template<typename Tin, typename Tout>
 struct UnpackConversion {
   UnpackConversion(Tout& aOut)
   : mOut(aOut)
@@ -207,16 +426,82 @@ UnpackPDU(BluetoothDaemonPDU& aPDU, cons
   Tin in;
   nsresult rv = UnpackPDU(aPDU, in);
   if (NS_FAILED(rv)) {
     return rv;
   }
   return Convert(in, aOut.mOut);
 }
 
+/* |UnpackArray| is a helper for unpacking arrays. Pass an instance
+ * of this structure as the second argument to |UnpackPDU| to unpack
+ * an array.
+ */
+template <typename T>
+struct UnpackArray
+{
+  UnpackArray(T* aData, size_t aLength)
+  : mData(aData)
+  , mLength(aLength)
+  { }
+
+  UnpackArray(nsAutoArrayPtr<T>& aData, size_t aLength)
+  : mData(nullptr)
+  , mLength(aLength)
+  {
+    aData = new T[mLength];
+    mData = aData.get();
+  }
+
+  UnpackArray(nsAutoArrayPtr<T>& aData, size_t aSize, size_t aElemSize)
+  : mData(nullptr)
+  , mLength(aSize / aElemSize)
+  {
+    aData = new T[mLength];
+    mData = aData.get();
+  }
+
+  T* mData;
+  size_t mLength;
+};
+
+template<typename T>
+inline nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, const UnpackArray<T>& aOut)
+{
+  for (size_t i = 0; i < aOut.mLength; ++i) {
+    nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
+template<>
+inline nsresult
+UnpackPDU<uint8_t>(BluetoothDaemonPDU& aPDU, const UnpackArray<uint8_t>& aOut)
+{
+  /* Read raw bytes in one pass */
+  return aPDU.Read(aOut.mData, aOut.mLength);
+}
+
+template<typename T>
+inline nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, nsTArray<T>& aOut)
+{
+  for (typename nsTArray<T>::size_type i = 0; i < aOut.Length(); ++i) {
+    nsresult rv = UnpackPDU(aPDU, aOut[i]);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
 //
 // Init operators
 //
 
 // |PDUInitOP| provides functionality for init operators that unpack PDUs.
 class PDUInitOp
 {
 protected:
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
@@ -196,23 +196,1269 @@ private:
 };
 
 //
 // Core module
 //
 
 static BluetoothNotificationHandler* sNotificationHandler;
 
+class BluetoothDaemonCoreModule
+{
+public:
+  enum {
+    SERVICE_ID = 0x01
+  };
+
+  enum {
+    OPCODE_ERROR = 0x00,
+    OPCODE_ENABLE = 0x01,
+    OPCODE_DISABLE = 0x02,
+    OPCODE_GET_ADAPTER_PROPERTIES = 0x03,
+    OPCODE_GET_ADAPTER_PROPERTY = 0x04,
+    OPCODE_SET_ADAPTER_PROPERTY = 0x05,
+    OPCODE_GET_REMOTE_DEVICE_PROPERTIES = 0x06,
+    OPCODE_GET_REMOTE_DEVICE_PROPERTY = 0x07,
+    OPCODE_SET_REMOTE_DEVICE_PROPERTY = 0x08,
+    OPCODE_GET_REMOTE_SERVICE_RECORD = 0x09,
+    OPCODE_GET_REMOTE_SERVICES = 0x0a,
+    OPCODE_START_DISCOVERY = 0x0b,
+    OPCODE_CANCEL_DISCOVERY = 0x0c,
+    OPCODE_CREATE_BOND = 0x0d,
+    OPCODE_REMOVE_BOND = 0x0e,
+    OPCODE_CANCEL_BOND = 0x0f,
+    OPCODE_PIN_REPLY = 0x10,
+    OPCODE_SSP_REPLY = 0x11,
+    OPCODE_DUT_MODE_CONFIGURE = 0x12,
+    OPCODE_DUT_MODE_SEND = 0x13,
+    OPCODE_LE_TEST_MODE = 0x14,
+    OPCODE_ADAPTER_STATE_CHANGED_NTF = 0x81,
+    OPCODE_ADAPTER_PROPERTIES_CHANGED_NTF = 0x82,
+    OPCODE_REMOTE_DEVICE_PROPERTIES_NTF = 0x83,
+    OPCODE_DEVICE_FOUND_NTF = 0x84,
+    OPCODE_DISCOVERY_STATE_CHANGED_NTF = 0x85,
+    OPCODE_PIN_REQUEST_NTF = 0x86,
+    OPCODE_SSP_REQUEST_NTF = 0x87,
+    OPCODE_BOND_STATE_CHANGED_NTF = 0x88,
+    OPCODE_ACL_STATE_CHANGED_NTF = 0x89,
+    OPCODE_DUT_MODE_RECEIVE_NTF = 0x8a,
+    OPCODE_LE_TEST_MODE_NTF = 0x8b
+  };
+
+  virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
+
+  nsresult EnableCmd(BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_ENABLE, 0));
+
+    nsresult rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult DisableCmd(BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_DISABLE, 0));
+
+    nsresult rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult GetAdapterPropertiesCmd(BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_ADAPTER_PROPERTIES, 0));
+
+    nsresult rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult GetAdapterPropertyCmd(const nsAString& aName,
+                                 BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_ADAPTER_PROPERTY, 0));
+
+    nsresult rv = PackPDU(
+      PackConversion<const nsAString, BluetoothPropertyType>(aName), *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult SetAdapterPropertyCmd(const BluetoothNamedValue& aProperty,
+                                 BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_SET_ADAPTER_PROPERTY, 0));
+
+    nsresult rv = PackPDU(aProperty, *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult GetRemoteDevicePropertiesCmd(const nsAString& aRemoteAddr,
+                                        BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_REMOTE_DEVICE_PROPERTIES,
+                             0));
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult GetRemoteDevicePropertyCmd(const nsAString& aRemoteAddr,
+                                      const nsAString& aName,
+                                      BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_REMOTE_DEVICE_PROPERTY,
+                             0));
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aRemoteAddr),
+      PackConversion<nsAString, BluetoothPropertyType>(aName), *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult SetRemoteDevicePropertyCmd(const nsAString& aRemoteAddr,
+                                      const BluetoothNamedValue& aProperty,
+                                      BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_SET_REMOTE_DEVICE_PROPERTY,
+                             0));
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aRemoteAddr),
+      aProperty, *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult GetRemoteServiceRecordCmd(const nsAString& aRemoteAddr,
+                                     const uint8_t aUuid[16],
+                                     BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_REMOTE_SERVICE_RECORD,
+                             0));
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aRemoteAddr),
+      PackArray<uint8_t>(aUuid, 16), *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult GetRemoteServicesCmd(const nsAString& aRemoteAddr,
+                                BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_GET_REMOTE_SERVICES, 0));
+
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aRemoteAddr), *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult StartDiscoveryCmd(BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_START_DISCOVERY, 0));
+
+    nsresult rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult CancelDiscoveryCmd(BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CANCEL_DISCOVERY, 0));
+
+    nsresult rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult CreateBondCmd(const nsAString& aBdAddr,
+                         BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CREATE_BOND, 0));
+
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aBdAddr), *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult RemoveBondCmd(const nsAString& aBdAddr,
+                         BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_REMOVE_BOND, 0));
+
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aBdAddr), *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult CancelBondCmd(const nsAString& aBdAddr,
+                         BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CANCEL_BOND, 0));
+
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aBdAddr), *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult PinReplyCmd(const nsAString& aBdAddr, bool aAccept,
+                       const nsAString& aPinCode,
+                       BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_PIN_REPLY, 0));
+
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aBdAddr),
+      aAccept,
+      PackConversion<nsAString, BluetoothPinCode>(aPinCode), *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult SspReplyCmd(const nsAString& aBdAddr, const nsAString& aVariant,
+                       bool aAccept, uint32_t aPasskey,
+                       BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_SSP_REPLY, 0));
+
+    nsresult rv = PackPDU(
+      PackConversion<nsAString, BluetoothAddress>(aBdAddr),
+      PackConversion<nsAString, BluetoothSspVariant>(aVariant),
+      aAccept, aPasskey, *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult DutModeConfigureCmd(bool aEnable, BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_DUT_MODE_CONFIGURE, 0));
+
+    nsresult rv = PackPDU(aEnable, *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult DutModeSendCmd(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
+                          BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_DUT_MODE_SEND, 0));
+
+    nsresult rv = PackPDU(aOpcode, aLen, PackArray<uint8_t>(aBuf, aLen),
+                          *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+  nsresult LeTestModeCmd(uint16_t aOpcode, uint8_t* aBuf, uint8_t aLen,
+                         BluetoothResultHandler* aRes)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoPtr<BluetoothDaemonPDU> pdu(
+      new BluetoothDaemonPDU(SERVICE_ID, OPCODE_LE_TEST_MODE, 0));
+
+    nsresult rv = PackPDU(aOpcode, aLen, PackArray<uint8_t>(aBuf, aLen),
+                          *pdu);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = Send(pdu, aRes);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    unused << pdu.forget();
+    return rv;
+  }
+
+protected:
+
+  void HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU, void* aUserData)
+  {
+    static void (BluetoothDaemonCoreModule::* const HandleOp[])(
+      const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = {
+      INIT_ARRAY_AT(0, &BluetoothDaemonCoreModule::HandleRsp),
+      INIT_ARRAY_AT(1, &BluetoothDaemonCoreModule::HandleNtf),
+    };
+
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    /* test notification bit; negating twice maps to 0 or 1 */
+    unsigned int isNtf = !!(aHeader.mOpcode & 0x80);
+
+    (this->*(HandleOp[isNtf]))(aHeader, aPDU, aUserData);
+  }
+
+  nsresult Send(BluetoothDaemonPDU* aPDU, BluetoothResultHandler* aRes)
+  {
+    aRes->AddRef(); // Keep reference for response
+    return Send(aPDU, static_cast<void*>(aRes));
+  }
+
+private:
+
+  // Responses
+  //
+
+  typedef BluetoothResultRunnable0<BluetoothResultHandler, void>
+    ResultRunnable;
+
+  typedef BluetoothResultRunnable1<BluetoothResultHandler, void,
+                                   BluetoothStatus, BluetoothStatus>
+    ErrorRunnable;
+
+  void ErrorRsp(const BluetoothDaemonPDUHeader& aHeader,
+                BluetoothDaemonPDU& aPDU,
+                BluetoothResultHandler* aRes)
+  {
+    ErrorRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::OnError, UnpackPDUInitOp(aPDU));
+  }
+
+  void EnableRsp(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU,
+                 BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::Enable, UnpackPDUInitOp(aPDU));
+  }
+
+  void DisableRsp(const BluetoothDaemonPDUHeader& aHeader,
+                  BluetoothDaemonPDU& aPDU,
+                  BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::Disable, UnpackPDUInitOp(aPDU));
+  }
+
+  void GetAdapterPropertiesRsp(const BluetoothDaemonPDUHeader& aHeader,
+                               BluetoothDaemonPDU& aPDU,
+                               BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::GetAdapterProperties,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void GetAdapterPropertyRsp(const BluetoothDaemonPDUHeader& aHeader,
+                             BluetoothDaemonPDU& aPDU,
+                             BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::GetAdapterProperty,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void SetAdapterPropertyRsp(const BluetoothDaemonPDUHeader& aHeader,
+                             BluetoothDaemonPDU& aPDU,
+                             BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::SetAdapterProperty,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void GetRemoteDevicePropertiesRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                    BluetoothDaemonPDU& aPDU,
+                                    BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::GetRemoteDeviceProperties,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void
+  GetRemoteDevicePropertyRsp(const BluetoothDaemonPDUHeader& aHeader,
+                             BluetoothDaemonPDU& aPDU,
+                             BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::GetRemoteDeviceProperty,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void SetRemoteDevicePropertyRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                  BluetoothDaemonPDU& aPDU,
+                                  BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::SetRemoteDeviceProperty,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void GetRemoteServiceRecordRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                 BluetoothDaemonPDU& aPDU,
+                                 BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::GetRemoteServiceRecord,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void GetRemoteServicesRsp(const BluetoothDaemonPDUHeader& aHeader,
+                            BluetoothDaemonPDU& aPDU,
+                            BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::GetRemoteServices,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void StartDiscoveryRsp(const BluetoothDaemonPDUHeader& aHeader,
+                         BluetoothDaemonPDU& aPDU,
+                         BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::StartDiscovery,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void CancelDiscoveryRsp(const BluetoothDaemonPDUHeader& aHeader,
+                          BluetoothDaemonPDU& aPDU,
+                          BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::CancelDiscovery,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void CreateBondRsp(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU,
+                     BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::CreateBond,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void RemoveBondRsp(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU,
+                     BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::RemoveBond,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void CancelBondRsp(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU,
+                     BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::CancelBond,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void PinReplyRsp(const BluetoothDaemonPDUHeader& aHeader,
+                   BluetoothDaemonPDU& aPDU,
+                   BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::PinReply,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void SspReplyRsp(const BluetoothDaemonPDUHeader& aHeader,
+                   BluetoothDaemonPDU& aPDU,
+                   BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::SspReply,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void DutModeConfigureRsp(const BluetoothDaemonPDUHeader& aHeader,
+                           BluetoothDaemonPDU& aPDU,
+                           BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::DutModeConfigure,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void DutModeSendRsp(const BluetoothDaemonPDUHeader& aHeader,
+                      BluetoothDaemonPDU& aPDU,
+                      BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::DutModeSend,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void LeTestModeRsp(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU,
+                     BluetoothResultHandler* aRes)
+  {
+    ResultRunnable::Dispatch(
+      aRes, &BluetoothResultHandler::LeTestMode,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void HandleRsp(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU, void* aUserData)
+  {
+    static void (BluetoothDaemonCoreModule::* const HandleRsp[])(
+      const BluetoothDaemonPDUHeader&,
+      BluetoothDaemonPDU&,
+      BluetoothResultHandler*) = {
+      INIT_ARRAY_AT(OPCODE_ERROR,
+        &BluetoothDaemonCoreModule::ErrorRsp),
+      INIT_ARRAY_AT(OPCODE_ENABLE,
+        &BluetoothDaemonCoreModule::EnableRsp),
+      INIT_ARRAY_AT(OPCODE_DISABLE,
+        &BluetoothDaemonCoreModule::DisableRsp),
+      INIT_ARRAY_AT(OPCODE_GET_ADAPTER_PROPERTIES,
+        &BluetoothDaemonCoreModule::GetAdapterPropertiesRsp),
+      INIT_ARRAY_AT(OPCODE_GET_ADAPTER_PROPERTY,
+        &BluetoothDaemonCoreModule::GetAdapterPropertyRsp),
+      INIT_ARRAY_AT(OPCODE_SET_ADAPTER_PROPERTY,
+        &BluetoothDaemonCoreModule::SetAdapterPropertyRsp),
+      INIT_ARRAY_AT(OPCODE_GET_REMOTE_DEVICE_PROPERTIES,
+        &BluetoothDaemonCoreModule::GetRemoteDevicePropertiesRsp),
+      INIT_ARRAY_AT(OPCODE_GET_REMOTE_DEVICE_PROPERTY,
+        &BluetoothDaemonCoreModule::GetRemoteDevicePropertyRsp),
+      INIT_ARRAY_AT(OPCODE_SET_REMOTE_DEVICE_PROPERTY,
+        &BluetoothDaemonCoreModule::SetRemoteDevicePropertyRsp),
+      INIT_ARRAY_AT(OPCODE_GET_REMOTE_SERVICE_RECORD,
+        &BluetoothDaemonCoreModule::GetRemoteServiceRecordRsp),
+      INIT_ARRAY_AT(OPCODE_GET_REMOTE_SERVICES,
+        &BluetoothDaemonCoreModule::GetRemoteServicesRsp),
+      INIT_ARRAY_AT(OPCODE_START_DISCOVERY,
+        &BluetoothDaemonCoreModule::StartDiscoveryRsp),
+      INIT_ARRAY_AT(OPCODE_CANCEL_DISCOVERY,
+        &BluetoothDaemonCoreModule::CancelDiscoveryRsp),
+      INIT_ARRAY_AT(OPCODE_CREATE_BOND,
+        &BluetoothDaemonCoreModule::CreateBondRsp),
+      INIT_ARRAY_AT(OPCODE_REMOVE_BOND,
+        &BluetoothDaemonCoreModule::RemoveBondRsp),
+      INIT_ARRAY_AT(OPCODE_CANCEL_BOND,
+        &BluetoothDaemonCoreModule::CancelBondRsp),
+      INIT_ARRAY_AT(OPCODE_PIN_REPLY,
+        &BluetoothDaemonCoreModule::PinReplyRsp),
+      INIT_ARRAY_AT(OPCODE_SSP_REPLY,
+        &BluetoothDaemonCoreModule::SspReplyRsp),
+      INIT_ARRAY_AT(OPCODE_DUT_MODE_CONFIGURE,
+        &BluetoothDaemonCoreModule::DutModeConfigureRsp),
+      INIT_ARRAY_AT(OPCODE_DUT_MODE_SEND,
+        &BluetoothDaemonCoreModule::DutModeSendRsp),
+      INIT_ARRAY_AT(OPCODE_LE_TEST_MODE,
+        &BluetoothDaemonCoreModule::LeTestModeRsp),
+    };
+
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    if (NS_WARN_IF(!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(HandleRsp))) ||
+        NS_WARN_IF(!HandleRsp[aHeader.mOpcode])) {
+      return;
+    }
+
+    nsRefPtr<BluetoothResultHandler> res =
+      already_AddRefed<BluetoothResultHandler>(
+        static_cast<BluetoothResultHandler*>(aUserData));
+
+    if (!res) {
+      return; // Return early if no result handler has been set for response
+    }
+
+    (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
+  }
+
+  // Notifications
+  //
+
+  class NotificationHandlerWrapper
+  {
+  public:
+    typedef BluetoothNotificationHandler ObjectType;
+
+    static ObjectType* GetInstance()
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+
+      return sNotificationHandler;
+    }
+  };
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+                                         bool>
+    AdapterStateChangedNotification;
+
+  typedef BluetoothNotificationRunnable3<NotificationHandlerWrapper, void,
+                                         BluetoothStatus, int,
+                                         nsAutoArrayPtr<BluetoothProperty>,
+                                         BluetoothStatus, int,
+                                         const BluetoothProperty*>
+    AdapterPropertiesNotification;
+
+  typedef BluetoothNotificationRunnable4<NotificationHandlerWrapper, void,
+                                         BluetoothStatus, nsString, int,
+                                         nsAutoArrayPtr<BluetoothProperty>,
+                                         BluetoothStatus, const nsAString&,
+                                         int, const BluetoothProperty*>
+    RemoteDevicePropertiesNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         int,
+                                         nsAutoArrayPtr<BluetoothProperty>,
+                                         int, const BluetoothProperty*>
+    DeviceFoundNotification;
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+                                         bool>
+    DiscoveryStateChangedNotification;
+
+  typedef BluetoothNotificationRunnable3<NotificationHandlerWrapper, void,
+                                         nsString, nsString, uint32_t,
+                                         const nsAString&, const nsAString&>
+    PinRequestNotification;
+
+  typedef BluetoothNotificationRunnable5<NotificationHandlerWrapper, void,
+                                         nsString, nsString, uint32_t,
+                                         BluetoothSspVariant, uint32_t,
+                                         const nsAString&, const nsAString&>
+    SspRequestNotification;
+
+  typedef BluetoothNotificationRunnable3<NotificationHandlerWrapper, void,
+                                         BluetoothStatus, nsString,
+                                         BluetoothBondState,
+                                         BluetoothStatus, const nsAString&>
+    BondStateChangedNotification;
+
+  typedef BluetoothNotificationRunnable3<NotificationHandlerWrapper, void,
+                                         BluetoothStatus, nsString, bool,
+                                         BluetoothStatus, const nsAString&>
+    AclStateChangedNotification;
+
+  typedef BluetoothNotificationRunnable3<NotificationHandlerWrapper, void,
+                                         uint16_t, nsAutoArrayPtr<uint8_t>,
+                                         uint8_t, uint16_t, const uint8_t*>
+    DutModeRecvNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         BluetoothStatus, uint16_t>
+    LeTestModeNotification;
+
+  void AdapterStateChangedNtf(const BluetoothDaemonPDUHeader& aHeader,
+                              BluetoothDaemonPDU& aPDU)
+  {
+    AdapterStateChangedNotification::Dispatch(
+      &BluetoothNotificationHandler::AdapterStateChangedNotification,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  // Init operator class for AdapterPropertiesNotification
+  class AdapterPropertiesInitOp MOZ_FINAL : private PDUInitOp
+  {
+  public:
+    AdapterPropertiesInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+    { }
+
+    nsresult
+    operator () (BluetoothStatus& aArg1, int& aArg2,
+                 nsAutoArrayPtr<BluetoothProperty>& aArg3) const
+    {
+      BluetoothDaemonPDU& pdu = GetPDU();
+
+      /* Read status */
+      nsresult rv = UnpackPDU(pdu, aArg1);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read number of properties */
+      uint8_t numProperties;
+      rv = UnpackPDU(pdu, numProperties);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      aArg2 = numProperties;
+
+      /* Read properties array */
+      UnpackArray<BluetoothProperty> properties(aArg3, aArg2);
+      rv = UnpackPDU(pdu, properties);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      WarnAboutTrailingData();
+      return NS_OK;
+    }
+  };
+
+  void AdapterPropertiesNtf(const BluetoothDaemonPDUHeader& aHeader,
+                            BluetoothDaemonPDU& aPDU)
+  {
+    AdapterPropertiesNotification::Dispatch(
+      &BluetoothNotificationHandler::AdapterPropertiesNotification,
+      AdapterPropertiesInitOp(aPDU));
+  }
+
+  // Init operator class for RemoteDevicePropertiesNotification
+  class RemoteDevicePropertiesInitOp MOZ_FINAL : private PDUInitOp
+  {
+  public:
+    RemoteDevicePropertiesInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+    { }
+
+    nsresult
+    operator () (BluetoothStatus& aArg1, nsString& aArg2, int& aArg3,
+                 nsAutoArrayPtr<BluetoothProperty>& aArg4) const
+    {
+      BluetoothDaemonPDU& pdu = GetPDU();
+
+      /* Read status */
+      nsresult rv = UnpackPDU(pdu, aArg1);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read address */
+      rv = UnpackPDU(
+        pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read number of properties */
+      uint8_t numProperties;
+      rv = UnpackPDU(pdu, numProperties);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      aArg3 = numProperties;
+
+      /* Read properties array */
+      UnpackArray<BluetoothProperty> properties(aArg4, aArg3);
+      rv = UnpackPDU(pdu, properties);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      WarnAboutTrailingData();
+      return NS_OK;
+    }
+  };
+
+  void RemoteDevicePropertiesNtf(const BluetoothDaemonPDUHeader& aHeader,
+                                 BluetoothDaemonPDU& aPDU)
+  {
+    RemoteDevicePropertiesNotification::Dispatch(
+      &BluetoothNotificationHandler::RemoteDevicePropertiesNotification,
+      RemoteDevicePropertiesInitOp(aPDU));
+  }
+
+  // Init operator class for DeviceFoundNotification
+  class DeviceFoundInitOp MOZ_FINAL : private PDUInitOp
+  {
+  public:
+    DeviceFoundInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+    { }
+
+    nsresult
+    operator () (int& aArg1, nsAutoArrayPtr<BluetoothProperty>& aArg2) const
+    {
+      BluetoothDaemonPDU& pdu = GetPDU();
+
+      /* Read number of properties */
+      uint8_t numProperties;
+      nsresult rv = UnpackPDU(pdu, numProperties);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      aArg1 = numProperties;
+
+      /* Read properties array */
+      UnpackArray<BluetoothProperty> properties(aArg2, aArg1);
+      rv = UnpackPDU(pdu, properties);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      WarnAboutTrailingData();
+      return NS_OK;
+    }
+  };
+
+  void DeviceFoundNtf(const BluetoothDaemonPDUHeader& aHeader,
+                      BluetoothDaemonPDU& aPDU)
+  {
+    DeviceFoundNotification::Dispatch(
+      &BluetoothNotificationHandler::DeviceFoundNotification,
+      DeviceFoundInitOp(aPDU));
+  }
+
+  void DiscoveryStateChangedNtf(const BluetoothDaemonPDUHeader& aHeader,
+                                BluetoothDaemonPDU& aPDU)
+  {
+    DiscoveryStateChangedNotification::Dispatch(
+      &BluetoothNotificationHandler::DiscoveryStateChangedNotification,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  // Init operator class for PinRequestNotification
+  class PinRequestInitOp MOZ_FINAL : private PDUInitOp
+  {
+  public:
+    PinRequestInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+    { }
+
+    nsresult
+    operator () (nsString& aArg1, nsString& aArg2, uint32_t& aArg3) const
+    {
+      BluetoothDaemonPDU& pdu = GetPDU();
+
+      /* Read remote address */
+      nsresult rv = UnpackPDU(
+        pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read remote name */
+      rv = UnpackPDU(
+        pdu, UnpackConversion<BluetoothRemoteName, nsAString>(aArg2));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read CoD */
+      rv = UnpackPDU(pdu, aArg3);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      WarnAboutTrailingData();
+      return NS_OK;
+    }
+  };
+
+  void PinRequestNtf(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU)
+  {
+    PinRequestNotification::Dispatch(
+      &BluetoothNotificationHandler::PinRequestNotification,
+      PinRequestInitOp(aPDU));
+  }
+
+  // Init operator class for SspRequestNotification
+  class SspRequestInitOp MOZ_FINAL : private PDUInitOp
+  {
+  public:
+    SspRequestInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+    { }
+
+    nsresult
+    operator () (nsString& aArg1, nsString& aArg2, uint32_t& aArg3,
+                 BluetoothSspVariant aArg4, uint32_t& aArg5) const
+    {
+      BluetoothDaemonPDU& pdu = GetPDU();
+
+      /* Read remote address */
+      nsresult rv = UnpackPDU(
+        pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg1));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read remote name */
+      rv = UnpackPDU(
+        pdu, UnpackConversion<BluetoothRemoteName, nsAString>(aArg2));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read CoD */
+      rv = UnpackPDU(pdu, aArg3);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read pairing variant */
+      rv = UnpackPDU(pdu, aArg4);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read passkey */
+      rv = UnpackPDU(pdu, aArg5);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      WarnAboutTrailingData();
+      return NS_OK;
+    }
+  };
+
+  void SspRequestNtf(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU)
+  {
+    SspRequestNotification::Dispatch(
+      &BluetoothNotificationHandler::SspRequestNotification,
+      SspRequestInitOp(aPDU));
+  }
+
+  // Init operator class for BondStateChangedNotification
+  class BondStateChangedInitOp MOZ_FINAL : private PDUInitOp
+  {
+  public:
+    BondStateChangedInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+    { }
+
+    nsresult
+    operator () (BluetoothStatus& aArg1, nsString& aArg2,
+                 BluetoothBondState& aArg3) const
+    {
+      BluetoothDaemonPDU& pdu = GetPDU();
+
+      /* Read status */
+      nsresult rv = UnpackPDU(pdu, aArg1);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read remote address */
+      rv = UnpackPDU(
+        pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read bond state */
+      rv = UnpackPDU(pdu, aArg3);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      WarnAboutTrailingData();
+      return NS_OK;
+    }
+  };
+
+  void BondStateChangedNtf(const BluetoothDaemonPDUHeader& aHeader,
+                           BluetoothDaemonPDU& aPDU)
+  {
+    BondStateChangedNotification::Dispatch(
+      &BluetoothNotificationHandler::BondStateChangedNotification,
+      BondStateChangedInitOp(aPDU));
+  }
+
+  // Init operator class for AclStateChangedNotification
+  class AclStateChangedInitOp MOZ_FINAL : private PDUInitOp
+  {
+  public:
+    AclStateChangedInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+    { }
+
+    nsresult
+    operator () (BluetoothStatus& aArg1, nsString& aArg2, bool& aArg3) const
+    {
+      BluetoothDaemonPDU& pdu = GetPDU();
+
+      /* Read status */
+      nsresult rv = UnpackPDU(pdu, aArg1);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read remote address */
+      rv = UnpackPDU(
+        pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read ACL state */
+      rv = UnpackPDU(
+        pdu, UnpackConversion<BluetoothAclState, bool>(aArg3));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      WarnAboutTrailingData();
+      return NS_OK;
+    }
+  };
+
+  void AclStateChangedNtf(const BluetoothDaemonPDUHeader& aHeader,
+                          BluetoothDaemonPDU& aPDU)
+  {
+    AclStateChangedNotification::Dispatch(
+      &BluetoothNotificationHandler::AclStateChangedNotification,
+      AclStateChangedInitOp(aPDU));
+  }
+
+  // Init operator class for DutModeRecvNotification
+  class DutModeRecvInitOp MOZ_FINAL : private PDUInitOp
+  {
+  public:
+    DutModeRecvInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+    { }
+
+    nsresult
+    operator () (uint16_t& aArg1, nsAutoArrayPtr<uint8_t>& aArg2,
+                 uint8_t& aArg3) const
+    {
+      BluetoothDaemonPDU& pdu = GetPDU();
+
+      /* Read opcode */
+      nsresult rv = UnpackPDU(pdu, aArg1);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read length */
+      rv = UnpackPDU(pdu, aArg3);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+
+      /* Read data */
+      rv = UnpackPDU(pdu, UnpackArray<uint8_t>(aArg2, aArg3));
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      WarnAboutTrailingData();
+      return NS_OK;
+    }
+  };
+
+  void DutModeRecvNtf(const BluetoothDaemonPDUHeader& aHeader,
+                      BluetoothDaemonPDU& aPDU)
+  {
+    DutModeRecvNotification::Dispatch(
+      &BluetoothNotificationHandler::DutModeRecvNotification,
+      DutModeRecvInitOp(aPDU));
+  }
+
+  void LeTestModeNtf(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU)
+  {
+    LeTestModeNotification::Dispatch(
+      &BluetoothNotificationHandler::LeTestModeNotification,
+      UnpackPDUInitOp(aPDU));
+  }
+
+  void HandleNtf(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU, void* aUserData)
+  {
+    static void (BluetoothDaemonCoreModule::* const HandleNtf[])(
+      const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&) = {
+      INIT_ARRAY_AT(0, &BluetoothDaemonCoreModule::AdapterStateChangedNtf),
+      INIT_ARRAY_AT(1, &BluetoothDaemonCoreModule::AdapterPropertiesNtf),
+      INIT_ARRAY_AT(2, &BluetoothDaemonCoreModule::RemoteDevicePropertiesNtf),
+      INIT_ARRAY_AT(3, &BluetoothDaemonCoreModule::DeviceFoundNtf),
+      INIT_ARRAY_AT(4, &BluetoothDaemonCoreModule::DiscoveryStateChangedNtf),
+      INIT_ARRAY_AT(5, &BluetoothDaemonCoreModule::PinRequestNtf),
+      INIT_ARRAY_AT(6, &BluetoothDaemonCoreModule::SspRequestNtf),
+      INIT_ARRAY_AT(7, &BluetoothDaemonCoreModule::BondStateChangedNtf),
+      INIT_ARRAY_AT(8, &BluetoothDaemonCoreModule::AclStateChangedNtf),
+      INIT_ARRAY_AT(9, &BluetoothDaemonCoreModule::DutModeRecvNtf),
+      INIT_ARRAY_AT(10, &BluetoothDaemonCoreModule::LeTestModeNtf)
+    };
+
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    uint8_t index = aHeader.mOpcode - 0x81;
+
+    if (NS_WARN_IF(!(index < MOZ_ARRAY_LENGTH(HandleNtf))) ||
+        NS_WARN_IF(!HandleNtf[index])) {
+      return;
+    }
+
+    (this->*(HandleNtf[index]))(aHeader, aPDU);
+  }
+
+};
+
 //
 // Protocol handling
 //
 
 class BluetoothDaemonProtocol MOZ_FINAL
   : public BluetoothDaemonPDUConsumer
   , public BluetoothDaemonSetupModule
+  , public BluetoothDaemonCoreModule
 {
 public:
   BluetoothDaemonProtocol(BluetoothDaemonConnection* aConnection);
 
   // Outgoing PDUs
   //
 
   nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) MOZ_OVERRIDE;
@@ -224,16 +1470,18 @@ public:
 
   void Handle(BluetoothDaemonPDU& aPDU) MOZ_OVERRIDE;
 
   void* FetchUserData(const BluetoothDaemonPDUHeader& aHeader);
 
 private:
   void HandleSetupSvc(const BluetoothDaemonPDUHeader& aHeader,
                       BluetoothDaemonPDU& aPDU, void* aUserData);
+  void HandleCoreSvc(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU, void* aUserData);
 
   BluetoothDaemonConnection* mConnection;
   nsTArray<void*> mUserDataQ;
 };
 
 BluetoothDaemonProtocol::BluetoothDaemonProtocol(
   BluetoothDaemonConnection* aConnection)
   : mConnection(aConnection)
@@ -255,21 +1503,32 @@ void
 BluetoothDaemonProtocol::HandleSetupSvc(
   const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
   void* aUserData)
 {
   BluetoothDaemonSetupModule::HandleSvc(aHeader, aPDU, aUserData);
 }
 
 void
+BluetoothDaemonProtocol::HandleCoreSvc(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  BluetoothDaemonCoreModule::HandleSvc(aHeader, aPDU, aUserData);
+}
+
+void
 BluetoothDaemonProtocol::Handle(BluetoothDaemonPDU& aPDU)
 {
   static void (BluetoothDaemonProtocol::* const HandleSvc[])(
     const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = {
-    [0] = &BluetoothDaemonProtocol::HandleSetupSvc
+    INIT_ARRAY_AT(BluetoothDaemonSetupModule::SERVICE_ID,
+      &BluetoothDaemonProtocol::HandleSetupSvc),
+    INIT_ARRAY_AT(BluetoothDaemonCoreModule::SERVICE_ID,
+      &BluetoothDaemonProtocol::HandleCoreSvc)
   };
 
   BluetoothDaemonPDUHeader header;
 
   if (NS_FAILED(UnpackPDU(aPDU, header)) ||
       NS_WARN_IF(!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc))) ||
       NS_WARN_IF(!(HandleSvc[header.mService]))) {
     return;
@@ -442,18 +1701,16 @@ public:
   // We need to call methods from the |BluetoothResultHandler|. Since
   // we're already on the main thread and returned from Init, we don't
   // need to dispatch a new runnable.
 
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    // TODO: close channels
-
     if (mRes) {
       mRes->OnError(aStatus);
     }
   }
 
   void RegisterModule() MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
@@ -496,17 +1753,18 @@ BluetoothDaemonInterface::OnConnectSucce
       break;
 
     case NTF_CHANNEL: {
         nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
         mResultHandlerQ.RemoveElementAt(0);
 
         // Init, step 3: Register Core module
         nsresult rv = mProtocol->RegisterModuleCmd(
-          0x01, 0x00, new InitResultHandler(this, res));
+          BluetoothDaemonCoreModule::SERVICE_ID, 0x00,
+          new InitResultHandler(this, res));
         if (NS_FAILED(rv) && res) {
           DispatchError(res, STATUS_FAIL);
         }
       }
       break;
   }
 }
 
@@ -604,17 +1862,18 @@ private:
   void Proceed()
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(mInterface->mProtocol);
 
     if (!mUnregisteredCoreModule) {
       mUnregisteredCoreModule = true;
       // Cleanup, step 2: Unregister Core module
-      mInterface->mProtocol->UnregisterModuleCmd(0x01, this);
+      mInterface->mProtocol->UnregisterModuleCmd(
+        BluetoothDaemonCoreModule::SERVICE_ID, this);
     } else {
       // Cleanup, step 3: Close notification channel
       mInterface->mNtfChannel->CloseSocket();
     }
   }
 
   BluetoothDaemonInterface* mInterface;
   bool mUnregisteredCoreModule;
@@ -629,150 +1888,187 @@ BluetoothDaemonInterface::Cleanup(Blueto
 
   // Cleanup, step 1: Unregister Socket module
   mProtocol->UnregisterModuleCmd(0x02, new CleanupResultHandler(this));
 }
 
 void
 BluetoothDaemonInterface::Enable(BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>(mProtocol)->EnableCmd(aRes);
 }
 
 void
 BluetoothDaemonInterface::Disable(BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>(mProtocol)->DisableCmd(aRes);
 }
 
 /* Adapter Properties */
 
 void
 BluetoothDaemonInterface::GetAdapterProperties(BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->GetAdapterPropertiesCmd(aRes);
 }
 
 void
 BluetoothDaemonInterface::GetAdapterProperty(const nsAString& aName,
                                              BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->GetAdapterPropertyCmd(aName, aRes);
 }
 
 void
 BluetoothDaemonInterface::SetAdapterProperty(
   const BluetoothNamedValue& aProperty, BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->SetAdapterPropertyCmd(aProperty, aRes);
 }
 
 /* Remote Device Properties */
 
 void
 BluetoothDaemonInterface::GetRemoteDeviceProperties(
   const nsAString& aRemoteAddr, BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->GetRemoteDevicePropertiesCmd(aRemoteAddr, aRes);
 }
 
 void
 BluetoothDaemonInterface::GetRemoteDeviceProperty(
   const nsAString& aRemoteAddr, const nsAString& aName,
   BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->GetRemoteDevicePropertyCmd(aRemoteAddr, aName, aRes);
 }
 
 void
 BluetoothDaemonInterface::SetRemoteDeviceProperty(
   const nsAString& aRemoteAddr, const BluetoothNamedValue& aProperty,
   BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->SetRemoteDevicePropertyCmd(aRemoteAddr, aProperty, aRes);
 }
 
 /* Remote Services */
 
 void
 BluetoothDaemonInterface::GetRemoteServiceRecord(const nsAString& aRemoteAddr,
                                                  const uint8_t aUuid[16],
                                                  BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>(
+    mProtocol)->GetRemoteServiceRecordCmd(aRemoteAddr, aUuid, aRes);
 }
 
 void
 BluetoothDaemonInterface::GetRemoteServices(const nsAString& aRemoteAddr,
                                             BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>(
+    mProtocol)->GetRemoteServicesCmd(aRemoteAddr, aRes);
 }
 
 /* Discovery */
 
 void
 BluetoothDaemonInterface::StartDiscovery(BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>(mProtocol)->StartDiscoveryCmd(aRes);
 }
 
 void
 BluetoothDaemonInterface::CancelDiscovery(BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->CancelDiscoveryCmd(aRes);
 }
 
 /* Bonds */
 
 void
 BluetoothDaemonInterface::CreateBond(const nsAString& aBdAddr,
                                      BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->CreateBondCmd(aBdAddr, aRes);
 }
 
 void
 BluetoothDaemonInterface::RemoveBond(const nsAString& aBdAddr,
                                      BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->RemoveBondCmd(aBdAddr, aRes);
 }
 
 void
 BluetoothDaemonInterface::CancelBond(const nsAString& aBdAddr,
                                      BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->CancelBondCmd(aBdAddr, aRes);
 }
 
 /* Authentication */
 
 void
 BluetoothDaemonInterface::PinReply(const nsAString& aBdAddr, bool aAccept,
                                    const nsAString& aPinCode,
                                    BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->PinReplyCmd(aBdAddr, aAccept, aPinCode, aRes);
 }
 
 void
 BluetoothDaemonInterface::SspReply(const nsAString& aBdAddr,
                                    const nsAString& aVariant,
                                    bool aAccept, uint32_t aPasskey,
                                    BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->SspReplyCmd(aBdAddr, aVariant, aAccept, aPasskey, aRes);
 }
 
 /* DUT Mode */
 
 void
 BluetoothDaemonInterface::DutModeConfigure(bool aEnable,
                                            BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->DutModeConfigureCmd(aEnable, aRes);
 }
 
 void
 BluetoothDaemonInterface::DutModeSend(uint16_t aOpcode, uint8_t* aBuf,
                                       uint8_t aLen,
                                       BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->DutModeSendCmd(aOpcode, aBuf, aLen, aRes);
 }
 
 /* LE Mode */
 
 void
 BluetoothDaemonInterface::LeTestMode(uint16_t aOpcode, uint8_t* aBuf,
                                      uint8_t aLen,
                                      BluetoothResultHandler* aRes)
 {
+  static_cast<BluetoothDaemonCoreModule*>
+    (mProtocol)->LeTestModeCmd(aOpcode, aBuf, aLen, aRes);
 }
 
 void
 BluetoothDaemonInterface::DispatchError(BluetoothResultHandler* aRes,
                                         BluetoothStatus aStatus)
 {
   BluetoothResultRunnable1<
     BluetoothResultHandler, void, BluetoothStatus, BluetoothStatus>::Dispatch(