1 // Copyright 2024 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #include "pw_bluetooth_sapphire/internal/host/l2cap/credit_based_flow_control_rx_engine.h" 16 17 #include <pw_bluetooth/l2cap_frames.emb.h> 18 19 namespace bt::l2cap::internal { 20 21 namespace emboss = pw::bluetooth::emboss; 22 constexpr auto kSduHeaderSize = 23 pw::bluetooth::emboss::KFrameSduHeader::IntrinsicSizeInBytes(); 24 CreditBasedFlowControlRxEngine(FailureCallback failure_callback)25CreditBasedFlowControlRxEngine::CreditBasedFlowControlRxEngine( 26 FailureCallback failure_callback) 27 : failure_callback_(std::move(failure_callback)) {} 28 ProcessPdu(PDU pdu)29ByteBufferPtr CreditBasedFlowControlRxEngine::ProcessPdu(PDU pdu) { 30 if (!pdu.is_valid()) { 31 OnFailure(); 32 return nullptr; 33 } 34 35 size_t sdu_offset = 0; 36 if (!next_sdu_) { 37 if (pdu.length() < kSduHeaderSize) { 38 // This is a PDU containing the start of a new K-Frame SDU, but the 39 // payload isn't large enough to contain the SDU size field as required 40 // by the spec. 41 OnFailure(); 42 return nullptr; 43 } 44 45 StaticByteBuffer<kSduHeaderSize> sdu_size_buffer; 46 pdu.Copy(&sdu_size_buffer, 0, kSduHeaderSize); 47 auto sdu_size = 48 emboss::MakeKFrameSduHeaderView(&sdu_size_buffer).sdu_length().Read(); 49 50 next_sdu_ = std::make_unique<DynamicByteBuffer>(sdu_size); 51 52 // Skip the SDU header when copying the payload. 53 sdu_offset = kSduHeaderSize; 54 } 55 56 if (valid_bytes_ + pdu.length() - sdu_offset > next_sdu_->size()) { 57 // Invalid PDU is larger than the number of remaining bytes in the SDU. 58 OnFailure(); 59 return nullptr; 60 } 61 auto view = next_sdu_->mutable_view(valid_bytes_); 62 valid_bytes_ += pdu.Copy(&view, sdu_offset); 63 64 if (valid_bytes_ < next_sdu_->size()) { 65 // Segmented SDU, wait for additional PDU(s) to complete. 66 return nullptr; 67 } 68 69 valid_bytes_ = 0; 70 return std::move(next_sdu_); 71 } 72 OnFailure()73void CreditBasedFlowControlRxEngine::OnFailure() { 74 failure_callback_(); 75 valid_bytes_ = 0; 76 next_sdu_ = nullptr; 77 } 78 79 } // namespace bt::l2cap::internal 80