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