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