Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2014-2017 Nest Labs, Inc.
5 : *
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
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
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.
17 : */
18 :
19 : /**
20 : * @file
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.
25 : *
26 : */
27 :
28 : #include <ble/BleConfig.h>
29 :
30 : #if CONFIG_NETWORK_LAYER_BLE
31 :
32 : #include <ble/BtpEngine.h>
33 : #if CHIP_ENABLE_CHIPOBLE_TEST
34 : #include <ble/BtpEngineTest.h>
35 : #endif
36 :
37 : #include <lib/support/BufferReader.h>
38 : #include <lib/support/CodeUtils.h>
39 : #include <lib/support/logging/CHIPLogging.h>
40 :
41 : // Define below to enable extremely verbose BLE-specific debug logging.
42 : #undef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
43 :
44 : #ifdef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
45 : #define ChipLogDebugBtpEngine(MOD, MSG, ...) ChipLogError(MOD, MSG, ##__VA_ARGS__)
46 : #else
47 : #define ChipLogDebugBtpEngine(MOD, MSG, ...)
48 : #endif
49 :
50 : namespace chip {
51 : namespace Ble {
52 :
53 0 : static inline void IncSeqNum(SequenceNumber_t & a_seq_num)
54 : {
55 0 : a_seq_num = static_cast<SequenceNumber_t>(0xff & ((a_seq_num) + 1));
56 0 : }
57 :
58 0 : static inline bool DidReceiveData(BitFlags<BtpEngine::HeaderFlags> rx_flags)
59 : {
60 0 : return rx_flags.HasAny(BtpEngine::HeaderFlags::kStartMessage, BtpEngine::HeaderFlags::kContinueMessage,
61 0 : BtpEngine::HeaderFlags::kEndMessage);
62 : }
63 :
64 0 : static void PrintBufDebug(const System::PacketBufferHandle & buf)
65 : {
66 : #ifdef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
67 : uint8_t * b = buf->Start();
68 :
69 : for (int i = 0; i < buf->DataLength(); i++)
70 : {
71 : ChipLogError(Ble, "\t%02x", b[i]);
72 : }
73 : #endif
74 0 : }
75 :
76 : const uint16_t BtpEngine::sDefaultFragmentSize = 20; // 23-byte minimum ATT_MTU - 3 bytes for ATT operation header
77 : const uint16_t BtpEngine::sMaxFragmentSize = 244; // Maximum size of BTP segment
78 :
79 0 : CHIP_ERROR BtpEngine::Init(void * an_app_state, bool expect_first_ack)
80 : {
81 0 : mAppState = an_app_state;
82 0 : mRxState = kState_Idle;
83 0 : mRxBuf = nullptr;
84 0 : mRxNewestUnackedSeqNum = 0;
85 0 : mRxOldestUnackedSeqNum = 0;
86 0 : mRxFragmentSize = sDefaultFragmentSize;
87 0 : mTxState = kState_Idle;
88 0 : mTxBuf = nullptr;
89 0 : mTxFragmentSize = sDefaultFragmentSize;
90 0 : mRxCharCount = 0;
91 0 : mRxPacketCount = 0;
92 0 : mTxCharCount = 0;
93 0 : mTxPacketCount = 0;
94 0 : mTxNewestUnackedSeqNum = 0;
95 0 : mTxOldestUnackedSeqNum = 0;
96 : #if CHIP_ENABLE_CHIPOBLE_TEST
97 : mTxPacketType = kType_Data; // Default BtpEngine Data packet
98 : mRxPacketType = kType_Data; // Default BtpEngine Data packet
99 : #endif
100 :
101 0 : if (expect_first_ack)
102 : {
103 0 : mTxNextSeqNum = 1;
104 0 : mExpectingAck = true;
105 0 : mRxNextSeqNum = 0;
106 : }
107 : else
108 : {
109 0 : mTxNextSeqNum = 0;
110 0 : mExpectingAck = false;
111 0 : mRxNextSeqNum = 1;
112 : }
113 :
114 0 : return CHIP_NO_ERROR;
115 : }
116 :
117 0 : SequenceNumber_t BtpEngine::GetAndIncrementNextTxSeqNum()
118 : {
119 0 : SequenceNumber_t ret = mTxNextSeqNum;
120 :
121 : // If not already expecting ack...
122 0 : if (!mExpectingAck)
123 : {
124 0 : mExpectingAck = true;
125 0 : mTxOldestUnackedSeqNum = mTxNextSeqNum;
126 : }
127 :
128 : // Update newest unacknowledged sequence number.
129 0 : mTxNewestUnackedSeqNum = mTxNextSeqNum;
130 :
131 : // Increment mTxNextSeqNum.
132 0 : IncSeqNum(mTxNextSeqNum);
133 :
134 0 : return ret;
135 : }
136 :
137 0 : SequenceNumber_t BtpEngine::GetAndRecordRxAckSeqNum()
138 : {
139 0 : SequenceNumber_t ret = mRxNewestUnackedSeqNum;
140 :
141 0 : mRxNewestUnackedSeqNum = mRxNextSeqNum;
142 0 : mRxOldestUnackedSeqNum = mRxNextSeqNum;
143 :
144 0 : return ret;
145 : }
146 :
147 : #if CHIP_ENABLE_CHIPOBLE_TEST
148 : bool BtpEngine::IsCommandPacket(const PacketBufferHandle & p)
149 : {
150 : if (p.IsNull())
151 : {
152 : return false;
153 : }
154 :
155 : BitFlags<HeaderFlags> rx_flags;
156 : Encoding::LittleEndian::Reader reader(data->Start(), data->DataLength());
157 : CHIP_ERROR err = reader.Read8(rx_flags.RawStorage()).StatusCode();
158 : if (err != CHIP_NO_ERROR)
159 : {
160 : return false;
161 : }
162 : return rx_flags.Has(HeaderFlags::kCommandMessage);
163 : }
164 : #endif // CHIP_ENABLE_CHIPOBLE_TEST
165 :
166 0 : bool BtpEngine::HasUnackedData() const
167 : {
168 0 : return (mRxOldestUnackedSeqNum != mRxNextSeqNum);
169 : }
170 :
171 0 : bool BtpEngine::IsValidAck(SequenceNumber_t ack_num) const
172 : {
173 : ChipLogDebugBtpEngine(Ble, "entered IsValidAck, ack = %u, oldest = %u, newest = %u", ack_num, mTxOldestUnackedSeqNum,
174 : mTxNewestUnackedSeqNum);
175 :
176 : // Return false if not awaiting any ack.
177 0 : if (!mExpectingAck)
178 : {
179 : ChipLogDebugBtpEngine(Ble, "unexpected ack is invalid");
180 0 : return false;
181 : }
182 :
183 : // Assumption: maximum valid sequence number equals maximum value of SequenceNumber_t.
184 :
185 0 : if (mTxNewestUnackedSeqNum >= mTxOldestUnackedSeqNum) // If current unacked interval does NOT wrap...
186 : {
187 0 : return (ack_num <= mTxNewestUnackedSeqNum && ack_num >= mTxOldestUnackedSeqNum);
188 : }
189 : // Else, if current unacked interval DOES wrap...
190 0 : return (ack_num <= mTxNewestUnackedSeqNum || ack_num >= mTxOldestUnackedSeqNum);
191 : }
192 :
193 0 : CHIP_ERROR BtpEngine::HandleAckReceived(SequenceNumber_t ack_num)
194 : {
195 : ChipLogDebugBtpEngine(Ble, "entered HandleAckReceived, ack_num = %u", ack_num);
196 :
197 : // Ensure ack_num falls within range of ack values we're expecting.
198 0 : VerifyOrReturnError(IsValidAck(ack_num), BLE_ERROR_INVALID_ACK);
199 :
200 0 : if (mTxNewestUnackedSeqNum == ack_num) // If ack is for newest outstanding unacknowledged fragment...
201 : {
202 0 : mTxOldestUnackedSeqNum = ack_num;
203 :
204 : // All outstanding fragments have been acknowledged.
205 0 : mExpectingAck = false;
206 : }
207 : else // If ack is valid, but not for newest outstanding unacknowledged fragment...
208 : {
209 : // Update newest unacknowledged fragment to one past that which was just acknowledged.
210 0 : mTxOldestUnackedSeqNum = ack_num;
211 0 : IncSeqNum(mTxOldestUnackedSeqNum);
212 : }
213 :
214 0 : return CHIP_NO_ERROR;
215 : }
216 :
217 : // Calling convention:
218 : // EncodeStandAloneAck may only be called if data arg is committed for immediate, synchronous subsequent transmission.
219 0 : CHIP_ERROR BtpEngine::EncodeStandAloneAck(const PacketBufferHandle & data)
220 : {
221 : // Ensure enough headroom exists for the lower BLE layers.
222 0 : VerifyOrReturnError(data->EnsureReservedSize(CHIP_CONFIG_BLE_PKT_RESERVED_SIZE), CHIP_ERROR_NO_MEMORY);
223 :
224 : // Ensure enough space for standalone ack payload.
225 0 : VerifyOrReturnError(data->MaxDataLength() >= kTransferProtocolStandaloneAckHeaderSize, CHIP_ERROR_NO_MEMORY);
226 0 : uint8_t * characteristic = data->Start();
227 :
228 : // Since there's no preexisting message payload, we can write BTP header without adjusting data start pointer.
229 0 : characteristic[0] = static_cast<uint8_t>(HeaderFlags::kFragmentAck);
230 :
231 : // Acknowledge most recently received sequence number.
232 0 : characteristic[1] = GetAndRecordRxAckSeqNum();
233 : ChipLogDebugBtpEngine(Ble, "===> encoded stand-alone ack = %u", characteristic[1]);
234 :
235 : // Include sequence number for stand-alone ack itself.
236 0 : characteristic[2] = GetAndIncrementNextTxSeqNum();
237 :
238 : // Set ack payload data length.
239 0 : data->SetDataLength(kTransferProtocolStandaloneAckHeaderSize);
240 :
241 0 : return CHIP_NO_ERROR;
242 : }
243 :
244 : // Calling convention:
245 : // BtpEngine does not retain ownership of reassembled messages, layer above needs to free when done.
246 : //
247 : // BtpEngine does not reset itself on error. Upper layer should free outbound message and inbound reassembly buffers
248 : // if there is a problem.
249 :
250 : // HandleCharacteristicReceived():
251 : //
252 : // Non-NULL characteristic data arg is always either designated as or appended to the message reassembly buffer,
253 : // or freed if it holds a stand-alone ack. In all cases, caller must clear its reference to data arg when this
254 : // function returns.
255 : //
256 : // Upper layer must immediately clean up and reinitialize protocol engine if returned err != CHIP_NO_ERROR.
257 0 : CHIP_ERROR BtpEngine::HandleCharacteristicReceived(System::PacketBufferHandle && data, SequenceNumber_t & receivedAck,
258 : bool & didReceiveAck)
259 : {
260 0 : CHIP_ERROR err = CHIP_NO_ERROR;
261 0 : BitFlags<HeaderFlags> rx_flags;
262 :
263 0 : VerifyOrExit(!data.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
264 :
265 : { // Scope for reader, so we can do the VerifyOrExit above.
266 : // BLE data uses little-endian byte order.
267 0 : Encoding::LittleEndian::Reader reader(data->Start(), data->DataLength());
268 :
269 0 : mRxCharCount++;
270 :
271 : // Get header flags, always in first byte.
272 0 : err = reader.Read8(rx_flags.RawStorage()).StatusCode();
273 0 : SuccessOrExit(err);
274 : #if CHIP_ENABLE_CHIPOBLE_TEST
275 : if (rx_flags.Has(HeaderFlags::kCommandMessage))
276 : SetRxPacketType(kType_Control);
277 : else
278 : SetRxPacketType(kType_Data);
279 : #endif
280 :
281 0 : didReceiveAck = rx_flags.Has(HeaderFlags::kFragmentAck);
282 :
283 : // Get ack number, if any.
284 0 : if (didReceiveAck)
285 : {
286 0 : err = reader.Read8(&receivedAck).StatusCode();
287 0 : SuccessOrExit(err);
288 :
289 0 : err = HandleAckReceived(receivedAck);
290 0 : SuccessOrExit(err);
291 : }
292 :
293 : // Get sequence number.
294 0 : err = reader.Read8(&mRxNewestUnackedSeqNum).StatusCode();
295 0 : SuccessOrExit(err);
296 :
297 : // Verify that received sequence number is the next one we'd expect.
298 0 : VerifyOrExit(mRxNewestUnackedSeqNum == mRxNextSeqNum, err = BLE_ERROR_INVALID_BTP_SEQUENCE_NUMBER);
299 :
300 : // Increment next expected rx sequence number.
301 0 : IncSeqNum(mRxNextSeqNum);
302 :
303 : // If fragment was stand-alone ack, we're done here; no payload for message reassembler.
304 0 : if (!DidReceiveData(rx_flags))
305 : {
306 0 : ExitNow();
307 : }
308 :
309 : // Truncate the incoming fragment length by the mRxFragmentSize as the negotiated
310 : // mRxFragnentSize may be smaller than the characteristic size. Make sure
311 : // we're not truncating to a data length smaller than what we have already consumed.
312 0 : VerifyOrExit(reader.OctetsRead() <= mRxFragmentSize, err = BLE_ERROR_REASSEMBLER_INCORRECT_STATE);
313 0 : data->SetDataLength(chip::min(data->DataLength(), mRxFragmentSize));
314 :
315 : // Now mark the bytes we consumed as consumed.
316 0 : data->ConsumeHead(static_cast<uint16_t>(reader.OctetsRead()));
317 :
318 : ChipLogDebugBtpEngine(Ble, ">>> BTP reassembler received data:");
319 0 : PrintBufDebug(data);
320 : }
321 :
322 0 : if (mRxState == kState_Idle)
323 : {
324 : // We need a new reader, because the state of our outer reader no longer
325 : // matches the state of the packetbuffer, both in terms of start
326 : // position and available length.
327 0 : Encoding::LittleEndian::Reader startReader(data->Start(), data->DataLength());
328 :
329 : // Verify StartMessage header flag set.
330 0 : VerifyOrExit(rx_flags.Has(HeaderFlags::kStartMessage), err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
331 :
332 0 : err = startReader.Read16(&mRxLength).StatusCode();
333 0 : SuccessOrExit(err);
334 :
335 0 : mRxState = kState_InProgress;
336 :
337 0 : data->ConsumeHead(static_cast<uint16_t>(startReader.OctetsRead()));
338 :
339 : // Create a new buffer for use as the Rx re-assembly area.
340 0 : mRxBuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
341 :
342 0 : VerifyOrExit(!mRxBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
343 :
344 0 : mRxBuf->AddToEnd(std::move(data));
345 0 : mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
346 :
347 : // For now, limit BtpEngine message size to max length of 1 pbuf, as we do for chip messages sent via IP.
348 : // TODO add support for BtpEngine messages longer than 1 pbuf
349 0 : VerifyOrExit(!mRxBuf->HasChainedBuffer(), err = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG);
350 : }
351 0 : else if (mRxState == kState_InProgress)
352 : {
353 : // Verify StartMessage header flag NOT set, since we're in the middle of receiving a message.
354 0 : VerifyOrExit(!rx_flags.Has(HeaderFlags::kStartMessage), err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
355 :
356 : // Verify ContinueMessage or EndMessage header flag set.
357 0 : VerifyOrExit(rx_flags.HasAny(HeaderFlags::kContinueMessage, HeaderFlags::kEndMessage),
358 : err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
359 :
360 : // Add received fragment to reassembled message buffer.
361 0 : mRxBuf->AddToEnd(std::move(data));
362 0 : mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
363 :
364 : // For now, limit BtpEngine message size to max length of 1 pbuf, as we do for chip messages sent via IP.
365 : // TODO add support for BtpEngine messages longer than 1 pbuf
366 0 : VerifyOrExit(!mRxBuf->HasChainedBuffer(), err = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG);
367 : }
368 : else
369 : {
370 0 : err = BLE_ERROR_REASSEMBLER_INCORRECT_STATE;
371 0 : ExitNow();
372 : }
373 :
374 0 : if (rx_flags.Has(HeaderFlags::kEndMessage))
375 : {
376 : // Trim remainder, if any, of the received packet buffer based on sender-specified length of reassembled message.
377 0 : int padding = mRxBuf->DataLength() - mRxLength;
378 :
379 0 : if (padding > 0)
380 : {
381 0 : mRxBuf->SetDataLength(mRxLength);
382 : }
383 :
384 : // Ensure all received fragments add up to sender-specified total message size.
385 0 : VerifyOrExit(mRxBuf->DataLength() == mRxLength, err = BLE_ERROR_REASSEMBLER_MISSING_DATA);
386 :
387 : // We've reassembled the entire message.
388 0 : mRxState = kState_Complete;
389 0 : mRxPacketCount++;
390 : }
391 :
392 0 : exit:
393 0 : if (err != CHIP_NO_ERROR)
394 : {
395 0 : mRxState = kState_Error;
396 :
397 : // Dump protocol engine state, plus header flags and received data length.
398 0 : ChipLogError(Ble, "HandleCharacteristicReceived failed, err = %" CHIP_ERROR_FORMAT ", rx_flags = %u", err.Format(),
399 : rx_flags.Raw());
400 0 : if (didReceiveAck)
401 : {
402 0 : ChipLogError(Ble, "With rx'd ack = %u", receivedAck);
403 : }
404 0 : if (!mRxBuf.IsNull())
405 : {
406 0 : ChipLogError(Ble, "With rx buf data length = %u", mRxBuf->DataLength());
407 : }
408 0 : LogState();
409 :
410 0 : if (!data.IsNull()) // NOLINT(bugprone-use-after-move)
411 : {
412 : // Tack received data onto rx buffer, to be freed when end point resets protocol engine on close.
413 0 : if (!mRxBuf.IsNull())
414 : {
415 0 : mRxBuf->AddToEnd(std::move(data));
416 : }
417 : else
418 : {
419 0 : mRxBuf = std::move(data);
420 : }
421 : }
422 : }
423 :
424 0 : return err;
425 : }
426 :
427 0 : PacketBufferHandle BtpEngine::TakeRxPacket()
428 : {
429 0 : if (mRxState == kState_Complete)
430 : {
431 0 : mRxState = kState_Idle;
432 : }
433 0 : return std::move(mRxBuf);
434 : }
435 :
436 : // Calling convention:
437 : // May only be called if data arg is committed for immediate, synchronous subsequent transmission.
438 : // Returns false on error. Caller must free data arg on error.
439 0 : bool BtpEngine::HandleCharacteristicSend(System::PacketBufferHandle data, bool send_ack)
440 : {
441 : uint8_t * characteristic;
442 0 : mTxCharCount++;
443 :
444 0 : if (send_ack && !HasUnackedData())
445 : {
446 0 : ChipLogError(Ble, "HandleCharacteristicSend: send_ack true, but nothing to acknowledge.");
447 0 : return false;
448 : }
449 :
450 0 : if (mTxState == kState_Idle)
451 : {
452 0 : if (data.IsNull())
453 : {
454 0 : return false;
455 : }
456 :
457 0 : mTxBuf = std::move(data);
458 0 : mTxState = kState_InProgress;
459 0 : mTxLength = mTxBuf->DataLength();
460 :
461 : ChipLogDebugBtpEngine(Ble, ">>> CHIPoBle preparing to send whole message:");
462 0 : PrintBufDebug(mTxBuf);
463 :
464 : // Determine fragment header size.
465 0 : uint8_t header_size =
466 : send_ack ? kTransferProtocolMaxHeaderSize : (kTransferProtocolMaxHeaderSize - kTransferProtocolAckSize);
467 :
468 : // Ensure enough headroom exists for the BTP header, and any headroom needed by the lower BLE layers.
469 0 : if (!mTxBuf->EnsureReservedSize(header_size + CHIP_CONFIG_BLE_PKT_RESERVED_SIZE))
470 : {
471 : // handle error
472 0 : ChipLogError(Ble, "HandleCharacteristicSend: not enough headroom");
473 0 : mTxState = kState_Error;
474 0 : mTxBuf = nullptr; // Avoid double-free after assignment above, as caller frees data on error.
475 :
476 0 : return false;
477 : }
478 :
479 : // prepend header.
480 0 : characteristic = mTxBuf->Start();
481 0 : characteristic -= header_size;
482 0 : mTxBuf->SetStart(characteristic);
483 0 : uint8_t cursor = 1; // first position past header flags byte
484 0 : BitFlags<HeaderFlags> headerFlags(HeaderFlags::kStartMessage);
485 :
486 : #if CHIP_ENABLE_CHIPOBLE_TEST
487 : if (TxPacketType() == kType_Control)
488 : headerFlags.Set(HeaderFlags::kCommandMessage);
489 : #endif
490 :
491 0 : if (send_ack)
492 : {
493 0 : headerFlags.Set(HeaderFlags::kFragmentAck);
494 0 : characteristic[cursor++] = GetAndRecordRxAckSeqNum();
495 : ChipLogDebugBtpEngine(Ble, "===> encoded piggybacked ack, ack_num = %u", characteristic[cursor - 1]);
496 : }
497 :
498 0 : characteristic[cursor++] = GetAndIncrementNextTxSeqNum();
499 0 : characteristic[cursor++] = static_cast<uint8_t>(mTxLength & 0xff);
500 0 : characteristic[cursor++] = static_cast<uint8_t>(mTxLength >> 8);
501 :
502 0 : if ((mTxLength + cursor) <= mTxFragmentSize)
503 : {
504 0 : mTxBuf->SetDataLength(static_cast<uint16_t>(mTxLength + cursor));
505 0 : mTxLength = 0;
506 0 : headerFlags.Set(HeaderFlags::kEndMessage);
507 0 : mTxState = kState_Complete;
508 0 : mTxPacketCount++;
509 : }
510 : else
511 : {
512 0 : mTxBuf->SetDataLength(mTxFragmentSize);
513 0 : mTxLength = static_cast<uint16_t>((mTxLength + cursor) - mTxFragmentSize);
514 : }
515 :
516 0 : characteristic[0] = headerFlags.Raw();
517 : ChipLogDebugBtpEngine(Ble, ">>> CHIPoBle preparing to send first fragment:");
518 0 : PrintBufDebug(mTxBuf);
519 : }
520 0 : else if (mTxState == kState_InProgress)
521 : {
522 0 : if (!data.IsNull())
523 : {
524 0 : return false;
525 : }
526 :
527 : // advance past the previous fragment
528 0 : characteristic = mTxBuf->Start();
529 0 : characteristic += mTxFragmentSize;
530 :
531 : // prepend header
532 0 : characteristic -= send_ack ? kTransferProtocolMidFragmentMaxHeaderSize
533 : : (kTransferProtocolMidFragmentMaxHeaderSize - kTransferProtocolAckSize);
534 0 : mTxBuf->SetStart(characteristic);
535 0 : uint8_t cursor = 1; // first position past header flags byte
536 :
537 0 : BitFlags<HeaderFlags> headerFlags(HeaderFlags::kContinueMessage);
538 :
539 : #if CHIP_ENABLE_CHIPOBLE_TEST
540 : if (TxPacketType() == kType_Control)
541 : headerFlags.Set(HeaderFlags::kCommandMessage);
542 : #endif
543 :
544 0 : if (send_ack)
545 : {
546 0 : headerFlags.Set(HeaderFlags::kFragmentAck);
547 0 : characteristic[cursor++] = GetAndRecordRxAckSeqNum();
548 : ChipLogDebugBtpEngine(Ble, "===> encoded piggybacked ack, ack_num = %u", characteristic[cursor - 1]);
549 : }
550 :
551 0 : characteristic[cursor++] = GetAndIncrementNextTxSeqNum();
552 :
553 0 : if ((mTxLength + cursor) <= mTxFragmentSize)
554 : {
555 0 : mTxBuf->SetDataLength(static_cast<uint16_t>(mTxLength + cursor));
556 0 : mTxLength = 0;
557 0 : headerFlags.Set(HeaderFlags::kEndMessage);
558 0 : mTxState = kState_Complete;
559 0 : mTxPacketCount++;
560 : }
561 : else
562 : {
563 0 : mTxBuf->SetDataLength(mTxFragmentSize);
564 0 : mTxLength = static_cast<uint16_t>((mTxLength + cursor) - mTxFragmentSize);
565 : }
566 :
567 0 : characteristic[0] = headerFlags.Raw();
568 : ChipLogDebugBtpEngine(Ble, ">>> CHIPoBle preparing to send additional fragment:");
569 0 : PrintBufDebug(mTxBuf);
570 : }
571 : else
572 : {
573 : // Invalid tx state.
574 0 : return false;
575 : }
576 :
577 0 : return true;
578 : }
579 :
580 0 : PacketBufferHandle BtpEngine::TakeTxPacket()
581 : {
582 0 : if (mTxState == kState_Complete)
583 : {
584 0 : mTxState = kState_Idle;
585 : }
586 0 : return std::move(mTxBuf);
587 : }
588 :
589 0 : void BtpEngine::LogState() const
590 : {
591 0 : ChipLogError(Ble, "mAppState: %p", mAppState);
592 :
593 0 : ChipLogError(Ble, "mRxFragmentSize: %d", mRxFragmentSize);
594 0 : ChipLogError(Ble, "mRxState: %d", mRxState);
595 0 : ChipLogError(Ble, "mRxBuf: %d", !mRxBuf.IsNull());
596 0 : ChipLogError(Ble, "mRxNextSeqNum: %d", mRxNextSeqNum);
597 0 : ChipLogError(Ble, "mRxNewestUnackedSeqNum: %d", mRxNewestUnackedSeqNum);
598 0 : ChipLogError(Ble, "mRxOldestUnackedSeqNum: %d", mRxOldestUnackedSeqNum);
599 0 : ChipLogError(Ble, "mRxCharCount: %d", mRxCharCount);
600 0 : ChipLogError(Ble, "mRxPacketCount: %d", mRxPacketCount);
601 :
602 0 : ChipLogError(Ble, "mTxFragmentSize: %d", mTxFragmentSize);
603 0 : ChipLogError(Ble, "mTxState: %d", mTxState);
604 0 : ChipLogError(Ble, "mTxBuf: %d", !mTxBuf.IsNull());
605 0 : ChipLogError(Ble, "mTxNextSeqNum: %d", mTxNextSeqNum);
606 0 : ChipLogError(Ble, "mTxNewestUnackedSeqNum: %d", mTxNewestUnackedSeqNum);
607 0 : ChipLogError(Ble, "mTxOldestUnackedSeqNum: %d", mTxOldestUnackedSeqNum);
608 0 : ChipLogError(Ble, "mTxCharCount: %d", mTxCharCount);
609 0 : ChipLogError(Ble, "mTxPacketCount: %d", mTxPacketCount);
610 0 : }
611 :
612 0 : void BtpEngine::LogStateDebug() const
613 : {
614 : #ifdef CHIP_BTP_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
615 : LogState();
616 : #endif
617 0 : }
618 :
619 : } /* namespace Ble */
620 : } /* namespace chip */
621 :
622 : #endif /* CONFIG_NETWORK_LAYER_BLE */
|