/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=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 #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, int32_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::min()) || NS_WARN_IF(aIn > std::numeric_limits::max())) { aOut = 0; // silences compiler warning return NS_ERROR_ILLEGAL_VALUE; } aOut = static_cast(aIn); return NS_OK; } nsresult Convert(int aIn, int16_t& aOut) { if (NS_WARN_IF(aIn < std::numeric_limits::min()) || NS_WARN_IF(aIn > std::numeric_limits::max())) { aOut = 0; // silences compiler warning return NS_ERROR_ILLEGAL_VALUE; } aOut = static_cast(aIn); return NS_OK; } nsresult Convert(int aIn, int32_t& aOut) { if (NS_WARN_IF(aIn < std::numeric_limits::min()) || NS_WARN_IF(aIn > std::numeric_limits::max())) { aOut = 0; // silences compiler warning return NS_ERROR_ILLEGAL_VALUE; } aOut = static_cast(aIn); return NS_OK; } nsresult Convert(int32_t aIn, BluetoothTypeOfDevice& aOut) { static const BluetoothTypeOfDevice sTypeOfDevice[] = { CONVERT(0x00, static_cast(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(aIn) >= MOZ_ARRAY_LENGTH(sTypeOfDevice))) { return NS_ERROR_ILLEGAL_VALUE; } aOut = sTypeOfDevice[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(aIn) >= MOZ_ARRAY_LENGTH(sScanMode))) { 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, char& aOut) { aOut = static_cast(aIn); return NS_OK; } nsresult Convert(uint8_t aIn, int& aOut) { aOut = static_cast(aIn); return NS_OK; } nsresult Convert(uint8_t aIn, unsigned long& aOut) { aOut = static_cast(aIn); return NS_OK; } nsresult Convert(uint8_t aIn, BluetoothA2dpAudioState& aOut) { static const BluetoothA2dpAudioState sAudioState[] = { CONVERT(0x00, A2DP_AUDIO_STATE_REMOTE_SUSPEND), CONVERT(0x01, A2DP_AUDIO_STATE_STOPPED), CONVERT(0x02, A2DP_AUDIO_STATE_STARTED) }; 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, BluetoothA2dpConnectionState& aOut) { static const BluetoothA2dpConnectionState sConnectionState[] = { CONVERT(0x00, A2DP_CONNECTION_STATE_DISCONNECTED), CONVERT(0x01, A2DP_CONNECTION_STATE_CONNECTING), CONVERT(0x02, A2DP_CONNECTION_STATE_CONNECTED), CONVERT(0x03, A2DP_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, 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, BluetoothAvrcpEvent& aOut) { static const BluetoothAvrcpEvent sAvrcpEvent[] = { CONVERT(0x00, static_cast(0)), CONVERT(0x01, AVRCP_EVENT_PLAY_STATUS_CHANGED), CONVERT(0x02, AVRCP_EVENT_TRACK_CHANGE), CONVERT(0x03, AVRCP_EVENT_TRACK_REACHED_END), CONVERT(0x04, AVRCP_EVENT_TRACK_REACHED_START), CONVERT(0x05, AVRCP_EVENT_PLAY_POS_CHANGED), CONVERT(0x06, static_cast(0)), CONVERT(0x07, static_cast(0)), CONVERT(0x08, AVRCP_EVENT_APP_SETTINGS_CHANGED) }; if (NS_WARN_IF(!aIn) || NS_WARN_IF(aIn == 0x06) || NS_WARN_IF(aIn == 0x07) || NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpEvent))) { aOut = static_cast(0); // silences compiler warning return NS_ERROR_ILLEGAL_VALUE; } aOut = sAvrcpEvent[aIn]; return NS_OK; } nsresult Convert(uint8_t aIn, BluetoothAvrcpMediaAttribute& aOut) { static const BluetoothAvrcpMediaAttribute sAvrcpMediaAttribute[] = { CONVERT(0x00, static_cast(0)), CONVERT(0x01, AVRCP_MEDIA_ATTRIBUTE_TITLE), CONVERT(0x02, AVRCP_MEDIA_ATTRIBUTE_ARTIST), CONVERT(0x03, AVRCP_MEDIA_ATTRIBUTE_ALBUM), CONVERT(0x04, AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM), CONVERT(0x05, AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS), CONVERT(0x06, AVRCP_MEDIA_ATTRIBUTE_GENRE), CONVERT(0x07, AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME) }; if (NS_WARN_IF(!aIn) || NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpMediaAttribute))) { // silences compiler warning aOut = static_cast(0); return NS_ERROR_ILLEGAL_VALUE; } aOut = sAvrcpMediaAttribute[aIn]; return NS_OK; } nsresult Convert(uint8_t aIn, BluetoothAvrcpPlayerAttribute& aOut) { static const BluetoothAvrcpPlayerAttribute sAvrcpPlayerAttribute[] = { CONVERT(0x00, static_cast(0)), CONVERT(0x01, AVRCP_PLAYER_ATTRIBUTE_EQUALIZER), CONVERT(0x02, AVRCP_PLAYER_ATTRIBUTE_REPEAT), CONVERT(0x03, AVRCP_PLAYER_ATTRIBUTE_SHUFFLE), CONVERT(0x04, AVRCP_PLAYER_ATTRIBUTE_SCAN) }; if (NS_WARN_IF(!aIn) || NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpPlayerAttribute))) { // silences compiler warning aOut = static_cast(0); return NS_ERROR_ILLEGAL_VALUE; } aOut = sAvrcpPlayerAttribute[aIn]; return NS_OK; } nsresult Convert(uint8_t aIn, BluetoothAvrcpRemoteFeature& aOut) { static const BluetoothAvrcpRemoteFeature sAvrcpRemoteFeature[] = { CONVERT(0x00, AVRCP_REMOTE_FEATURE_NONE), CONVERT(0x01, AVRCP_REMOTE_FEATURE_METADATA), CONVERT(0x02, AVRCP_REMOTE_FEATURE_ABSOLUTE_VOLUME), CONVERT(0x03, AVRCP_REMOTE_FEATURE_BROWSE) }; if (NS_WARN_IF(!aIn) || NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpRemoteFeature))) { // silences compiler warning aOut = static_cast(0); return NS_ERROR_ILLEGAL_VALUE; } aOut = sAvrcpRemoteFeature[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(uint8_t aIn, BluetoothHandsfreeWbsConfig& aOut) { static const BluetoothHandsfreeWbsConfig sWbsConfig[] = { CONVERT(0x00, HFP_WBS_NONE), CONVERT(0x01, HFP_WBS_NO), CONVERT(0x02, HFP_WBS_YES) }; if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sWbsConfig))) { return NS_ERROR_ILLEGAL_VALUE; } aOut = sWbsConfig[aIn]; return NS_OK; } nsresult Convert(uint8_t aIn, BluetoothTypeOfDevice& aOut) { return Convert((int32_t)aIn, aOut); } nsresult Convert(uint8_t aIn, BluetoothPropertyType& aOut) { static const BluetoothPropertyType sPropertyType[] = { CONVERT(0x00, static_cast(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(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(int32_t aIn, BluetoothGattStatus& aOut) { /* Reference: $B2G/external/bluetooth/bluedroid/stack/include/gatt_api.h */ static const BluetoothGattStatus sGattStatus[] = { CONVERT(0x0000, GATT_STATUS_SUCCESS), CONVERT(0x0001, GATT_STATUS_INVALID_HANDLE), CONVERT(0x0002, GATT_STATUS_READ_NOT_PERMITTED), CONVERT(0x0003, GATT_STATUS_WRITE_NOT_PERMITTED), CONVERT(0x0004, GATT_STATUS_INVALID_PDU), CONVERT(0x0005, GATT_STATUS_INSUFFICIENT_AUTHENTICATION), CONVERT(0x0006, GATT_STATUS_REQUEST_NOT_SUPPORTED), CONVERT(0x0007, GATT_STATUS_INVALID_OFFSET), CONVERT(0x0008, GATT_STATUS_INSUFFICIENT_AUTHORIZATION), CONVERT(0x0009, GATT_STATUS_PREPARE_QUEUE_FULL), CONVERT(0x000a, GATT_STATUS_ATTRIBUTE_NOT_FOUND), CONVERT(0x000b, GATT_STATUS_ATTRIBUTE_NOT_LONG), CONVERT(0x000c, GATT_STATUS_INSUFFICIENT_ENCRYPTION_KEY_SIZE), CONVERT(0x000d, GATT_STATUS_INVALID_ATTRIBUTE_LENGTH), CONVERT(0x000e, GATT_STATUS_UNLIKELY_ERROR), CONVERT(0x000f, GATT_STATUS_INSUFFICIENT_ENCRYPTION), CONVERT(0x0010, GATT_STATUS_UNSUPPORTED_GROUP_TYPE), CONVERT(0x0011, GATT_STATUS_INSUFFICIENT_RESOURCES) }; if (NS_WARN_IF(aIn < 0) || NS_WARN_IF(aIn >= static_cast(MOZ_ARRAY_LENGTH(sGattStatus)))) { aOut = GATT_STATUS_UNKNOWN_ERROR; } else { aOut = sGattStatus[aIn]; } return NS_OK; } nsresult Convert(uint32_t aIn, int& aOut) { aOut = static_cast(aIn); return NS_OK; } nsresult Convert(uint32_t aIn, uint8_t& aOut) { if (NS_WARN_IF(aIn < std::numeric_limits::min()) || NS_WARN_IF(aIn > std::numeric_limits::max())) { aOut = 0; // silences compiler warning return NS_ERROR_ILLEGAL_VALUE; } aOut = static_cast(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(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(strtoul(str, const_cast(&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(*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(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(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(aIn.mAddr[0]), static_cast(aIn.mAddr[1]), static_cast(aIn.mAddr[2]), static_cast(aIn.mAddr[3]), static_cast(aIn.mAddr[4]), static_cast(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(BluetoothAvrcpEvent aIn, uint8_t& aOut) { static const uint8_t sValue[] = { CONVERT(AVRCP_EVENT_PLAY_STATUS_CHANGED, 0x01), CONVERT(AVRCP_EVENT_TRACK_CHANGE, 0x02), CONVERT(AVRCP_EVENT_TRACK_REACHED_END, 0x03), CONVERT(AVRCP_EVENT_TRACK_REACHED_START, 0x04), CONVERT(AVRCP_EVENT_PLAY_POS_CHANGED, 0x05), CONVERT(AVRCP_EVENT_APP_SETTINGS_CHANGED, 0x08) }; if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) { return NS_ERROR_ILLEGAL_VALUE; } aOut = sValue[aIn]; return NS_OK; } nsresult Convert(BluetoothAvrcpNotification aIn, uint8_t& aOut) { static const bool sValue[] = { CONVERT(AVRCP_NTF_INTERIM, 0x00), CONVERT(AVRCP_NTF_CHANGED, 0x01) }; if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) { return NS_ERROR_ILLEGAL_VALUE; } aOut = sValue[aIn]; return NS_OK; } nsresult Convert(BluetoothAvrcpPlayerAttribute aIn, uint8_t& aOut) { static const uint8_t sValue[] = { CONVERT(AVRCP_PLAYER_ATTRIBUTE_EQUALIZER, 0x01), CONVERT(AVRCP_PLAYER_ATTRIBUTE_REPEAT, 0x02), CONVERT(AVRCP_PLAYER_ATTRIBUTE_SHUFFLE, 0x03), CONVERT(AVRCP_PLAYER_ATTRIBUTE_SCAN, 0x04) }; if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) { return NS_ERROR_ILLEGAL_VALUE; } aOut = sValue[aIn]; return NS_OK; } nsresult Convert(BluetoothAvrcpRemoteFeature aIn, unsigned long& aOut) { if (NS_WARN_IF(aIn < std::numeric_limits::min()) || NS_WARN_IF(aIn > std::numeric_limits::max())) { aOut = 0; // silences compiler warning return NS_ERROR_ILLEGAL_VALUE; } aOut = static_cast(aIn); return NS_OK; } nsresult Convert(BluetoothAvrcpStatus aIn, uint8_t& aOut) { static const uint8_t sValue[] = { CONVERT(AVRCP_STATUS_BAD_COMMAND, 0x00), CONVERT(AVRCP_STATUS_BAD_PARAMETER, 0x01), CONVERT(AVRCP_STATUS_NOT_FOUND, 0x02), CONVERT(AVRCP_STATUS_INTERNAL_ERROR, 0x03), CONVERT(AVRCP_STATUS_SUCCESS, 0x04) }; if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) { return NS_ERROR_ILLEGAL_VALUE; } aOut = sValue[aIn]; 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(BluetoothHandsfreeWbsConfig aIn, uint8_t& aOut) { static const uint8_t sWbsConfig[] = { CONVERT(HFP_WBS_NONE, 0x00), CONVERT(HFP_WBS_NO, 0x01), CONVERT(HFP_WBS_YES, 0x02) }; if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sWbsConfig))) { aOut = 0x00; // silences compiler warning return NS_ERROR_ILLEGAL_VALUE; } aOut = sWbsConfig[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(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; } nsresult Convert(ControlPlayStatus aIn, uint8_t& aOut) { static const uint8_t sValue[] = { CONVERT(PLAYSTATUS_STOPPED, 0x00), CONVERT(PLAYSTATUS_PLAYING, 0x01), CONVERT(PLAYSTATUS_PAUSED, 0x02), CONVERT(PLAYSTATUS_FWD_SEEK, 0x03), CONVERT(PLAYSTATUS_REV_SEEK, 0x04) }; if (aIn == PLAYSTATUS_ERROR) { /* This case is handled separately to not populate * |sValue| with empty entries. */ aOut = 0xff; return NS_OK; } 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; } nsresult Convert(BluetoothGattAuthReq aIn, int32_t& aOut) { static const int32_t sGattAuthReq[] = { CONVERT(GATT_AUTH_REQ_NONE, 0x00), CONVERT(GATT_AUTH_REQ_NO_MITM, 0x01), CONVERT(GATT_AUTH_REQ_MITM, 0x02), CONVERT(GATT_AUTH_REQ_SIGNED_NO_MITM, 0x03), CONVERT(GATT_AUTH_REQ_SIGNED_MITM, 0x04) }; if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sGattAuthReq))) { aOut = GATT_AUTH_REQ_NONE; // silences compiler warning return NS_ERROR_ILLEGAL_VALUE; } aOut = sGattAuthReq[aIn]; return NS_OK; } nsresult Convert(BluetoothGattWriteType aIn, int32_t& aOut) { static const int32_t sGattWriteType[] = { CONVERT(GATT_WRITE_TYPE_NO_RESPONSE, 0x01), CONVERT(GATT_WRITE_TYPE_NORMAL, 0x02), CONVERT(GATT_WRITE_TYPE_PREPARE, 0x03), CONVERT(GATT_WRITE_TYPE_SIGNED, 0x04) }; if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sGattWriteType))) { aOut = GATT_WRITE_TYPE_NORMAL; // silences compiler warning return NS_ERROR_ILLEGAL_VALUE; } aOut = sGattWriteType[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 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 inline nsresult Convert(const ConvertArray& 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, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothAddress& aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackArray(aIn.mAddr, sizeof(aIn.mAddr)), aPDU); } nsresult PackPDU(const BluetoothAvrcpAttributeTextPairs& aIn, DaemonSocketPDU& aPDU) { size_t i; for (i = 0; i < aIn.mLength; ++i) { nsresult rv = PackPDU(aIn.mAttr[i], aPDU); if (NS_FAILED(rv)) { return rv; } uint8_t len; const uint8_t* str; if (aIn.mText[i]) { str = reinterpret_cast(aIn.mText[i]); len = strlen(aIn.mText[i]) + 1; } else { /* write \0 character for NULL strings */ str = reinterpret_cast("\0"); len = 1; } rv = PackPDU(len, aPDU); if (NS_FAILED(rv)) { return rv; } rv = PackPDU(PackArray(str, len), aPDU); if (NS_FAILED(rv)) { return rv; } } return NS_OK; } nsresult PackPDU(const BluetoothAvrcpAttributeValuePairs& aIn, DaemonSocketPDU& aPDU) { size_t i; for (i = 0; i < aIn.mLength; ++i) { nsresult rv = PackPDU(aIn.mAttr[i], aPDU); if (NS_FAILED(rv)) { return rv; } rv = PackPDU(aIn.mValue[i], aPDU); if (NS_FAILED(rv)) { return rv; } } return NS_OK; } nsresult PackPDU(const BluetoothAvrcpElementAttribute& aIn, DaemonSocketPDU& aPDU) { nsresult rv = PackPDU(PackConversion(aIn.mId), aPDU); if (NS_FAILED(rv)) { return rv; } const NS_ConvertUTF16toUTF8 cstr(aIn.mValue); if (NS_WARN_IF(cstr.Length() == PR_UINT32_MAX)) { return NS_ERROR_ILLEGAL_VALUE; /* integer overflow detected */ } uint32_t clen = cstr.Length() + 1; /* include \0 character */ rv = PackPDU(PackConversion(clen), aPDU); if (NS_FAILED(rv)) { return rv; } return PackPDU( PackArray(reinterpret_cast(cstr.get()), clen), aPDU); } nsresult PackPDU(BluetoothAvrcpEvent aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothAvrcpEventParamPair& aIn, DaemonSocketPDU& aPDU) { nsresult rv; switch (aIn.mEvent) { case AVRCP_EVENT_PLAY_STATUS_CHANGED: rv = PackPDU(aIn.mParam.mPlayStatus, aPDU); break; case AVRCP_EVENT_TRACK_CHANGE: rv = PackPDU(PackArray(aIn.mParam.mTrack, MOZ_ARRAY_LENGTH(aIn.mParam.mTrack)), aPDU); break; case AVRCP_EVENT_TRACK_REACHED_END: /* fall through */ case AVRCP_EVENT_TRACK_REACHED_START: /* no data to pack */ rv = NS_OK; break; case AVRCP_EVENT_PLAY_POS_CHANGED: rv = PackPDU(aIn.mParam.mSongPos, aPDU); break; case AVRCP_EVENT_APP_SETTINGS_CHANGED: /* pack number of attribute-value pairs */ rv = PackPDU(aIn.mParam.mNumAttr, aPDU); if (NS_FAILED(rv)) { return rv; } /* pack attribute-value pairs */ rv = PackPDU(BluetoothAvrcpAttributeValuePairs(aIn.mParam.mIds, aIn.mParam.mValues, aIn.mParam.mNumAttr), aPDU); break; default: rv = NS_ERROR_ILLEGAL_VALUE; break; } return rv; } nsresult PackPDU(BluetoothAvrcpNotification aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(BluetoothAvrcpPlayerAttribute aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(BluetoothAvrcpStatus aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothConfigurationParameter& aIn, DaemonSocketPDU& aPDU) { return PackPDU(aIn.mType, aIn.mLength, PackArray(aIn.mValue.get(), aIn.mLength), aPDU); } nsresult PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU) { return PackPDU(aIn.mService, aIn.mOpcode, aIn.mLength, aPDU); } nsresult PackPDU(const BluetoothHandsfreeAtResponse& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothHandsfreeCallAddressType& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothHandsfreeCallDirection& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothHandsfreeCallMode& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothHandsfreeCallMptyType& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothHandsfreeCallState& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothHandsfreeNetworkState& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothHandsfreeServiceType& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothHandsfreeVolumeType& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothHandsfreeWbsConfig& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothNamedValue& aIn, DaemonSocketPDU& aPDU) { nsresult rv = PackPDU( PackConversion(aIn.name()), aPDU); if (NS_FAILED(rv)) { return rv; } if (aIn.value().type() == BluetoothValue::Tuint32_t) { // Set discoverable timeout rv = PackPDU(static_cast(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(value.Length()), PackArray( reinterpret_cast(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(sizeof(int32_t)), PackConversion(value), aPDU); } else { BT_LOGR("Invalid property value type"); rv = NS_ERROR_ILLEGAL_VALUE; } return rv; } nsresult PackPDU(const BluetoothPinCode& aIn, DaemonSocketPDU& aPDU) { return PackPDU(aIn.mLength, PackArray(aIn.mPinCode, sizeof(aIn.mPinCode)), aPDU); } nsresult PackPDU(BluetoothPropertyType aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(BluetoothSspVariant aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(BluetoothScanMode aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothServiceName& aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackArray(aIn.mName, sizeof(aIn.mName)), aPDU); } nsresult PackPDU(BluetoothSocketType aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(ControlPlayStatus aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(BluetoothTransport aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(const BluetoothUuid& aIn, DaemonSocketPDU& aPDU) { return PackPDU( PackArray(aIn.mUuid, sizeof(aIn.mUuid)), aPDU); } nsresult PackPDU(const BluetoothGattId& aIn, DaemonSocketPDU& aPDU) { nsresult rv = PackPDU(PackReversed(aIn.mUuid), aPDU); if (NS_FAILED(rv)) { return rv; } return PackPDU(aIn.mInstanceId, aPDU); } nsresult PackPDU(const BluetoothGattServiceId& aIn, DaemonSocketPDU& aPDU) { nsresult rv = PackPDU(aIn.mId, aPDU); if (NS_FAILED(rv)) { return rv; } return PackPDU(aIn.mIsPrimary, aPDU); } nsresult PackPDU(BluetoothGattAuthReq aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } nsresult PackPDU(BluetoothGattWriteType aIn, DaemonSocketPDU& aPDU) { return PackPDU(PackConversion(aIn), aPDU); } // // Unpacking // nsresult UnpackPDU(DaemonSocketPDU& aPDU, bool& aOut) { return UnpackPDU(aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, char& aOut) { return UnpackPDU(aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothA2dpAudioState& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothA2dpConnectionState& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothAclState& aOut) { return UnpackPDU(aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothAvrcpEvent& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothAvrcpMediaAttribute& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothAvrcpPlayerAttribute& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothAvrcpPlayerSettings& aOut) { /* Read number of attribute-value pairs */ nsresult rv = UnpackPDU(aPDU, aOut.mNumAttr); if (NS_FAILED(rv)) { return rv; } /* Read attribute-value pairs */ for (uint8_t i = 0; i < aOut.mNumAttr; ++i) { nsresult rv = UnpackPDU(aPDU, aOut.mIds[i]); if (NS_FAILED(rv)) { return rv; } rv = UnpackPDU(aPDU, aOut.mValues[i]); if (NS_FAILED(rv)) { return rv; } } return NS_OK; } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothAvrcpRemoteFeature& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothBondState& aOut) { return UnpackPDU(aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothTypeOfDevice& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeAudioState& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeCallHoldType& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeConnectionState& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeNRECState& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeVoiceRecognitionState& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeVolumeType& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& 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(data), len)); } break; case PROPERTY_BDADDR: rv = UnpackPDU( aPDU, UnpackConversion(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 addresses; UnpackArray addressArray(addresses, numAddresses); rv = UnpackPDU(aPDU, addressArray); if (NS_FAILED(rv)) { return rv; } /* convert addresses to strings */ aOut.mStringArray.SetLength(numAddresses); ConvertArray 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(DaemonSocketPDU& aPDU, BluetoothPropertyType& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothRemoteInfo& aOut) { nsresult rv = UnpackPDU(aPDU, UnpackConversion(aOut.mVerMajor)); if (NS_FAILED(rv)) { return rv; } rv = UnpackPDU(aPDU, UnpackConversion(aOut.mVerMinor)); if (NS_FAILED(rv)) { return rv; } return UnpackPDU(aPDU, UnpackConversion(aOut.mManufacturer)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothScanMode& aOut) { return UnpackPDU(aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& 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(DaemonSocketPDU& aPDU, BluetoothSspVariant& aOut) { return UnpackPDU( aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothStatus& aOut) { return UnpackPDU(aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattStatus& aOut) { return UnpackPDU(aPDU, UnpackConversion(aOut)); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattId& aOut) { /* unpack UUID */ nsresult rv = UnpackPDU(aPDU, UnpackReversed(aOut.mUuid)); if (NS_FAILED(rv)) { return rv; } /* unpack instance id */ return UnpackPDU(aPDU, aOut.mInstanceId); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattServiceId& aOut) { /* unpack id */ nsresult rv = UnpackPDU(aPDU, aOut.mId); if (NS_FAILED(rv)) { return rv; } /* unpack isPrimary */ return UnpackPDU(aPDU, aOut.mIsPrimary); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattReadParam& aOut) { /* unpack service id */ nsresult rv = UnpackPDU(aPDU, aOut.mServiceId); if (NS_FAILED(rv)) { return rv; } /* unpack characteristic id */ rv = UnpackPDU(aPDU, aOut.mCharId); if (NS_FAILED(rv)) { return rv; } /* unpack descriptor id */ rv = UnpackPDU(aPDU, aOut.mDescriptorId); if (NS_FAILED(rv)) { return rv; } /* unpack status */ rv = UnpackPDU(aPDU, aOut.mStatus); if (NS_FAILED(rv)) { return rv; } /* unpack value type */ rv = UnpackPDU(aPDU, aOut.mValueType); if (NS_FAILED(rv)) { return rv; } /* unpack length */ rv = UnpackPDU(aPDU, aOut.mValueLength); if (NS_FAILED(rv)) { return rv; } /* unpack value */ return aPDU.Read(aOut.mValue, aOut.mValueLength); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattWriteParam& aOut) { /* unpack service id */ nsresult rv = UnpackPDU(aPDU, aOut.mServiceId); if (NS_FAILED(rv)) { return rv; } /* unpack characteristic id */ rv = UnpackPDU(aPDU, aOut.mCharId); if (NS_FAILED(rv)) { return rv; } /* unpack descriptor id */ rv = UnpackPDU(aPDU, aOut.mDescriptorId); if (NS_FAILED(rv)) { return rv; } /* unpack status */ return UnpackPDU(aPDU, aOut.mStatus); } nsresult UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattNotifyParam& aOut) { /* unpack address and convert to nsString */ BluetoothAddress address; nsresult rv = UnpackPDU(aPDU, address); if (NS_FAILED(rv)) { return rv; } rv = Convert(address, aOut.mBdAddr); if (NS_FAILED(rv)) { return rv; } /* unpack service id */ rv = UnpackPDU(aPDU, aOut.mServiceId); if (NS_FAILED(rv)) { return rv; } /* unpack characteristic id */ rv = UnpackPDU(aPDU, aOut.mCharId); if (NS_FAILED(rv)) { return rv; } /* unpack isNotify */ rv = UnpackPDU(aPDU, aOut.mIsNotify); if (NS_FAILED(rv)) { return rv; } /* unpack length */ rv = UnpackPDU(aPDU, aOut.mLength); if (NS_FAILED(rv)) { return rv; } /* unpack value */ return aPDU.Read(aOut.mValue, aOut.mLength); } nsresult UnpackPDU(DaemonSocketPDU& 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(aPDU.Consume(1)); if (NS_WARN_IF(!str)) { return NS_ERROR_ILLEGAL_VALUE; // end of PDU } const char* end = static_cast(memchr(str, '\0', aPDU.GetSize() + 1)); 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(DaemonSocketPDU& 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(DaemonSocketPDU& 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