3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2014-2017 Nest Labs, Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * This module implements encode, decode, fragmentation and reassembly of
22 * Bluetooth Transport Layer (BTP) packet types for transport of a
23 * CHIP-over-Bluetooth Low Energy (CHIPoBLE) byte-stream over point-to-point
24 * Bluetooth Low Energy (BLE) links.
28 #include <ble/BleConfig.h>
30 #if CONFIG_NETWORK_LAYER_BLE
32 #include <ble/BtpEngine.h>
33 #if CHIP_ENABLE_CHIPOBLE_TEST
34 #include <ble/BtpEngineTest.h>
37 #include <support/BufferReader.h>
38 #include <support/CodeUtils.h>
39 #include <support/logging/CHIPLogging.h>
41 // Define below to enable extremely verbose BLE-specific debug logging.
42 #undef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
44 #ifdef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
45 #define ChipLogDebugBtpEngine(MOD, MSG, ...) ChipLogError(MOD, MSG, ##__VA_ARGS__)
47 #define ChipLogDebugBtpEngine(MOD, MSG, ...)
53 static inline void IncSeqNum(SequenceNumber_t & a_seq_num)
55 a_seq_num = static_cast<SequenceNumber_t>(0xff & ((a_seq_num) + 1));
58 static inline bool DidReceiveData(BitFlags<BtpEngine::HeaderFlags> rx_flags)
60 return rx_flags.HasAny(BtpEngine::HeaderFlags::kStartMessage, BtpEngine::HeaderFlags::kContinueMessage,
61 BtpEngine::HeaderFlags::kEndMessage);
64 static void PrintBufDebug(const System::PacketBufferHandle & buf)
66 #ifdef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
67 uint8_t * b = buf->Start();
69 for (int i = 0; i < buf->DataLength(); i++)
71 ChipLogError(Ble, "\t%02x", b[i]);
76 const uint16_t BtpEngine::sDefaultFragmentSize = 20; // 23-byte minimum ATT_MTU - 3 bytes for ATT operation header
77 const uint16_t BtpEngine::sMaxFragmentSize = 128; // Size of write and indication characteristics
79 BLE_ERROR BtpEngine::Init(void * an_app_state, bool expect_first_ack)
81 mAppState = an_app_state;
82 mRxState = kState_Idle;
84 mRxNewestUnackedSeqNum = 0;
85 mRxOldestUnackedSeqNum = 0;
86 mRxFragmentSize = sDefaultFragmentSize;
87 mTxState = kState_Idle;
89 mTxFragmentSize = sDefaultFragmentSize;
94 mTxNewestUnackedSeqNum = 0;
95 mTxOldestUnackedSeqNum = 0;
96 #if CHIP_ENABLE_CHIPOBLE_TEST
97 mTxPacketType = kType_Data; // Default BtpEngine Data packet
98 mRxPacketType = kType_Data; // Default BtpEngine Data packet
101 if (expect_first_ack)
104 mExpectingAck = true;
110 mExpectingAck = false;
117 SequenceNumber_t BtpEngine::GetAndIncrementNextTxSeqNum()
119 SequenceNumber_t ret = mTxNextSeqNum;
121 // If not already expecting ack...
124 mExpectingAck = true;
125 mTxOldestUnackedSeqNum = mTxNextSeqNum;
128 // Update newest unacknowledged sequence number.
129 mTxNewestUnackedSeqNum = mTxNextSeqNum;
131 // Increment mTxNextSeqNum.
132 IncSeqNum(mTxNextSeqNum);
137 SequenceNumber_t BtpEngine::GetAndRecordRxAckSeqNum()
139 SequenceNumber_t ret = mRxNewestUnackedSeqNum;
141 mRxNewestUnackedSeqNum = mRxNextSeqNum;
142 mRxOldestUnackedSeqNum = mRxNextSeqNum;
147 bool BtpEngine::HasUnackedData() const
149 return (mRxOldestUnackedSeqNum != mRxNextSeqNum);
152 bool BtpEngine::IsValidAck(SequenceNumber_t ack_num) const
154 ChipLogDebugBtpEngine(Ble, "entered IsValidAck, ack = %u, oldest = %u, newest = %u", ack_num, mTxOldestUnackedSeqNum,
155 mTxNewestUnackedSeqNum);
157 // Return false if not awaiting any ack.
160 ChipLogDebugBtpEngine(Ble, "unexpected ack is invalid");
164 // Assumption: maximum valid sequence number equals maximum value of SequenceNumber_t.
166 if (mTxNewestUnackedSeqNum >= mTxOldestUnackedSeqNum) // If current unacked interval does NOT wrap...
168 return (ack_num <= mTxNewestUnackedSeqNum && ack_num >= mTxOldestUnackedSeqNum);
170 // Else, if current unacked interval DOES wrap...
171 return (ack_num <= mTxNewestUnackedSeqNum || ack_num >= mTxOldestUnackedSeqNum);
174 BLE_ERROR BtpEngine::HandleAckReceived(SequenceNumber_t ack_num)
176 BLE_ERROR err = BLE_NO_ERROR;
178 ChipLogDebugBtpEngine(Ble, "entered HandleAckReceived, ack_num = %u", ack_num);
180 // Ensure ack_num falls within range of ack values we're expecting.
181 VerifyOrExit(IsValidAck(ack_num), err = BLE_ERROR_INVALID_ACK);
183 if (mTxNewestUnackedSeqNum == ack_num) // If ack is for newest outstanding unacknowledged fragment...
185 mTxOldestUnackedSeqNum = ack_num;
187 // All oustanding fragments have been acknowledged.
188 mExpectingAck = false;
190 else // If ack is valid, but not for newest oustanding unacknowledged fragment...
192 // Update newest unacknowledged fragment to one past that which was just acknowledged.
193 mTxOldestUnackedSeqNum = ack_num;
194 IncSeqNum(mTxOldestUnackedSeqNum);
201 // Calling convention:
202 // EncodeStandAloneAck may only be called if data arg is commited for immediate, synchronous subsequent transmission.
203 BLE_ERROR BtpEngine::EncodeStandAloneAck(const PacketBufferHandle & data)
205 BLE_ERROR err = BLE_NO_ERROR;
206 uint8_t * characteristic;
208 // Ensure enough headroom exists for the lower BLE layers.
209 VerifyOrExit(data->EnsureReservedSize(CHIP_CONFIG_BLE_PKT_RESERVED_SIZE), err = BLE_ERROR_NO_MEMORY);
211 // Ensure enough space for standalone ack payload.
212 VerifyOrExit(data->MaxDataLength() >= kTransferProtocolStandaloneAckHeaderSize, err = BLE_ERROR_NO_MEMORY);
213 characteristic = data->Start();
215 // Since there's no preexisting message payload, we can write BTP header without adjusting data start pointer.
216 characteristic[0] = static_cast<uint8_t>(HeaderFlags::kFragmentAck);
218 // Acknowledge most recently received sequence number.
219 characteristic[1] = GetAndRecordRxAckSeqNum();
220 ChipLogDebugBtpEngine(Ble, "===> encoded stand-alone ack = %u", characteristic[1]);
222 // Include sequence number for stand-alone ack itself.
223 characteristic[2] = GetAndIncrementNextTxSeqNum();
225 // Set ack payload data length.
226 data->SetDataLength(kTransferProtocolStandaloneAckHeaderSize);
232 // Calling convention:
233 // BtpEngine does not retain ownership of reassembled messages, layer above needs to free when done.
235 // BtpEngine does not reset itself on error. Upper layer should free outbound message and inbound reassembly buffers
236 // if there is a problem.
238 // HandleCharacteristicReceived():
240 // Non-NULL characteristic data arg is always either designated as or appended to the message reassembly buffer,
241 // or freed if it holds a stand-alone ack. In all cases, caller must clear its reference to data arg when this
244 // Upper layer must immediately clean up and reinitialize protocol engine if returned err != BLE_NO_ERROR.
245 BLE_ERROR BtpEngine::HandleCharacteristicReceived(System::PacketBufferHandle data, SequenceNumber_t & receivedAck,
246 bool & didReceiveAck)
248 BLE_ERROR err = BLE_NO_ERROR;
249 BitFlags<HeaderFlags> rx_flags;
250 // BLE data uses little-endian byte order.
251 Encoding::LittleEndian::Reader reader(data->Start(), data->DataLength());
253 VerifyOrExit(!data.IsNull(), err = BLE_ERROR_BAD_ARGS);
257 // Get header flags, always in first byte.
258 VerifyOrExit(reader.Read8(rx_flags.RawStorage()).StatusCode() == CHIP_NO_ERROR, err = BLE_ERROR_MESSAGE_INCOMPLETE);
259 #if CHIP_ENABLE_CHIPOBLE_TEST
260 if (rx_flags.Has(HeaderFlags::kCommandMessage))
261 SetRxPacketType(kType_Control);
263 SetRxPacketType(kType_Data);
266 didReceiveAck = rx_flags.Has(HeaderFlags::kFragmentAck);
268 // Get ack number, if any.
271 VerifyOrExit(reader.Read8(&receivedAck).StatusCode() == CHIP_NO_ERROR, err = BLE_ERROR_MESSAGE_INCOMPLETE);
273 err = HandleAckReceived(receivedAck);
277 // Get sequence number.
278 VerifyOrExit(reader.Read8(&mRxNewestUnackedSeqNum).StatusCode() == CHIP_NO_ERROR, err = BLE_ERROR_MESSAGE_INCOMPLETE);
280 // Verify that received sequence number is the next one we'd expect.
281 VerifyOrExit(mRxNewestUnackedSeqNum == mRxNextSeqNum, err = BLE_ERROR_INVALID_BTP_SEQUENCE_NUMBER);
283 // Increment next expected rx sequence number.
284 IncSeqNum(mRxNextSeqNum);
286 // If fragment was stand-alone ack, we're done here; no payload for message reassembler.
287 if (!DidReceiveData(rx_flags))
292 // Truncate the incoming fragment length by the mRxFragmentSize as the negotiated
293 // mRxFragnentSize may be smaller than the characteristic size. Make sure
294 // we're not truncating to a data length smaller than what we have already consumed.
295 VerifyOrExit(reader.OctetsRead() <= mRxFragmentSize, err = BLE_ERROR_REASSEMBLER_INCORRECT_STATE);
296 data->SetDataLength(chip::min(data->DataLength(), mRxFragmentSize));
298 // Now mark the bytes we consumed as consumed.
299 data->ConsumeHead(reader.OctetsRead());
301 ChipLogDebugBtpEngine(Ble, ">>> BTP reassembler received data:");
304 if (mRxState == kState_Idle)
306 // We need a new reader, because the state of our outer reader no longer
307 // matches the state of the packetbuffer, both in terms of start
308 // position and available length.
309 Encoding::LittleEndian::Reader startReader(data->Start(), data->DataLength());
311 // Verify StartMessage header flag set.
312 VerifyOrExit(rx_flags.Has(HeaderFlags::kStartMessage), err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
314 VerifyOrExit(startReader.Read16(&mRxLength).StatusCode() == CHIP_NO_ERROR, err = BLE_ERROR_MESSAGE_INCOMPLETE);
316 mRxState = kState_InProgress;
318 data->ConsumeHead(startReader.OctetsRead());
320 // Create a new buffer for use as the Rx re-assembly area.
321 mRxBuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
323 VerifyOrExit(!mRxBuf.IsNull(), err = BLE_ERROR_NO_MEMORY);
325 mRxBuf->AddToEnd(std::move(data));
326 mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
328 else if (mRxState == kState_InProgress)
330 // Verify StartMessage header flag NOT set, since we're in the middle of receiving a message.
331 VerifyOrExit(!rx_flags.Has(HeaderFlags::kStartMessage), err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
333 // Verify ContinueMessage or EndMessage header flag set.
334 VerifyOrExit(rx_flags.HasAny(HeaderFlags::kContinueMessage, HeaderFlags::kEndMessage),
335 err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
337 // Add received fragment to reassembled message buffer.
338 mRxBuf->AddToEnd(std::move(data));
339 mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
341 // For now, limit BtpEngine message size to max length of 1 pbuf, as we do for chip messages sent via IP.
342 // TODO add support for BtpEngine messages longer than 1 pbuf
343 VerifyOrExit(!mRxBuf->HasChainedBuffer(), err = BLE_ERROR_RECEIVED_MESSAGE_TOO_BIG);
347 err = BLE_ERROR_REASSEMBLER_INCORRECT_STATE;
351 if (rx_flags.Has(HeaderFlags::kEndMessage))
353 // Trim remainder, if any, of the received packet buffer based on sender-specified length of reassembled message.
354 int padding = mRxBuf->DataLength() - mRxLength;
358 mRxBuf->SetDataLength(mRxLength);
361 // Ensure all received fragments add up to sender-specified total message size.
362 VerifyOrExit(mRxBuf->DataLength() == mRxLength, err = BLE_ERROR_REASSEMBLER_MISSING_DATA);
364 // We've reassembled the entire message.
365 mRxState = kState_Complete;
370 if (err != BLE_NO_ERROR)
372 mRxState = kState_Error;
374 // Dump protocol engine state, plus header flags and received data length.
375 ChipLogError(Ble, "HandleCharacteristicReceived failed, err = %d, rx_flags = %u", err, rx_flags.Raw());
378 ChipLogError(Ble, "With rx'd ack = %u", receivedAck);
380 if (!mRxBuf.IsNull())
382 ChipLogError(Ble, "With rx buf data length = %u", mRxBuf->DataLength());
388 // Tack received data onto rx buffer, to be freed when end point resets protocol engine on close.
389 if (!mRxBuf.IsNull())
391 mRxBuf->AddToEnd(std::move(data));
395 mRxBuf = std::move(data);
403 PacketBufferHandle BtpEngine::TakeRxPacket()
405 if (mRxState == kState_Complete)
407 mRxState = kState_Idle;
409 return std::move(mRxBuf);
412 // Calling convention:
413 // May only be called if data arg is commited for immediate, synchronous subsequent transmission.
414 // Returns false on error. Caller must free data arg on error.
415 bool BtpEngine::HandleCharacteristicSend(System::PacketBufferHandle data, bool send_ack)
417 uint8_t * characteristic;
420 if (send_ack && !HasUnackedData())
422 ChipLogError(Ble, "HandleCharacteristicSend: send_ack true, but nothing to acknowledge.");
426 if (mTxState == kState_Idle)
433 mTxBuf = std::move(data);
434 mTxState = kState_InProgress;
435 mTxLength = mTxBuf->DataLength();
437 ChipLogDebugBtpEngine(Ble, ">>> CHIPoBle preparing to send whole message:");
440 // Determine fragment header size.
441 uint8_t header_size =
442 send_ack ? kTransferProtocolMaxHeaderSize : (kTransferProtocolMaxHeaderSize - kTransferProtocolAckSize);
444 // Ensure enough headroom exists for the BTP header, and any headroom needed by the lower BLE layers.
445 if (!mTxBuf->EnsureReservedSize(header_size + CHIP_CONFIG_BLE_PKT_RESERVED_SIZE))
448 ChipLogError(Ble, "HandleCharacteristicSend: not enough headroom");
449 mTxState = kState_Error;
450 mTxBuf = nullptr; // Avoid double-free after assignment above, as caller frees data on error.
456 characteristic = mTxBuf->Start();
457 characteristic -= header_size;
458 mTxBuf->SetStart(characteristic);
459 uint8_t cursor = 1; // first position past header flags byte
460 BitFlags<HeaderFlags> headerFlags(HeaderFlags::kStartMessage);
462 #if CHIP_ENABLE_CHIPOBLE_TEST
463 if (TxPacketType() == kType_Control)
464 headerFlags.Set(HeaderFlags::kCommandMessage);
469 headerFlags.Set(HeaderFlags::kFragmentAck);
470 characteristic[cursor++] = GetAndRecordRxAckSeqNum();
471 ChipLogDebugBtpEngine(Ble, "===> encoded piggybacked ack, ack_num = %u", characteristic[cursor - 1]);
474 characteristic[cursor++] = GetAndIncrementNextTxSeqNum();
475 characteristic[cursor++] = static_cast<uint8_t>(mTxLength & 0xff);
476 characteristic[cursor++] = static_cast<uint8_t>(mTxLength >> 8);
478 if ((mTxLength + cursor) <= mTxFragmentSize)
480 mTxBuf->SetDataLength(static_cast<uint16_t>(mTxLength + cursor));
482 headerFlags.Set(HeaderFlags::kEndMessage);
483 mTxState = kState_Complete;
488 mTxBuf->SetDataLength(mTxFragmentSize);
489 mTxLength = static_cast<uint16_t>((mTxLength + cursor) - mTxFragmentSize);
492 characteristic[0] = headerFlags.Raw();
493 ChipLogDebugBtpEngine(Ble, ">>> CHIPoBle preparing to send first fragment:");
496 else if (mTxState == kState_InProgress)
503 // advance past the previous fragment
504 characteristic = mTxBuf->Start();
505 characteristic += mTxFragmentSize;
508 characteristic -= send_ack ? kTransferProtocolMidFragmentMaxHeaderSize
509 : (kTransferProtocolMidFragmentMaxHeaderSize - kTransferProtocolAckSize);
510 mTxBuf->SetStart(characteristic);
511 uint8_t cursor = 1; // first position past header flags byte
513 BitFlags<HeaderFlags> headerFlags(HeaderFlags::kContinueMessage);
515 #if CHIP_ENABLE_CHIPOBLE_TEST
516 if (TxPacketType() == kType_Control)
517 headerFlags.Set(HeaderFlags::kCommandMessage);
522 headerFlags.Set(HeaderFlags::kFragmentAck);
523 characteristic[cursor++] = GetAndRecordRxAckSeqNum();
524 ChipLogDebugBtpEngine(Ble, "===> encoded piggybacked ack, ack_num = %u", characteristic[cursor - 1]);
527 characteristic[cursor++] = GetAndIncrementNextTxSeqNum();
529 if ((mTxLength + cursor) <= mTxFragmentSize)
531 mTxBuf->SetDataLength(static_cast<uint16_t>(mTxLength + cursor));
533 headerFlags.Set(HeaderFlags::kEndMessage);
534 mTxState = kState_Complete;
539 mTxBuf->SetDataLength(mTxFragmentSize);
540 mTxLength = static_cast<uint16_t>((mTxLength + cursor) - mTxFragmentSize);
543 characteristic[0] = headerFlags.Raw();
544 ChipLogDebugBtpEngine(Ble, ">>> CHIPoBle preparing to send additional fragment:");
545 PrintBufDebug(mTxBuf);
556 PacketBufferHandle BtpEngine::TakeTxPacket()
558 if (mTxState == kState_Complete)
560 mTxState = kState_Idle;
562 return std::move(mTxBuf);
565 void BtpEngine::LogState() const
567 ChipLogError(Ble, "mAppState: %p", mAppState);
569 ChipLogError(Ble, "mRxFragmentSize: %d", mRxFragmentSize);
570 ChipLogError(Ble, "mRxState: %d", mRxState);
571 ChipLogError(Ble, "mRxBuf: %d", !mRxBuf.IsNull());
572 ChipLogError(Ble, "mRxNextSeqNum: %d", mRxNextSeqNum);
573 ChipLogError(Ble, "mRxNewestUnackedSeqNum: %d", mRxNewestUnackedSeqNum);
574 ChipLogError(Ble, "mRxOldestUnackedSeqNum: %d", mRxOldestUnackedSeqNum);
575 ChipLogError(Ble, "mRxCharCount: %d", mRxCharCount);
576 ChipLogError(Ble, "mRxPacketCount: %d", mRxPacketCount);
578 ChipLogError(Ble, "mTxFragmentSize: %d", mTxFragmentSize);
579 ChipLogError(Ble, "mTxState: %d", mTxState);
580 ChipLogError(Ble, "mTxBuf: %d", !mTxBuf.IsNull());
581 ChipLogError(Ble, "mTxNextSeqNum: %d", mTxNextSeqNum);
582 ChipLogError(Ble, "mTxNewestUnackedSeqNum: %d", mTxNewestUnackedSeqNum);
583 ChipLogError(Ble, "mTxOldestUnackedSeqNum: %d", mTxOldestUnackedSeqNum);
584 ChipLogError(Ble, "mTxCharCount: %d", mTxCharCount);
585 ChipLogError(Ble, "mTxPacketCount: %d", mTxPacketCount);
588 void BtpEngine::LogStateDebug() const
590 #ifdef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
595 } /* namespace Ble */
596 } /* namespace chip */
598 #endif /* CONFIG_NETWORK_LAYER_BLE */