Add TLV parsing and vendor ID tlv to C++ advertisement.

PiperOrigin-RevId: 635936457
This commit is contained in:
Anay Wadhera
2024-05-21 14:54:28 -07:00
committed by Copybara-Service
parent 0e85eb6a58
commit ffda9da870
3 changed files with 109 additions and 24 deletions
+88 -20
View File
@@ -49,9 +49,36 @@ constexpr uint8_t kVisibilityBitmask = 0b1;
// The bit mask for parsing and writing Device Type.
constexpr uint8_t kDeviceTypeBitmask = 0b111;
// The minimum length of a TLV element.
// 1 byte for type and 1 byte for length, which can be 0.
constexpr uint8_t kTlvMinimumLength = 2;
// LINT.IfChange()
enum class TlvTypes : uint8_t {
kUnknown = 0,
kQrCode = 1,
kVendorId = 2,
};
enum class VendorId : uint8_t {
kNone = 0,
kSamsung = 1,
};
// The length in bytes of the vendor ID in the TLV advertisement.
constexpr uint8_t kVendorIdLength = 1;
// Turns |vendor_id| into a supported vendor ID.
uint8_t ConvertVendorId(uint8_t vendor_id) {
switch (vendor_id) {
case 1:
return 1;
default:
return 0;
}
}
// LINT.ThenChange(//depot/google3/java/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/sharing/provider/connections/certificatemanager/Advertisement.java)
const uint8_t kMinimumSize =
/* Version(3 bits)|Visibility(1 bit)|Device Type(3 bits)|Reserved(1 bits)=
*/
/* Version(3 bits)|Visibility(1 bit)|Device Type(3 bits)|Reserved(1 bits) */
1 + sharing::Advertisement::kSaltSize +
sharing::Advertisement::kMetadataEncryptionKeyHashByteSize;
@@ -94,14 +121,13 @@ ShareTargetType ParseDeviceType(uint8_t b) {
bool ParseHasDeviceName(uint8_t b) {
return ((b >> 4) & kVisibilityBitmask) == 0;
}
} // namespace
// static
std::unique_ptr<Advertisement> Advertisement::NewInstance(
std::vector<uint8_t> salt, std::vector<uint8_t> encrypted_metadata_key,
ShareTargetType device_type, std::optional<std::string> device_name,
int32_t vendor_id) {
uint8_t vendor_id) {
if (salt.size() != Advertisement::kSaltSize) {
NL_LOG(ERROR) << "Failed to create advertisement because the salt did "
"not match the expected length "
@@ -132,8 +158,13 @@ std::unique_ptr<Advertisement> Advertisement::NewInstance(
}
std::vector<uint8_t> Advertisement::ToEndpointInfo() {
// We add 3 bytes for vendor ID because of type (1 byte), len (1 byte), and
// the ID itself (1 byte).
int size = kMinimumSize + (device_name_.has_value() ? 1 : 0) +
(device_name_.has_value() ? device_name_->size() : 0);
(device_name_.has_value() ? device_name_->size() : 0) +
(vendor_id_ != static_cast<uint8_t>(VendorId::kNone)
? (kTlvMinimumLength + kVendorIdLength)
: 0);
std::vector<uint8_t> endpoint_info;
endpoint_info.reserve(size);
@@ -151,6 +182,16 @@ std::vector<uint8_t> Advertisement::ToEndpointInfo() {
device_name_->end());
}
// Add vendor ID if it is not the default |VendorId::kNone|.
if (vendor_id_ != static_cast<uint8_t>(VendorId::kNone)) {
// Add vendor ID in TLV format.
endpoint_info.push_back(static_cast<uint8_t>(TlvTypes::kVendorId));
// Length is 1 byte.
endpoint_info.push_back(kVendorIdLength);
// The vendor ID itself.
endpoint_info.push_back(vendor_id_);
}
return endpoint_info;
}
@@ -182,27 +223,54 @@ std::unique_ptr<Advertisement> Advertisement::FromEndpointInfo(
iter, iter + Advertisement::kMetadataEncryptionKeyHashByteSize);
iter += Advertisement::kMetadataEncryptionKeyHashByteSize;
int device_name_length = 0;
if (iter != endpoint_info.end()) device_name_length = *iter++ & 0xff;
if (endpoint_info.end() - iter < device_name_length ||
(device_name_length == 0 && has_device_name)) {
NL_LOG(ERROR)
<< "Failed to parse advertisement because the device name did "
"not match the expected length "
<< device_name_length;
return nullptr;
}
std::optional<std::string> optional_device_name;
if (device_name_length > 0) {
if (has_device_name) {
int device_name_length = 0;
if (iter != endpoint_info.end()) device_name_length = *iter++ & 0xff;
if (device_name_length == 0 ||
(endpoint_info.end() - iter < device_name_length)) {
NL_LOG(ERROR)
<< "Failed to parse advertisement because the device name did "
"not match the expected length "
<< device_name_length;
return nullptr;
}
optional_device_name = std::string(iter, iter + device_name_length);
iter += device_name_length;
}
uint8_t vendor_id = static_cast<uint8_t>(VendorId::kNone);
while (endpoint_info.end() - iter >= kTlvMinimumLength) {
// We will parse a TLV element now.
TlvTypes type = static_cast<TlvTypes>(*iter++);
uint8_t value_len = *iter++;
if (endpoint_info.end() - iter < value_len) {
NL_LOG(ERROR) << "Invalid length when parsing TLV element: " << value_len;
return nullptr;
}
switch (type) {
case TlvTypes::kVendorId:
if (value_len != kVendorIdLength) {
NL_LOG(ERROR) << "Invalid vendor_id_len: " << value_len;
return nullptr;
}
vendor_id = ConvertVendorId(*iter++);
break;
case TlvTypes::kQrCode:
// TODO: b/341984671 - Implement handling for this TLV type.
break;
default:
NL_LOG(ERROR) << "Unknown TLV type: " << static_cast<uint8_t>(type);
break;
}
iter += value_len;
}
return Advertisement::NewInstance(
std::move(salt), std::move(encrypted_metadata_key), device_type,
std::move(optional_device_name), /*vendor_id=*/0);
std::move(optional_device_name), vendor_id);
}
bool Advertisement::operator==(const Advertisement& other) const {
@@ -217,7 +285,7 @@ Advertisement::Advertisement(int version, std::vector<uint8_t> salt,
std::vector<uint8_t> encrypted_metadata_key,
ShareTargetType device_type,
std::optional<std::string> device_name,
int32_t vendor_id)
uint8_t vendor_id)
: version_(version),
salt_(std::move(salt)),
encrypted_metadata_key_(std::move(encrypted_metadata_key)),
+6 -4
View File
@@ -40,12 +40,14 @@ class Advertisement {
static std::unique_ptr<Advertisement> NewInstance(
std::vector<uint8_t> salt, std::vector<uint8_t> encrypted_metadata_key,
ShareTargetType device_type, std::optional<std::string> device_name,
int32_t vendor_id);
uint8_t vendor_id);
// TODO: b/341967036 - Remove uses of std::optional for device name. Empty
// string should be enough.
Advertisement(int version, std::vector<uint8_t> salt,
std::vector<uint8_t> encrypted_metadata_key,
ShareTargetType device_type,
std::optional<std::string> device_name, int32_t vendor_id);
std::optional<std::string> device_name, uint8_t vendor_id);
~Advertisement() = default;
Advertisement(const Advertisement&) = default;
Advertisement& operator=(const Advertisement&) = default;
@@ -63,7 +65,7 @@ class Advertisement {
ShareTargetType device_type() const { return device_type_; }
const std::optional<std::string>& device_name() const { return device_name_; }
bool HasDeviceName() const { return device_name_.has_value(); }
int32_t vendor_id() const { return vendor_id_; }
uint8_t vendor_id() const { return vendor_id_; }
static std::unique_ptr<Advertisement> FromEndpointInfo(
absl::Span<const uint8_t> endpoint_info);
@@ -91,7 +93,7 @@ class Advertisement {
// The vendor identifier of the remote device. Reference for vendor ID:
// google3/java/com/google/android/gmscore/integ/client/nearby/src/com/google/android/gms/nearby/sharing/SharingOptions.java
const int32_t vendor_id_;
const uint8_t vendor_id_;
};
} // namespace sharing
+15
View File
@@ -67,6 +67,21 @@ INSTANTIATE_TEST_SUITE_P(
.target_type = ShareTargetType::kTablet,
.target_name = std::nullopt,
.vendor_id = 0}));
INSTANTIATE_TEST_SUITE_P(
VendorIds, AdvertisementTest,
testing::Values(
TestParameters{.salt = std::vector<uint8_t>(Advertisement::kSaltSize),
.encrypted_metadata_key = std::vector<uint8_t>(
Advertisement::kMetadataEncryptionKeyHashByteSize),
.target_type = ShareTargetType::kPhone,
.target_name = std::nullopt,
.vendor_id = 0},
TestParameters{.salt = std::vector<uint8_t>(Advertisement::kSaltSize),
.encrypted_metadata_key = std::vector<uint8_t>(
Advertisement::kMetadataEncryptionKeyHashByteSize),
.target_type = ShareTargetType::kPhone,
.target_name = std::nullopt,
.vendor_id = 1}));
INSTANTIATE_TEST_SUITE_P(
TargetNames, AdvertisementTest,
testing::Values(