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