fido_ble_frames.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/fido/cable/fido_ble_frames.h"
  5. #include <algorithm>
  6. #include <limits>
  7. #include <tuple>
  8. #include "base/check_op.h"
  9. #include "base/notreached.h"
  10. #include "base/numerics/safe_conversions.h"
  11. #include "device/fido/fido_constants.h"
  12. #include "device/fido/fido_parsing_utils.h"
  13. namespace device {
  14. FidoBleFrame::FidoBleFrame() = default;
  15. FidoBleFrame::FidoBleFrame(FidoBleDeviceCommand command,
  16. std::vector<uint8_t> data)
  17. : command_(command), data_(std::move(data)) {}
  18. FidoBleFrame::FidoBleFrame(const FidoBleFrame&) = default;
  19. FidoBleFrame& FidoBleFrame::operator=(const FidoBleFrame&) = default;
  20. FidoBleFrame::FidoBleFrame(FidoBleFrame&&) = default;
  21. FidoBleFrame& FidoBleFrame::operator=(FidoBleFrame&&) = default;
  22. FidoBleFrame::~FidoBleFrame() = default;
  23. bool FidoBleFrame::IsValid() const {
  24. switch (command_) {
  25. case FidoBleDeviceCommand::kPing:
  26. case FidoBleDeviceCommand::kMsg:
  27. case FidoBleDeviceCommand::kCancel:
  28. case FidoBleDeviceCommand::kControl:
  29. return true;
  30. case FidoBleDeviceCommand::kKeepAlive:
  31. case FidoBleDeviceCommand::kError:
  32. return data_.size() == 1;
  33. }
  34. NOTREACHED();
  35. return false;
  36. }
  37. FidoBleFrame::KeepaliveCode FidoBleFrame::GetKeepaliveCode() const {
  38. DCHECK_EQ(command_, FidoBleDeviceCommand::kKeepAlive);
  39. DCHECK_EQ(data_.size(), 1u);
  40. return static_cast<KeepaliveCode>(data_[0]);
  41. }
  42. FidoBleFrame::ErrorCode FidoBleFrame::GetErrorCode() const {
  43. DCHECK_EQ(command_, FidoBleDeviceCommand::kError);
  44. DCHECK_EQ(data_.size(), 1u);
  45. return static_cast<ErrorCode>(data_[0]);
  46. }
  47. std::pair<FidoBleFrameInitializationFragment,
  48. base::queue<FidoBleFrameContinuationFragment>>
  49. FidoBleFrame::ToFragments(size_t max_fragment_size) const {
  50. DCHECK_LE(data_.size(), std::numeric_limits<uint16_t>::max());
  51. DCHECK_GE(max_fragment_size, 3u);
  52. // Cast is necessary to ignore too high bits.
  53. auto data_view =
  54. base::make_span(data_.data(), static_cast<uint16_t>(data_.size()));
  55. // Subtract 3 to account for CMD, HLEN and LLEN bytes.
  56. const size_t init_fragment_size =
  57. std::min(max_fragment_size - 3, data_view.size());
  58. FidoBleFrameInitializationFragment initial_fragment(
  59. command_, data_view.size(), data_view.first(init_fragment_size));
  60. base::queue<FidoBleFrameContinuationFragment> other_fragments;
  61. data_view = data_view.subspan(init_fragment_size);
  62. // Subtract 1 to account for SEQ byte.
  63. for (auto cont_data :
  64. fido_parsing_utils::SplitSpan(data_view, max_fragment_size - 1)) {
  65. // High bit must stay cleared.
  66. other_fragments.emplace(cont_data, other_fragments.size() & 0x7F);
  67. }
  68. return {initial_fragment, std::move(other_fragments)};
  69. }
  70. bool operator==(const FidoBleFrame& lhs, const FidoBleFrame& rhs) {
  71. return std::forward_as_tuple(lhs.command(), lhs.data()) ==
  72. std::forward_as_tuple(rhs.command(), rhs.data());
  73. }
  74. FidoBleFrameFragment::FidoBleFrameFragment() = default;
  75. FidoBleFrameFragment::FidoBleFrameFragment(const FidoBleFrameFragment& frame) =
  76. default;
  77. FidoBleFrameFragment::~FidoBleFrameFragment() = default;
  78. FidoBleFrameFragment::FidoBleFrameFragment(base::span<const uint8_t> fragment)
  79. : fragment_(fragment) {}
  80. bool FidoBleFrameInitializationFragment::Parse(
  81. base::span<const uint8_t> data,
  82. FidoBleFrameInitializationFragment* fragment) {
  83. if (data.size() < 3)
  84. return false;
  85. const auto command = static_cast<FidoBleDeviceCommand>(data[0]);
  86. const uint16_t data_length = (static_cast<uint16_t>(data[1]) << 8) + data[2];
  87. if (static_cast<size_t>(data_length) + 3 < data.size())
  88. return false;
  89. *fragment =
  90. FidoBleFrameInitializationFragment(command, data_length, data.subspan(3));
  91. return true;
  92. }
  93. size_t FidoBleFrameInitializationFragment::Serialize(
  94. std::vector<uint8_t>* buffer) const {
  95. buffer->push_back(static_cast<uint8_t>(command_));
  96. buffer->push_back((data_length_ >> 8) & 0xFF);
  97. buffer->push_back(data_length_ & 0xFF);
  98. buffer->insert(buffer->end(), fragment().begin(), fragment().end());
  99. return fragment().size() + 3;
  100. }
  101. bool FidoBleFrameContinuationFragment::Parse(
  102. base::span<const uint8_t> data,
  103. FidoBleFrameContinuationFragment* fragment) {
  104. if (data.empty())
  105. return false;
  106. const uint8_t sequence = data[0];
  107. *fragment = FidoBleFrameContinuationFragment(data.subspan(1), sequence);
  108. return true;
  109. }
  110. size_t FidoBleFrameContinuationFragment::Serialize(
  111. std::vector<uint8_t>* buffer) const {
  112. buffer->push_back(sequence_);
  113. buffer->insert(buffer->end(), fragment().begin(), fragment().end());
  114. return fragment().size() + 1;
  115. }
  116. FidoBleFrameAssembler::FidoBleFrameAssembler(
  117. const FidoBleFrameInitializationFragment& fragment)
  118. : data_length_(fragment.data_length()),
  119. frame_(fragment.command(),
  120. std::vector<uint8_t>(fragment.fragment().begin(),
  121. fragment.fragment().end())) {}
  122. bool FidoBleFrameAssembler::AddFragment(
  123. const FidoBleFrameContinuationFragment& fragment) {
  124. if (fragment.sequence() != sequence_number_)
  125. return false;
  126. sequence_number_ = (sequence_number_ + 1) & 0x7F;
  127. if (static_cast<size_t>(data_length_) <
  128. frame_.data().size() + fragment.fragment().size()) {
  129. return false;
  130. }
  131. frame_.data().insert(frame_.data().end(), fragment.fragment().begin(),
  132. fragment.fragment().end());
  133. return true;
  134. }
  135. bool FidoBleFrameAssembler::IsDone() const {
  136. return frame_.data().size() == data_length_;
  137. }
  138. FidoBleFrame* FidoBleFrameAssembler::GetFrame() {
  139. return IsDone() ? &frame_ : nullptr;
  140. }
  141. FidoBleFrameAssembler::~FidoBleFrameAssembler() = default;
  142. } // namespace device