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