mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 20:17:37 +00:00
28c30fed04
This patch adds helpers for packing, unpacking and converting Handsfree values to and from Bluetooth PDUs.
1188 lines
31 KiB
C++
1188 lines
31 KiB
C++
/* -*- 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"
|
|
#include <limits>
|
|
|
|
#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(int aIn, uint8_t& aOut)
|
|
{
|
|
if (NS_WARN_IF(aIn < std::numeric_limits<uint8_t>::min()) ||
|
|
NS_WARN_IF(aIn > std::numeric_limits<uint8_t>::max())) {
|
|
aOut = 0; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = static_cast<uint8_t>(aIn);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(int aIn, int16_t& aOut)
|
|
{
|
|
if (NS_WARN_IF(aIn < std::numeric_limits<int16_t>::min()) ||
|
|
NS_WARN_IF(aIn > std::numeric_limits<int16_t>::max())) {
|
|
aOut = 0; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = static_cast<int16_t>(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, char& aOut)
|
|
{
|
|
aOut = static_cast<char>(aIn);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(uint8_t aIn, int& aOut)
|
|
{
|
|
aOut = static_cast<int>(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(uint8_t aIn, BluetoothHandsfreeAudioState& aOut)
|
|
{
|
|
static const BluetoothHandsfreeAudioState sAudioState[] = {
|
|
CONVERT(0x00, HFP_AUDIO_STATE_DISCONNECTED),
|
|
CONVERT(0x01, HFP_AUDIO_STATE_CONNECTING),
|
|
CONVERT(0x02, HFP_AUDIO_STATE_CONNECTED),
|
|
CONVERT(0x03, HFP_AUDIO_STATE_DISCONNECTING)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAudioState))) {
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sAudioState[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(uint8_t aIn, BluetoothHandsfreeCallHoldType& aOut)
|
|
{
|
|
static const BluetoothHandsfreeCallHoldType sCallHoldType[] = {
|
|
CONVERT(0x00, HFP_CALL_HOLD_RELEASEHELD),
|
|
CONVERT(0x01, HFP_CALL_HOLD_RELEASEACTIVE_ACCEPTHELD),
|
|
CONVERT(0x02, HFP_CALL_HOLD_HOLDACTIVE_ACCEPTHELD),
|
|
CONVERT(0x03, HFP_CALL_HOLD_ADDHELDTOCONF)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sCallHoldType))) {
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sCallHoldType[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(uint8_t aIn, BluetoothHandsfreeConnectionState& aOut)
|
|
{
|
|
static const BluetoothHandsfreeConnectionState sConnectionState[] = {
|
|
CONVERT(0x00, HFP_CONNECTION_STATE_DISCONNECTED),
|
|
CONVERT(0x01, HFP_CONNECTION_STATE_CONNECTING),
|
|
CONVERT(0x02, HFP_CONNECTION_STATE_CONNECTED),
|
|
CONVERT(0x03, HFP_CONNECTION_STATE_SLC_CONNECTED),
|
|
CONVERT(0x04, HFP_CONNECTION_STATE_DISCONNECTING)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sConnectionState))) {
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sConnectionState[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(uint8_t aIn, BluetoothHandsfreeNRECState& aOut)
|
|
{
|
|
static const BluetoothHandsfreeNRECState sNRECState[] = {
|
|
CONVERT(0x00, HFP_NREC_STOPPED),
|
|
CONVERT(0x01, HFP_NREC_STARTED)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sNRECState))) {
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sNRECState[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(uint8_t aIn, BluetoothHandsfreeVoiceRecognitionState& aOut)
|
|
{
|
|
static const BluetoothHandsfreeVoiceRecognitionState sState[] = {
|
|
CONVERT(0x00, HFP_VOICE_RECOGNITION_STOPPED),
|
|
CONVERT(0x01, HFP_VOICE_RECOGNITION_STOPPED)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sState))) {
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sState[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(uint8_t aIn, BluetoothHandsfreeVolumeType& aOut)
|
|
{
|
|
static const BluetoothHandsfreeVolumeType sVolumeType[] = {
|
|
CONVERT(0x00, HFP_VOLUME_TYPE_SPEAKER),
|
|
CONVERT(0x01, HFP_VOLUME_TYPE_MICROPHONE)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sVolumeType))) {
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sVolumeType[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(BluetoothSocketType aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sSocketType[] = {
|
|
CONVERT(0, 0), // silences compiler warning
|
|
CONVERT(BluetoothSocketType::RFCOMM, 0x01),
|
|
CONVERT(BluetoothSocketType::SCO, 0x02),
|
|
CONVERT(BluetoothSocketType::L2CAP, 0x03)
|
|
// EL2CAP not supported
|
|
};
|
|
if (NS_WARN_IF(aIn == BluetoothSocketType::EL2CAP) ||
|
|
NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sSocketType)) ||
|
|
NS_WARN_IF(!sSocketType[aIn])) {
|
|
aOut = 0; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sSocketType[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),
|
|
CONVERT(0x05, STATUS_DONE),
|
|
CONVERT(0x06, STATUS_UNSUPPORTED),
|
|
CONVERT(0x07, STATUS_PARM_INVALID),
|
|
CONVERT(0x08, STATUS_UNHANDLED),
|
|
CONVERT(0x09, STATUS_AUTH_FAILURE),
|
|
CONVERT(0x0a, STATUS_RMT_DEV_DOWN)
|
|
};
|
|
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, BluetoothServiceName& aOut)
|
|
{
|
|
NS_ConvertUTF16toUTF8 serviceNameUTF8(aIn);
|
|
const char* str = serviceNameUTF8.get();
|
|
size_t len = strlen(str);
|
|
|
|
if (NS_WARN_IF(len > sizeof(aOut.mName))) {
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
|
|
memcpy(aOut.mName, str, len);
|
|
memset(aOut.mName + len, 0, sizeof(aOut.mName) - len);
|
|
|
|
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(BluetoothHandsfreeAtResponse aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sAtResponse[] = {
|
|
CONVERT(HFP_AT_RESPONSE_ERROR, 0x00),
|
|
CONVERT(HFP_AT_RESPONSE_OK, 0x01)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAtResponse))) {
|
|
aOut = 0x00; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sAtResponse[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(BluetoothHandsfreeCallAddressType aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sCallAddressType[] = {
|
|
CONVERT(HFP_CALL_ADDRESS_TYPE_UNKNOWN, 0x81),
|
|
CONVERT(HFP_CALL_ADDRESS_TYPE_INTERNATIONAL, 0x91)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sCallAddressType))) {
|
|
aOut = 0x00; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sCallAddressType[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(BluetoothHandsfreeCallDirection aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sCallDirection[] = {
|
|
CONVERT(HFP_CALL_DIRECTION_OUTGOING, 0x00),
|
|
CONVERT(HFP_CALL_DIRECTION_INCOMING, 0x01)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sCallDirection))) {
|
|
aOut = 0x00; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sCallDirection[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(BluetoothHandsfreeCallState aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sCallState[] = {
|
|
CONVERT(HFP_CALL_STATE_ACTIVE, 0x00),
|
|
CONVERT(HFP_CALL_STATE_HELD, 0x01),
|
|
CONVERT(HFP_CALL_STATE_DIALING, 0x02),
|
|
CONVERT(HFP_CALL_STATE_ALERTING, 0x03),
|
|
CONVERT(HFP_CALL_STATE_INCOMING, 0x04),
|
|
CONVERT(HFP_CALL_STATE_WAITING, 0x05),
|
|
CONVERT(HFP_CALL_STATE_IDLE, 0x06)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sCallState))) {
|
|
aOut = 0x00; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sCallState[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(BluetoothHandsfreeCallMode aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sCallMode[] = {
|
|
CONVERT(HFP_CALL_MODE_VOICE, 0x00),
|
|
CONVERT(HFP_CALL_MODE_DATA, 0x01),
|
|
CONVERT(HFP_CALL_MODE_FAX, 0x02)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sCallMode))) {
|
|
aOut = 0x00; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sCallMode[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(BluetoothHandsfreeCallMptyType aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sCallMptyType[] = {
|
|
CONVERT(HFP_CALL_MPTY_TYPE_SINGLE, 0x00),
|
|
CONVERT(HFP_CALL_MPTY_TYPE_MULTI, 0x01)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sCallMptyType))) {
|
|
aOut = 0x00; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sCallMptyType[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(BluetoothHandsfreeNetworkState aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sNetworkState[] = {
|
|
CONVERT(HFP_NETWORK_STATE_NOT_AVAILABLE, 0x00),
|
|
CONVERT(HFP_NETWORK_STATE_AVAILABLE, 0x01)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sNetworkState))) {
|
|
aOut = 0x00; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sNetworkState[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(BluetoothHandsfreeServiceType aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sServiceType[] = {
|
|
CONVERT(HFP_SERVICE_TYPE_HOME, 0x00),
|
|
CONVERT(HFP_SERVICE_TYPE_ROAMING, 0x01)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sServiceType))) {
|
|
aOut = 0x00; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sServiceType[aIn];
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
Convert(BluetoothHandsfreeVolumeType aIn, uint8_t& aOut)
|
|
{
|
|
static const uint8_t sVolumeType[] = {
|
|
CONVERT(HFP_VOLUME_TYPE_SPEAKER, 0x00),
|
|
CONVERT(HFP_VOLUME_TYPE_MICROPHONE, 0x01)
|
|
};
|
|
if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sVolumeType))) {
|
|
aOut = 0x00; // silences compiler warning
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
aOut = sVolumeType[aIn];
|
|
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 BluetoothHandsfreeAtResponse& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(
|
|
PackConversion<BluetoothHandsfreeAtResponse, uint8_t>(aIn), aPDU);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(const BluetoothHandsfreeCallAddressType& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(
|
|
PackConversion<BluetoothHandsfreeCallAddressType, uint8_t>(aIn), aPDU);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(const BluetoothHandsfreeCallDirection& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(
|
|
PackConversion<BluetoothHandsfreeCallDirection, uint8_t>(aIn), aPDU);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(const BluetoothHandsfreeCallMode& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(
|
|
PackConversion<BluetoothHandsfreeCallMode, uint8_t>(aIn), aPDU);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(const BluetoothHandsfreeCallMptyType& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(
|
|
PackConversion<BluetoothHandsfreeCallMptyType, uint8_t>(aIn), aPDU);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(const BluetoothHandsfreeCallState& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(
|
|
PackConversion<BluetoothHandsfreeCallState, uint8_t>(aIn), aPDU);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(const BluetoothHandsfreeNetworkState& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(
|
|
PackConversion<BluetoothHandsfreeNetworkState, uint8_t>(aIn), aPDU);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(const BluetoothHandsfreeServiceType& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(
|
|
PackConversion<BluetoothHandsfreeServiceType, uint8_t>(aIn), aPDU);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(const BluetoothHandsfreeVolumeType& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(
|
|
PackConversion<BluetoothHandsfreeVolumeType, uint8_t>(aIn), 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);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(const BluetoothServiceName& aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(PackArray<uint8_t>(aIn.mName, sizeof(aIn.mName)), aPDU);
|
|
}
|
|
|
|
nsresult
|
|
PackPDU(BluetoothSocketType aIn, BluetoothDaemonPDU& aPDU)
|
|
{
|
|
return PackPDU(PackConversion<BluetoothSocketType, uint8_t>(aIn), aPDU);
|
|
}
|
|
|
|
//
|
|
// Unpacking
|
|
//
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU, bool& aOut)
|
|
{
|
|
return UnpackPDU(aPDU, UnpackConversion<uint8_t, bool>(aOut));
|
|
}
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU, char& aOut)
|
|
{
|
|
return UnpackPDU(aPDU, UnpackConversion<uint8_t, char>(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, BluetoothHandsfreeAudioState& aOut)
|
|
{
|
|
return UnpackPDU(
|
|
aPDU, UnpackConversion<uint8_t, BluetoothHandsfreeAudioState>(aOut));
|
|
}
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothHandsfreeCallHoldType& aOut)
|
|
{
|
|
return UnpackPDU(
|
|
aPDU, UnpackConversion<uint8_t, BluetoothHandsfreeCallHoldType>(aOut));
|
|
}
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothHandsfreeConnectionState& aOut)
|
|
{
|
|
return UnpackPDU(
|
|
aPDU, UnpackConversion<uint8_t, BluetoothHandsfreeConnectionState>(aOut));
|
|
}
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothHandsfreeNRECState& aOut)
|
|
{
|
|
return UnpackPDU(
|
|
aPDU, UnpackConversion<uint8_t, BluetoothHandsfreeNRECState>(aOut));
|
|
}
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU,
|
|
BluetoothHandsfreeVoiceRecognitionState& aOut)
|
|
{
|
|
return UnpackPDU(
|
|
aPDU,
|
|
UnpackConversion<uint8_t, BluetoothHandsfreeVoiceRecognitionState>(aOut));
|
|
}
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothHandsfreeVolumeType& aOut)
|
|
{
|
|
return UnpackPDU(
|
|
aPDU, UnpackConversion<uint8_t, BluetoothHandsfreeVolumeType>(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));
|
|
}
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU, nsDependentCString& aOut)
|
|
{
|
|
// We get a pointer to the first character in the PDU, a length
|
|
// of 1 ensures we consume the \0 byte. With 'str' pointing to
|
|
// the string in the PDU, we can copy the actual bytes.
|
|
|
|
const char* str = reinterpret_cast<const char*>(aPDU.Consume(1));
|
|
if (NS_WARN_IF(!str)) {
|
|
return NS_ERROR_ILLEGAL_VALUE; // end of PDU
|
|
}
|
|
|
|
const char* end = static_cast<char*>(memchr(str, '\0', aPDU.GetSize()));
|
|
if (NS_WARN_IF(!end)) {
|
|
return NS_ERROR_ILLEGAL_VALUE; // no string terminator
|
|
}
|
|
|
|
ptrdiff_t len = end - str;
|
|
|
|
const uint8_t* rest = aPDU.Consume(len);
|
|
if (NS_WARN_IF(!rest)) {
|
|
// We couldn't consume bytes that should have been there.
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
|
|
aOut.Rebind(str, len);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU, const UnpackCString0& aOut)
|
|
{
|
|
nsDependentCString cstring;
|
|
|
|
nsresult rv = UnpackPDU(aPDU, cstring);
|
|
if (NS_FAILED(rv)) {
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
|
|
aOut.mString->AssignASCII(cstring.get(), cstring.Length());
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
UnpackPDU(BluetoothDaemonPDU& aPDU, const UnpackString0& aOut)
|
|
{
|
|
nsDependentCString cstring;
|
|
|
|
nsresult rv = UnpackPDU(aPDU, cstring);
|
|
if (NS_FAILED(rv)) {
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
|
|
*aOut.mString = NS_ConvertUTF8toUTF16(cstring);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
END_BLUETOOTH_NAMESPACE
|