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 #include "pw_bluetooth_sapphire/internal/host/common/assert.h" 20 21 namespace bt::l2cap::internal { 22 23 namespace emboss = pw::bluetooth::emboss; 24 constexpr auto kSduHeaderSize = 25 pw::bluetooth::emboss::KFrameSduHeader::IntrinsicSizeInBytes(); 26 CreditBasedFlowControlRxEngine(FailureCallback failure_callback)27CreditBasedFlowControlRxEngine::CreditBasedFlowControlRxEngine( 28 FailureCallback failure_callback) 29 : failure_callback_(std::move(failure_callback)) {} 30 ProcessPdu(PDU pdu)31ByteBufferPtr CreditBasedFlowControlRxEngine::ProcessPdu(PDU pdu) { 32 if (!pdu.is_valid()) { 33 OnFailure(); 34 return nullptr; 35 } 36 37 size_t sdu_offset = 0; 38 if (!next_sdu_) { 39 if (pdu.length() < kSduHeaderSize) { 40 // This is a PDU containing the start of a new K-Frame SDU, but the 41 // payload isn't large enough to contain the SDU size field as required 42 // by the spec. 43 OnFailure(); 44 return nullptr; 45 } 46 47 StaticByteBuffer<kSduHeaderSize> sdu_size_buffer; 48 pdu.Copy(&sdu_size_buffer, 0, kSduHeaderSize); 49 auto sdu_size = 50 emboss::MakeKFrameSduHeaderView(&sdu_size_buffer).sdu_length().Read(); 51 52 next_sdu_ = std::make_unique<DynamicByteBuffer>(sdu_size); 53 54 // Skip the SDU header when copying the payload. 55 sdu_offset = kSduHeaderSize; 56 } 57 58 if (valid_bytes_ + pdu.length() - sdu_offset > next_sdu_->size()) { 59 // Invalid PDU is larger than the number of remaining bytes in the SDU. 60 OnFailure(); 61 return nullptr; 62 } 63 auto view = next_sdu_->mutable_view(valid_bytes_); 64 valid_bytes_ += pdu.Copy(&view, sdu_offset); 65 66 if (valid_bytes_ < next_sdu_->size()) { 67 // Segmented SDU, wait for additional PDU(s) to complete. 68 return nullptr; 69 } 70 71 valid_bytes_ = 0; 72 return std::move(next_sdu_); 73 } 74 OnFailure()75void CreditBasedFlowControlRxEngine::OnFailure() { 76 failure_callback_(); 77 valid_bytes_ = 0; 78 next_sdu_ = nullptr; 79 } 80 81 } // namespace bt::l2cap::internal 82