Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2014-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file implements a Bluetooth Low Energy (BLE) connection
22 : * endpoint abstraction for the byte-streaming,
23 : * connection-oriented CHIP over Bluetooth Low Energy (CHIPoBLE)
24 : * Bluetooth Transport Protocol (BTP).
25 : *
26 : */
27 :
28 : #ifndef __STDC_LIMIT_MACROS
29 : #define __STDC_LIMIT_MACROS
30 : #endif
31 : #include <stdint.h>
32 : #include <string.h>
33 :
34 : #include <ble/BleConfig.h>
35 :
36 : #if CONFIG_NETWORK_LAYER_BLE
37 : #include <lib/core/CHIPConfig.h>
38 :
39 : #include <lib/support/BitFlags.h>
40 : #include <lib/support/CHIPFaultInjection.h>
41 : #include <lib/support/CodeUtils.h>
42 : #include <lib/support/logging/CHIPLogging.h>
43 :
44 : #include <ble/BLEEndPoint.h>
45 : #include <ble/BleLayer.h>
46 : #include <ble/BtpEngine.h>
47 : #if CHIP_ENABLE_CHIPOBLE_TEST
48 : #include "BtpEngineTest.h"
49 : #endif
50 :
51 : // clang-format off
52 :
53 : // Define below to enable extremely verbose, BLE end point-specific debug logging.
54 : #undef CHIP_BLE_END_POINT_DEBUG_LOGGING_ENABLED
55 :
56 : #ifdef CHIP_BLE_END_POINT_DEBUG_LOGGING_ENABLED
57 : #define ChipLogDebugBleEndPoint(MOD, MSG, ...) ChipLogDetail(MOD, MSG, ## __VA_ARGS__)
58 : #else
59 : #define ChipLogDebugBleEndPoint(MOD, MSG, ...)
60 : #endif
61 :
62 : /**
63 : * @def BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD
64 : *
65 : * @brief
66 : * If an end point's receive window drops equal to or below this value, it will send an immediate acknowledgement
67 : * packet to re-open its window instead of waiting for the send-ack timer to expire.
68 : *
69 : */
70 : #define BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD 1
71 :
72 : /**
73 : * @def BLE_UNSUBSCRIBE_TIMEOUT_MS
74 : *
75 : * @brief
76 : * This is amount of time, in milliseconds, which a BLE end point will wait for an unsubscribe operation to complete
77 : * before it automatically releases its BLE connection and frees itself. The default value of 5 seconds is arbitrary.
78 : *
79 : */
80 : #define BLE_UNSUBSCRIBE_TIMEOUT_MS 5000 // 5 seconds
81 :
82 : #define BTP_ACK_SEND_TIMEOUT_MS 2500 // 2.5 seconds
83 :
84 : #define BTP_WINDOW_NO_ACK_SEND_THRESHOLD 1 // Data fragments may only be sent without piggybacked
85 : // acks if receiver's window size is above this threshold.
86 :
87 : // clang-format on
88 :
89 : namespace chip {
90 : namespace Ble {
91 :
92 0 : CHIP_ERROR BLEEndPoint::StartConnect()
93 : {
94 0 : CHIP_ERROR err = CHIP_NO_ERROR;
95 : BleTransportCapabilitiesRequestMessage req;
96 0 : PacketBufferHandle buf;
97 0 : constexpr uint8_t numVersions =
98 : CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION - CHIP_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION + 1;
99 : static_assert(numVersions <= NUM_SUPPORTED_PROTOCOL_VERSIONS, "Incompatibly protocol versions");
100 :
101 : // Ensure we're in the correct state.
102 0 : VerifyOrExit(mState == kState_Ready, err = CHIP_ERROR_INCORRECT_STATE);
103 0 : mState = kState_Connecting;
104 :
105 : // Build BLE transport protocol capabilities request.
106 0 : buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
107 0 : VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
108 :
109 : // Zero-initialize BLE transport capabilities request.
110 0 : memset(&req, 0, sizeof(req));
111 :
112 0 : req.mMtu = mBle->mPlatformDelegate->GetMTU(mConnObj);
113 :
114 0 : req.mWindowSize = BLE_MAX_RECEIVE_WINDOW_SIZE;
115 :
116 : // Populate request with highest supported protocol versions
117 0 : for (uint8_t i = 0; i < numVersions; i++)
118 : {
119 0 : req.SetSupportedProtocolVersion(i, static_cast<uint8_t>(CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION - i));
120 : }
121 :
122 0 : err = req.Encode(buf);
123 0 : SuccessOrExit(err);
124 :
125 : // Start connect timer. Canceled when end point freed or connection established.
126 0 : err = StartConnectTimer();
127 0 : SuccessOrExit(err);
128 :
129 : // Send BLE transport capabilities request to peripheral via GATT write.
130 : // Add reference to message fragment for duration of platform's GATT write attempt. CHIP retains partial
131 : // ownership of message fragment's packet buffer, since this is the same buffer as that of the whole message, just
132 : // with a fragmenter-modified payload offset and data length, by a Retain() on the handle when calling this function.
133 0 : if (!SendWrite(buf.Retain()))
134 : {
135 0 : err = BLE_ERROR_GATT_WRITE_FAILED;
136 0 : ExitNow();
137 : }
138 :
139 : // Free request buffer on write confirmation. Stash a reference to it in mSendQueue, which we don't use anyway
140 : // until the connection has been set up.
141 0 : QueueTx(std::move(buf), kType_Data);
142 :
143 0 : exit:
144 : // If we failed to initiate the connection, close the end point.
145 0 : if (err != CHIP_NO_ERROR)
146 : {
147 0 : StopConnectTimer();
148 0 : DoClose(kBleCloseFlag_AbortTransmission, err);
149 : }
150 :
151 0 : return err;
152 0 : }
153 :
154 0 : CHIP_ERROR BLEEndPoint::HandleConnectComplete()
155 : {
156 0 : CHIP_ERROR err = CHIP_NO_ERROR;
157 :
158 0 : mState = kState_Connected;
159 :
160 : // Cancel the connect timer.
161 0 : StopConnectTimer();
162 :
163 : // We've successfully completed the BLE transport protocol handshake, so let the application know we're open for business.
164 0 : if (mBleTransport != nullptr)
165 : {
166 : // Indicate connect complete to next-higher layer.
167 0 : mBleTransport->OnEndPointConnectComplete(this, CHIP_NO_ERROR);
168 : }
169 : else
170 : {
171 : // If no connect complete callback has been set up, close the end point.
172 0 : err = BLE_ERROR_NO_CONNECT_COMPLETE_CALLBACK;
173 : }
174 :
175 0 : return err;
176 : }
177 :
178 0 : CHIP_ERROR BLEEndPoint::HandleReceiveConnectionComplete()
179 : {
180 0 : CHIP_ERROR err = CHIP_NO_ERROR;
181 :
182 : ChipLogDebugBleEndPoint(Ble, "entered HandleReceiveConnectionComplete");
183 0 : mState = kState_Connected;
184 :
185 : // Cancel receive connection timer.
186 0 : StopReceiveConnectionTimer();
187 :
188 : // We've successfully completed the BLE transport protocol handshake, so let the transport know we're open for business.
189 0 : if (mBleTransport != nullptr)
190 : {
191 : // Indicate BLE transport protocol connection received to next-higher layer.
192 0 : err = mBleTransport->SetEndPoint(this);
193 : }
194 : else
195 : {
196 0 : err = BLE_ERROR_NO_CONNECTION_RECEIVED_CALLBACK;
197 : }
198 :
199 0 : return err;
200 : }
201 :
202 0 : void BLEEndPoint::HandleSubscribeReceived()
203 : {
204 0 : CHIP_ERROR err = CHIP_NO_ERROR;
205 :
206 0 : VerifyOrExit(mState == kState_Connecting || mState == kState_Aborting, err = CHIP_ERROR_INCORRECT_STATE);
207 0 : VerifyOrExit(!mSendQueue.IsNull(), err = CHIP_ERROR_INCORRECT_STATE);
208 :
209 : // Send BTP capabilities response to peripheral via GATT indication.
210 : #if CHIP_ENABLE_CHIPOBLE_TEST
211 : VerifyOrExit(mBtpEngine.PopPacketTag(mSendQueue) == kType_Data, err = BLE_ERROR_INVALID_BTP_HEADER_FLAGS);
212 : #endif
213 : // Add reference to message fragment for duration of platform's GATT indication attempt. CHIP retains partial
214 : // ownership of message fragment's packet buffer, since this is the same buffer as that of the whole message, just
215 : // with a fragmenter-modified payload offset and data length.
216 0 : if (!SendIndication(mSendQueue.Retain()))
217 : {
218 : // Ensure transmit queue is empty and set to NULL.
219 0 : QueueTxLock();
220 0 : mSendQueue = nullptr;
221 0 : QueueTxUnlock();
222 :
223 0 : ChipLogError(Ble, "cap resp ind failed");
224 0 : err = BLE_ERROR_GATT_INDICATE_FAILED;
225 0 : ExitNow();
226 : }
227 :
228 : // Shrink remote receive window counter by 1, since we've sent an indication which requires acknowledgement.
229 0 : mRemoteReceiveWindowSize = static_cast<SequenceNumber_t>(mRemoteReceiveWindowSize - 1);
230 : ChipLogDebugBleEndPoint(Ble, "decremented remote rx window, new size = %u", mRemoteReceiveWindowSize);
231 :
232 : // Start ack recvd timer for handshake indication.
233 0 : err = StartAckReceivedTimer();
234 0 : SuccessOrExit(err);
235 :
236 : ChipLogDebugBleEndPoint(Ble, "got subscribe, sent indication w/ capabilities response");
237 :
238 : // If SendIndication returns true, mSendQueue is freed on indication confirmation, or on close in case of
239 : // connection error.
240 :
241 0 : if (mState != kState_Aborting)
242 : {
243 : // If peripheral accepted the BTP connection, its end point must enter the connected state here, i.e. before it
244 : // receives a GATT confirmation for the capabilities response indication. This behavior is required to handle the
245 : // case where a peripheral's BLE controller passes up the central's first message fragment write before the
246 : // capabilities response indication confirmation. If the end point waited for this indication confirmation before
247 : // it entered the connected state, it'd be in the wrong state to receive the central's first data write, and drop
248 : // the corresponding message fragment.
249 0 : err = HandleReceiveConnectionComplete();
250 0 : SuccessOrExit(err);
251 : } // Else State == kState_Aborting, so we'll close end point when indication confirmation received.
252 :
253 0 : exit:
254 0 : if (err != CHIP_NO_ERROR)
255 : {
256 0 : DoClose(kBleCloseFlag_SuppressCallback | kBleCloseFlag_AbortTransmission, err);
257 : }
258 0 : }
259 :
260 0 : void BLEEndPoint::HandleSubscribeComplete()
261 : {
262 0 : ChipLogProgress(Ble, "subscribe complete, ep = %p", this);
263 0 : mConnStateFlags.Clear(ConnectionStateFlag::kGattOperationInFlight);
264 :
265 0 : CHIP_ERROR err = DriveSending();
266 :
267 0 : if (err != CHIP_NO_ERROR)
268 : {
269 0 : DoClose(kBleCloseFlag_AbortTransmission, CHIP_NO_ERROR);
270 : }
271 0 : }
272 :
273 0 : void BLEEndPoint::HandleUnsubscribeComplete()
274 : {
275 : // Don't bother to clear GattOperationInFlight, we're about to free the end point anyway.
276 0 : Free();
277 0 : }
278 :
279 0 : bool BLEEndPoint::IsConnected(uint8_t state) const
280 : {
281 0 : return (state == kState_Connected || state == kState_Closing);
282 : }
283 :
284 0 : bool BLEEndPoint::IsUnsubscribePending() const
285 : {
286 0 : return mTimerStateFlags.Has(TimerStateFlag::kUnsubscribeTimerRunning);
287 : }
288 :
289 0 : void BLEEndPoint::Abort()
290 : {
291 : // No more callbacks after this point, since application explicitly called Abort().
292 0 : OnConnectComplete = nullptr;
293 0 : OnConnectionClosed = nullptr;
294 0 : OnMessageReceived = nullptr;
295 : #if CHIP_ENABLE_CHIPOBLE_TEST
296 : OnCommandReceived = NULL;
297 : #endif
298 :
299 0 : DoClose(kBleCloseFlag_SuppressCallback | kBleCloseFlag_AbortTransmission, CHIP_NO_ERROR);
300 0 : }
301 :
302 0 : void BLEEndPoint::Close()
303 : {
304 : // No more callbacks after this point, since application explicitly called Close().
305 0 : OnConnectComplete = nullptr;
306 0 : OnConnectionClosed = nullptr;
307 0 : OnMessageReceived = nullptr;
308 : #if CHIP_ENABLE_CHIPOBLE_TEST
309 : OnCommandReceived = NULL;
310 : #endif
311 :
312 0 : DoClose(kBleCloseFlag_SuppressCallback, CHIP_NO_ERROR);
313 0 : }
314 :
315 0 : void BLEEndPoint::DoClose(uint8_t flags, CHIP_ERROR err)
316 : {
317 0 : uint8_t oldState = mState;
318 :
319 : // If end point is not closed or closing, OR end point was closing gracefully, but tx abort has been specified...
320 0 : if ((mState != kState_Closed && mState != kState_Closing) ||
321 0 : (mState == kState_Closing && (flags & kBleCloseFlag_AbortTransmission)))
322 : {
323 : // Cancel Connect and ReceiveConnect timers if they are running.
324 : // Check role first to avoid needless iteration over timer pool.
325 0 : if (mRole == kBleRole_Central)
326 : {
327 0 : StopConnectTimer();
328 : }
329 : else // (mRole == kBleRole_Peripheral), verified on Init
330 : {
331 0 : StopReceiveConnectionTimer();
332 : }
333 :
334 : // If transmit buffer is empty or a transmission abort was specified...
335 0 : if (mBtpEngine.TxState() == BtpEngine::kState_Idle || (flags & kBleCloseFlag_AbortTransmission))
336 : {
337 0 : FinalizeClose(oldState, flags, err);
338 : }
339 : else
340 : {
341 : // Wait for send queue and fragmenter's tx buffer to become empty, to ensure all pending messages have been
342 : // sent. Only free end point and tell platform it can throw away the underlying BLE connection once all
343 : // pending messages have been sent and acknowledged by the remote CHIPoBLE stack, or once the remote stack
344 : // closes the CHIPoBLE connection.
345 : //
346 : // In so doing, BLEEndPoint attempts to emulate the level of reliability afforded by TCPEndPoint and TCP
347 : // sockets in general with a typical default SO_LINGER option. That said, there is no hard guarantee that
348 : // pending messages will be sent once (Do)Close() is called, so developers should use application-level
349 : // messages to confirm the receipt of all data sent prior to a Close() call.
350 0 : mState = kState_Closing;
351 :
352 0 : if ((flags & kBleCloseFlag_SuppressCallback) == 0)
353 : {
354 0 : DoCloseCallback(oldState, flags, err);
355 : }
356 :
357 0 : if ((flags & kBleCloseFlag_SuppressCallback) != 0)
358 : {
359 0 : mBleTransport->OnEndPointConnectionClosed(this, err);
360 : }
361 : }
362 : }
363 0 : }
364 :
365 0 : void BLEEndPoint::FinalizeClose(uint8_t oldState, uint8_t flags, CHIP_ERROR err)
366 : {
367 0 : mState = kState_Closed;
368 :
369 : // Ensure transmit queue is empty and set to NULL.
370 0 : QueueTxLock();
371 0 : mSendQueue = nullptr;
372 0 : QueueTxUnlock();
373 :
374 : // Fire application's close callback if we haven't already, and it's not suppressed.
375 0 : if (oldState != kState_Closing && (flags & kBleCloseFlag_SuppressCallback) == 0)
376 : {
377 0 : DoCloseCallback(oldState, flags, err);
378 : }
379 :
380 0 : if ((flags & kBleCloseFlag_SuppressCallback) != 0)
381 : {
382 0 : mBleTransport->OnEndPointConnectionClosed(this, err);
383 : }
384 :
385 : // If underlying BLE connection has closed, connection object is invalid, so just free the end point and return.
386 0 : if (err == BLE_ERROR_REMOTE_DEVICE_DISCONNECTED || err == BLE_ERROR_APP_CLOSED_CONNECTION)
387 : {
388 0 : mConnObj = BLE_CONNECTION_UNINITIALIZED; // Clear handle to BLE connection, so we don't double-close it.
389 0 : Free();
390 : }
391 : else // Otherwise, try to signal close to remote device before end point releases BLE connection and frees itself.
392 : {
393 0 : if (mRole == kBleRole_Central && mConnStateFlags.Has(ConnectionStateFlag::kDidBeginSubscribe))
394 : {
395 : // Cancel send and receive-ack timers, if running.
396 0 : StopAckReceivedTimer();
397 0 : StopSendAckTimer();
398 :
399 : // Indicate close of chipConnection to peripheral via GATT unsubscribe. Keep end point allocated until
400 : // unsubscribe completes or times out, so platform doesn't close underlying BLE connection before
401 : // we're really sure the unsubscribe request has been sent.
402 0 : if (!mBle->mPlatformDelegate->UnsubscribeCharacteristic(mConnObj, &CHIP_BLE_SVC_ID, &mBle->CHIP_BLE_CHAR_2_ID))
403 : {
404 0 : ChipLogError(Ble, "BtpEngine unsub failed");
405 :
406 : // If unsubscribe fails, release BLE connection and free end point immediately.
407 0 : Free();
408 : }
409 0 : else if (mConnObj != BLE_CONNECTION_UNINITIALIZED)
410 : {
411 : // Unsubscribe request was sent successfully, and a confirmation wasn't spontaneously generated or
412 : // received in the downcall to UnsubscribeCharacteristic, so set timer for the unsubscribe to complete.
413 0 : err = StartUnsubscribeTimer();
414 :
415 0 : if (err != CHIP_NO_ERROR)
416 : {
417 0 : Free();
418 : }
419 :
420 : // Mark unsubscribe GATT operation in progress.
421 0 : mConnStateFlags.Set(ConnectionStateFlag::kGattOperationInFlight);
422 : }
423 : }
424 : else // mRole == kBleRole_Peripheral, OR mTimerStateFlags.Has(ConnectionStateFlag::kDidBeginSubscribe) == false...
425 : {
426 0 : Free();
427 : }
428 : }
429 0 : }
430 :
431 0 : void BLEEndPoint::DoCloseCallback(uint8_t state, uint8_t flags, CHIP_ERROR err)
432 : {
433 0 : if (state == kState_Connecting)
434 : {
435 0 : if (mBleTransport != nullptr)
436 : {
437 0 : mBleTransport->OnEndPointConnectComplete(this, err);
438 : }
439 : }
440 : else
441 : {
442 0 : if (mBleTransport != nullptr)
443 : {
444 0 : mBleTransport->OnEndPointConnectionClosed(this, err);
445 : }
446 : }
447 :
448 : // Callback fires once per end point lifetime.
449 0 : OnConnectComplete = nullptr;
450 0 : OnConnectionClosed = nullptr;
451 0 : }
452 :
453 0 : void BLEEndPoint::ReleaseBleConnection()
454 : {
455 0 : if (mConnObj != BLE_CONNECTION_UNINITIALIZED)
456 : {
457 0 : if (mConnStateFlags.Has(ConnectionStateFlag::kAutoClose))
458 : {
459 0 : ChipLogProgress(Ble, "Auto-closing end point's BLE connection.");
460 0 : mBle->mPlatformDelegate->CloseConnection(mConnObj);
461 : }
462 : else
463 : {
464 0 : ChipLogProgress(Ble, "Releasing end point's BLE connection back to application.");
465 0 : mBle->mApplicationDelegate->NotifyChipConnectionClosed(mConnObj);
466 : }
467 :
468 : // Never release the same BLE connection twice.
469 0 : mConnObj = BLE_CONNECTION_UNINITIALIZED;
470 : }
471 0 : }
472 :
473 0 : void BLEEndPoint::Free()
474 : {
475 : // Release BLE connection. Will close connection if AutoClose enabled for this end point. Otherwise, informs
476 : // application that CHIP is done with this BLE connection, and application makes decision about whether to close
477 : // and clean up or retain connection.
478 0 : ReleaseBleConnection();
479 :
480 : // Clear fragmentation and reassembly engine's Tx and Rx buffers. Counters will be reset by next engine init.
481 0 : FreeBtpEngine();
482 :
483 : // Clear pending ack buffer, if any.
484 0 : mAckToSend = nullptr;
485 :
486 : // Cancel all timers.
487 0 : StopConnectTimer();
488 0 : StopReceiveConnectionTimer();
489 0 : StopAckReceivedTimer();
490 0 : StopSendAckTimer();
491 0 : StopUnsubscribeTimer();
492 : #if CHIP_ENABLE_CHIPOBLE_TEST
493 : mBtpEngineTest.StopTestTimer();
494 : // Clear callback
495 : OnCommandReceived = NULL;
496 : #endif
497 :
498 : // Clear callbacks.
499 0 : OnConnectComplete = nullptr;
500 0 : OnMessageReceived = nullptr;
501 0 : OnConnectionClosed = nullptr;
502 :
503 : // Clear handle to underlying BLE connection.
504 0 : mConnObj = BLE_CONNECTION_UNINITIALIZED;
505 :
506 : // Release the AddRef() that happened when the end point was allocated.
507 0 : Release();
508 0 : }
509 :
510 0 : void BLEEndPoint::FreeBtpEngine()
511 : {
512 : // Free transmit disassembly buffer
513 0 : mBtpEngine.ClearTxPacket();
514 :
515 : // Free receive reassembly buffer
516 0 : mBtpEngine.ClearRxPacket();
517 0 : }
518 :
519 0 : CHIP_ERROR BLEEndPoint::Init(BleLayer * bleLayer, BLE_CONNECTION_OBJECT connObj, BleRole role, bool autoClose)
520 : {
521 : // Fail if already initialized.
522 0 : VerifyOrReturnError(mBle == nullptr, CHIP_ERROR_INCORRECT_STATE);
523 :
524 : // Validate args.
525 0 : VerifyOrReturnError(bleLayer != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
526 0 : VerifyOrReturnError(connObj != BLE_CONNECTION_UNINITIALIZED, CHIP_ERROR_INVALID_ARGUMENT);
527 0 : VerifyOrReturnError((role == kBleRole_Central || role == kBleRole_Peripheral), CHIP_ERROR_INVALID_ARGUMENT);
528 :
529 : // If end point plays peripheral role, expect ack for indication sent as last step of BTP handshake.
530 : // If central, periperal's handshake indication 'ack's write sent by central to kick off the BTP handshake.
531 0 : bool expectInitialAck = (role == kBleRole_Peripheral);
532 :
533 0 : CHIP_ERROR err = mBtpEngine.Init(this, expectInitialAck);
534 0 : if (err != CHIP_NO_ERROR)
535 : {
536 0 : ChipLogError(Ble, "BtpEngine init failed");
537 0 : return err;
538 : }
539 :
540 : #if CHIP_ENABLE_CHIPOBLE_TEST
541 : err = static_cast<CHIP_ERROR>(mTxQueueMutex.Init(mTxQueueMutex));
542 : if (err != CHIP_NO_ERROR)
543 : {
544 : ChipLogError(Ble, "%s: Mutex init failed", __FUNCTION__);
545 : return err;
546 : }
547 : err = mBtpEngineTest.Init(this);
548 : if (err != CHIP_NO_ERROR)
549 : {
550 : ChipLogError(Ble, "BTP test init failed");
551 : return err;
552 : }
553 : #endif
554 :
555 0 : mBle = bleLayer;
556 0 : mRefCount = 1;
557 :
558 : // BLEEndPoint data members:
559 0 : mConnObj = connObj;
560 0 : mRole = role;
561 0 : mTimerStateFlags.ClearAll();
562 0 : mConnStateFlags.ClearAll().Set(ConnectionStateFlag::kAutoClose, autoClose);
563 0 : mLocalReceiveWindowSize = 0;
564 0 : mRemoteReceiveWindowSize = 0;
565 0 : mReceiveWindowMaxSize = 0;
566 0 : mSendQueue = nullptr;
567 0 : mAckToSend = nullptr;
568 :
569 : ChipLogDebugBleEndPoint(Ble, "initialized local rx window, size = %u", mLocalReceiveWindowSize);
570 :
571 : // End point is ready to connect or receive a connection.
572 0 : mState = kState_Ready;
573 :
574 0 : return CHIP_NO_ERROR;
575 : }
576 :
577 0 : void BLEEndPoint::AddRef()
578 : {
579 0 : VerifyOrDie(mRefCount < UINT32_MAX);
580 0 : mRefCount++;
581 0 : }
582 :
583 0 : void BLEEndPoint::Release()
584 : {
585 0 : VerifyOrDie(mRefCount > 0u);
586 : // Decrement the ref count. When it reaches zero, NULL out the pointer to the chip::System::Layer
587 : // object. This effectively declared the object free and ready for re-allocation.
588 0 : mRefCount--;
589 0 : if (mRefCount == 0)
590 : {
591 0 : mBle = nullptr;
592 : }
593 0 : }
594 :
595 0 : CHIP_ERROR BLEEndPoint::SendCharacteristic(PacketBufferHandle && buf)
596 : {
597 0 : CHIP_ERROR err = CHIP_NO_ERROR;
598 :
599 0 : if (mRole == kBleRole_Central)
600 : {
601 0 : if (!SendWrite(std::move(buf)))
602 : {
603 0 : err = BLE_ERROR_GATT_WRITE_FAILED;
604 : }
605 : else
606 : {
607 : // Write succeeded, so shrink remote receive window counter by 1.
608 0 : mRemoteReceiveWindowSize = static_cast<SequenceNumber_t>(mRemoteReceiveWindowSize - 1);
609 : ChipLogDebugBleEndPoint(Ble, "decremented remote rx window, new size = %u", mRemoteReceiveWindowSize);
610 : }
611 : }
612 : else // (mRole == kBleRole_Peripheral), verified on Init
613 : {
614 0 : if (!SendIndication(std::move(buf)))
615 : {
616 0 : err = BLE_ERROR_GATT_INDICATE_FAILED;
617 : }
618 : else
619 : {
620 : // Indication succeeded, so shrink remote receive window counter by 1.
621 0 : mRemoteReceiveWindowSize = static_cast<SequenceNumber_t>(mRemoteReceiveWindowSize - 1);
622 : ChipLogDebugBleEndPoint(Ble, "decremented remote rx window, new size = %u", mRemoteReceiveWindowSize);
623 : }
624 : }
625 :
626 0 : return err;
627 : }
628 :
629 : /*
630 : * Routine to queue the Tx packet with a packet type
631 : * kType_Data(0) - data packet
632 : * kType_Control(1) - control packet
633 : */
634 0 : void BLEEndPoint::QueueTx(PacketBufferHandle && data, PacketType_t type)
635 : {
636 : #if CHIP_ENABLE_CHIPOBLE_TEST
637 : ChipLogDebugBleEndPoint(Ble, "%s: data->%p, type %d, len %d", __FUNCTION__, data, type, data->DataLength());
638 : mBtpEngine.PushPacketTag(data, type);
639 : #endif
640 :
641 0 : QueueTxLock();
642 :
643 0 : if (mSendQueue.IsNull())
644 : {
645 0 : mSendQueue = std::move(data);
646 : ChipLogDebugBleEndPoint(Ble, "%s: Set data as new mSendQueue %p, type %d", __FUNCTION__, mSendQueue->Start(), type);
647 : }
648 : else
649 : {
650 0 : mSendQueue->AddToEnd(std::move(data));
651 : ChipLogDebugBleEndPoint(Ble, "%s: Append data to mSendQueue %p, type %d", __FUNCTION__, mSendQueue->Start(), type);
652 : }
653 :
654 0 : QueueTxUnlock();
655 0 : }
656 :
657 0 : CHIP_ERROR BLEEndPoint::Send(PacketBufferHandle && data)
658 : {
659 : ChipLogDebugBleEndPoint(Ble, "entered Send");
660 :
661 0 : CHIP_ERROR err = CHIP_NO_ERROR;
662 :
663 0 : VerifyOrExit(!data.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
664 0 : VerifyOrExit(IsConnected(mState), err = CHIP_ERROR_INCORRECT_STATE);
665 :
666 : // Ensure outgoing message fits in a single contiguous packet buffer, as currently required by the
667 : // message fragmentation and reassembly engine.
668 0 : if (data->HasChainedBuffer())
669 : {
670 0 : data->CompactHead();
671 :
672 0 : if (data->HasChainedBuffer())
673 : {
674 0 : err = CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG;
675 0 : ExitNow();
676 : }
677 : }
678 :
679 : // Add new message to send queue.
680 0 : QueueTx(std::move(data), kType_Data);
681 :
682 : // Send first fragment of new message, if we can.
683 0 : err = DriveSending();
684 0 : SuccessOrExit(err);
685 :
686 0 : exit:
687 : ChipLogDebugBleEndPoint(Ble, "exiting Send");
688 0 : if (err != CHIP_NO_ERROR)
689 : {
690 0 : DoClose(kBleCloseFlag_AbortTransmission, err);
691 : }
692 :
693 0 : return err;
694 : }
695 :
696 0 : bool BLEEndPoint::PrepareNextFragment(PacketBufferHandle && data, bool & sentAck)
697 : {
698 : // If we have a pending fragment acknowledgement to send, piggyback it on the fragment we're about to transmit.
699 0 : if (mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning))
700 : {
701 : // Reset local receive window counter.
702 0 : mLocalReceiveWindowSize = mReceiveWindowMaxSize;
703 : ChipLogDebugBleEndPoint(Ble, "reset local rx window on piggyback ack tx, size = %u", mLocalReceiveWindowSize);
704 :
705 : // Tell caller AND fragmenter we have an ack to piggyback.
706 0 : sentAck = true;
707 : }
708 : else
709 : {
710 : // No ack to piggyback.
711 0 : sentAck = false;
712 : }
713 :
714 0 : return mBtpEngine.HandleCharacteristicSend(std::move(data), sentAck);
715 : }
716 :
717 0 : CHIP_ERROR BLEEndPoint::SendNextMessage()
718 : {
719 : // Get the first queued packet to send
720 0 : QueueTxLock();
721 : #if CHIP_ENABLE_CHIPOBLE_TEST
722 : // Return if tx queue is empty
723 : // Note: PopHead() does not check an empty queue
724 : if (mSendQueue.IsNull())
725 : {
726 : QueueTxUnlock();
727 : return CHIP_NO_ERROR;
728 : }
729 : #endif
730 :
731 0 : PacketBufferHandle data = mSendQueue.PopHead();
732 0 : QueueTxUnlock();
733 :
734 : #if CHIP_ENABLE_CHIPOBLE_TEST
735 : // Get and consume the packet tag in message buffer
736 : PacketType_t type = mBtpEngine.PopPacketTag(data);
737 : mBtpEngine.SetTxPacketType(type);
738 : mBtpEngineTest.DoTxTiming(data, BTP_TX_START);
739 : #endif
740 :
741 : // Hand whole message payload to the fragmenter.
742 : bool sentAck;
743 0 : VerifyOrReturnError(PrepareNextFragment(std::move(data), sentAck), BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT);
744 :
745 : /*
746 : // Todo: reenabled it after integrating fault injection
747 : // Send first message fragment over the air.
748 : CHIP_FAULT_INJECT(chip::FaultInjection::kFault_CHIPOBLESend, {
749 : if (mRole == kBleRole_Central)
750 : {
751 : err = BLE_ERROR_GATT_WRITE_FAILED;
752 : }
753 : else
754 : {
755 : err = BLE_ERROR_GATT_INDICATE_FAILED;
756 : }
757 : ExitNow();
758 : });
759 : */
760 0 : ReturnErrorOnFailure(SendCharacteristic(mBtpEngine.BorrowTxPacket()));
761 :
762 0 : if (sentAck)
763 : {
764 : // If sent piggybacked ack, stop send-ack timer.
765 0 : StopSendAckTimer();
766 : }
767 :
768 : // Start ack received timer, if it's not already running.
769 0 : return StartAckReceivedTimer();
770 0 : }
771 :
772 0 : CHIP_ERROR BLEEndPoint::ContinueMessageSend()
773 : {
774 : bool sentAck;
775 :
776 0 : if (!PrepareNextFragment(nullptr, sentAck))
777 : {
778 : // Log BTP error
779 0 : ChipLogError(Ble, "btp fragmenter error on send!");
780 0 : mBtpEngine.LogState();
781 :
782 0 : return BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT;
783 : }
784 :
785 0 : ReturnErrorOnFailure(SendCharacteristic(mBtpEngine.BorrowTxPacket()));
786 :
787 0 : if (sentAck)
788 : {
789 : // If sent piggybacked ack, stop send-ack timer.
790 0 : StopSendAckTimer();
791 : }
792 :
793 : // Start ack received timer, if it's not already running.
794 0 : return StartAckReceivedTimer();
795 : }
796 :
797 0 : CHIP_ERROR BLEEndPoint::HandleHandshakeConfirmationReceived()
798 : {
799 : ChipLogDebugBleEndPoint(Ble, "entered HandleHandshakeConfirmationReceived");
800 :
801 0 : CHIP_ERROR err = CHIP_NO_ERROR;
802 0 : uint8_t closeFlags = kBleCloseFlag_AbortTransmission;
803 :
804 : // Free capabilities request/response payload.
805 0 : QueueTxLock();
806 0 : mSendQueue.FreeHead();
807 0 : QueueTxUnlock();
808 :
809 0 : if (mRole == kBleRole_Central)
810 : {
811 : // Subscribe to characteristic which peripheral will use to send indications. Prompts peripheral to send
812 : // BLE transport capabilities indication.
813 0 : VerifyOrExit(mBle->mPlatformDelegate->SubscribeCharacteristic(mConnObj, &CHIP_BLE_SVC_ID, &mBle->CHIP_BLE_CHAR_2_ID),
814 : err = BLE_ERROR_GATT_SUBSCRIBE_FAILED);
815 :
816 : // We just sent a GATT subscribe request, so make sure to attempt unsubscribe on close.
817 0 : mConnStateFlags.Set(ConnectionStateFlag::kDidBeginSubscribe);
818 :
819 : // Mark GATT operation in progress for subscribe request.
820 0 : mConnStateFlags.Set(ConnectionStateFlag::kGattOperationInFlight);
821 : }
822 : else // (mRole == kBleRole_Peripheral), verified on Init
823 : {
824 : ChipLogDebugBleEndPoint(Ble, "got peripheral handshake indication confirmation");
825 :
826 0 : if (mState == kState_Connected) // If we accepted BTP connection...
827 : {
828 : // If local receive window size has shrunk to or below immediate ack threshold, AND a message fragment is not
829 : // pending on which to piggyback an ack, send immediate stand-alone ack.
830 0 : if (mLocalReceiveWindowSize <= BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD && mSendQueue.IsNull())
831 : {
832 0 : err = DriveStandAloneAck(); // Encode stand-alone ack and drive sending.
833 0 : SuccessOrExit(err);
834 : }
835 : else
836 : {
837 : // Drive sending in case application callend Send() after we sent the handshake indication, but
838 : // before the GATT confirmation for this indication was received.
839 0 : err = DriveSending();
840 0 : SuccessOrExit(err);
841 : }
842 : }
843 0 : else if (mState == kState_Aborting) // Else, if we rejected BTP connection...
844 : {
845 0 : closeFlags |= kBleCloseFlag_SuppressCallback;
846 0 : err = BLE_ERROR_INCOMPATIBLE_PROTOCOL_VERSIONS;
847 0 : ExitNow();
848 : }
849 : }
850 :
851 0 : exit:
852 : ChipLogDebugBleEndPoint(Ble, "exiting HandleHandshakeConfirmationReceived");
853 :
854 0 : if (err != CHIP_NO_ERROR)
855 : {
856 0 : DoClose(closeFlags, err);
857 : }
858 :
859 0 : return err;
860 : }
861 :
862 0 : CHIP_ERROR BLEEndPoint::HandleFragmentConfirmationReceived()
863 : {
864 0 : CHIP_ERROR err = CHIP_NO_ERROR;
865 :
866 : ChipLogDebugBleEndPoint(Ble, "entered HandleFragmentConfirmationReceived");
867 :
868 : // Suppress error logging if GATT confirmation overlaps with unsubscribe on final close.
869 0 : if (IsUnsubscribePending())
870 : {
871 : ChipLogDebugBleEndPoint(Ble, "send conf rx'd while unsubscribe in flight");
872 0 : ExitNow();
873 : }
874 :
875 : // Ensure we're in correct state to receive confirmation of non-handshake GATT send.
876 0 : VerifyOrExit(IsConnected(mState), err = CHIP_ERROR_INCORRECT_STATE);
877 :
878 0 : if (mConnStateFlags.Has(ConnectionStateFlag::kStandAloneAckInFlight))
879 : {
880 : // If confirmation was received for stand-alone ack, free its tx buffer.
881 0 : mAckToSend = nullptr;
882 :
883 0 : mConnStateFlags.Clear(ConnectionStateFlag::kStandAloneAckInFlight);
884 : }
885 :
886 : // If local receive window size has shrunk to or below immediate ack threshold, AND a message fragment is not
887 : // pending on which to piggyback an ack, send immediate stand-alone ack.
888 : //
889 : // This check covers the case where the local receive window has shrunk between transmission and confirmation of
890 : // the stand-alone ack, and also the case where a window size < the immediate ack threshold was detected in
891 : // Receive(), but the stand-alone ack was deferred due to a pending outbound message fragment.
892 0 : if (mLocalReceiveWindowSize <= BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD && mSendQueue.IsNull() &&
893 0 : mBtpEngine.TxState() != BtpEngine::kState_InProgress)
894 : {
895 0 : err = DriveStandAloneAck(); // Encode stand-alone ack and drive sending.
896 0 : SuccessOrExit(err);
897 : }
898 : else
899 : {
900 0 : err = DriveSending();
901 0 : SuccessOrExit(err);
902 : }
903 :
904 0 : exit:
905 0 : if (err != CHIP_NO_ERROR)
906 : {
907 0 : DoClose(kBleCloseFlag_AbortTransmission, err);
908 : }
909 :
910 0 : return err;
911 : }
912 :
913 0 : CHIP_ERROR BLEEndPoint::HandleGattSendConfirmationReceived()
914 : {
915 : ChipLogDebugBleEndPoint(Ble, "entered HandleGattSendConfirmationReceived");
916 :
917 : // Mark outstanding GATT operation as finished.
918 0 : mConnStateFlags.Clear(ConnectionStateFlag::kGattOperationInFlight);
919 :
920 : // If confirmation was for outbound portion of BTP connect handshake...
921 0 : if (!mConnStateFlags.Has(ConnectionStateFlag::kCapabilitiesConfReceived))
922 : {
923 0 : mConnStateFlags.Set(ConnectionStateFlag::kCapabilitiesConfReceived);
924 :
925 0 : return HandleHandshakeConfirmationReceived();
926 : }
927 :
928 0 : return HandleFragmentConfirmationReceived();
929 : }
930 :
931 0 : CHIP_ERROR BLEEndPoint::DriveStandAloneAck()
932 : {
933 : // Stop send-ack timer if running.
934 0 : StopSendAckTimer();
935 :
936 : // If stand-alone ack not already pending, allocate new payload buffer here.
937 0 : if (mAckToSend.IsNull())
938 : {
939 0 : mAckToSend = System::PacketBufferHandle::New(kTransferProtocolStandaloneAckHeaderSize);
940 0 : VerifyOrReturnError(!mAckToSend.IsNull(), CHIP_ERROR_NO_MEMORY);
941 : }
942 :
943 : // Attempt to send stand-alone ack.
944 0 : return DriveSending();
945 : }
946 :
947 0 : CHIP_ERROR BLEEndPoint::DoSendStandAloneAck()
948 : {
949 : ChipLogDebugBleEndPoint(Ble, "entered DoSendStandAloneAck; sending stand-alone ack");
950 :
951 : // Encode and transmit stand-alone ack.
952 0 : mBtpEngine.EncodeStandAloneAck(mAckToSend);
953 0 : ReturnErrorOnFailure(SendCharacteristic(mAckToSend.Retain()));
954 :
955 : // Reset local receive window counter.
956 0 : mLocalReceiveWindowSize = mReceiveWindowMaxSize;
957 : ChipLogDebugBleEndPoint(Ble, "reset local rx window on stand-alone ack tx, size = %u", mLocalReceiveWindowSize);
958 :
959 0 : mConnStateFlags.Set(ConnectionStateFlag::kStandAloneAckInFlight);
960 :
961 : // Start ack received timer, if it's not already running.
962 0 : return StartAckReceivedTimer();
963 : }
964 :
965 0 : CHIP_ERROR BLEEndPoint::DriveSending()
966 : {
967 : ChipLogDebugBleEndPoint(Ble, "entered DriveSending");
968 :
969 : // If receiver's window is almost closed and we don't have an ack to send, OR we do have an ack to send but
970 : // receiver's window is completely empty, OR another GATT operation is in flight, awaiting confirmation...
971 0 : if ((mRemoteReceiveWindowSize <= BTP_WINDOW_NO_ACK_SEND_THRESHOLD &&
972 0 : !mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning) && mAckToSend.IsNull()) ||
973 0 : (mRemoteReceiveWindowSize == 0) || (mConnStateFlags.Has(ConnectionStateFlag::kGattOperationInFlight)))
974 : {
975 : #ifdef CHIP_BLE_END_POINT_DEBUG_LOGGING_ENABLED
976 : if (mRemoteReceiveWindowSize <= BTP_WINDOW_NO_ACK_SEND_THRESHOLD &&
977 : !mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning) && mAckToSend.IsNull())
978 : {
979 : ChipLogDebugBleEndPoint(Ble, "NO SEND: receive window almost closed, and no ack to send");
980 : }
981 :
982 : if (mRemoteReceiveWindowSize == 0)
983 : {
984 : ChipLogDebugBleEndPoint(Ble, "NO SEND: remote receive window closed");
985 : }
986 :
987 : if (mConnStateFlags.Has(ConnectionStateFlag::kGattOperationInFlight))
988 : {
989 : ChipLogDebugBleEndPoint(Ble, "NO SEND: Gatt op in flight");
990 : }
991 : #endif
992 :
993 : // Can't send anything.
994 0 : return CHIP_NO_ERROR;
995 : }
996 :
997 : // Otherwise, let's see what we can send.
998 :
999 0 : if (!mAckToSend.IsNull()) // If immediate, stand-alone ack is pending, send it.
1000 : {
1001 0 : ReturnErrorOnFailure(DoSendStandAloneAck());
1002 : }
1003 0 : else if (mBtpEngine.TxState() == BtpEngine::kState_Idle) // Else send next message fragment, if any.
1004 : {
1005 : // Fragmenter's idle, let's see what's in the send queue...
1006 0 : if (!mSendQueue.IsNull())
1007 : {
1008 : // Transmit first fragment of next whole message in send queue.
1009 0 : ReturnErrorOnFailure(SendNextMessage());
1010 : }
1011 : else
1012 : {
1013 : // Nothing to send!
1014 : }
1015 : }
1016 0 : else if (mBtpEngine.TxState() == BtpEngine::kState_InProgress)
1017 : {
1018 : // Send next fragment of message currently held by fragmenter.
1019 0 : ReturnErrorOnFailure(ContinueMessageSend());
1020 : }
1021 0 : else if (mBtpEngine.TxState() == BtpEngine::kState_Complete)
1022 : {
1023 : // Clear fragmenter's pointer to sent message buffer and reset its Tx state.
1024 : // Buffer will be freed at scope exit.
1025 0 : PacketBufferHandle sentBuf = mBtpEngine.TakeTxPacket();
1026 : #if CHIP_ENABLE_CHIPOBLE_TEST
1027 : mBtpEngineTest.DoTxTiming(sentBuf, BTP_TX_DONE);
1028 : #endif // CHIP_ENABLE_CHIPOBLE_TEST
1029 :
1030 0 : if (!mSendQueue.IsNull())
1031 : {
1032 : // Transmit first fragment of next whole message in send queue.
1033 0 : ReturnErrorOnFailure(SendNextMessage());
1034 : }
1035 0 : else if (mState == kState_Closing && !mBtpEngine.ExpectingAck()) // and mSendQueue is NULL, per above...
1036 : {
1037 : // If end point closing, got last ack, and got out-of-order confirmation for last send, finalize close.
1038 0 : FinalizeClose(mState, kBleCloseFlag_SuppressCallback, CHIP_NO_ERROR);
1039 : }
1040 : else
1041 : {
1042 : // Nothing to send!
1043 0 : mBle->mApplicationDelegate->CheckNonConcurrentBleClosing();
1044 : }
1045 0 : }
1046 :
1047 0 : return CHIP_NO_ERROR;
1048 : }
1049 :
1050 0 : CHIP_ERROR BLEEndPoint::HandleCapabilitiesRequestReceived(PacketBufferHandle && data)
1051 : {
1052 : BleTransportCapabilitiesRequestMessage req;
1053 : BleTransportCapabilitiesResponseMessage resp;
1054 : uint16_t mtu;
1055 :
1056 0 : VerifyOrReturnError(!data.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
1057 :
1058 0 : mState = kState_Connecting;
1059 :
1060 : // Decode BTP capabilities request.
1061 0 : ReturnErrorOnFailure(BleTransportCapabilitiesRequestMessage::Decode(data, req));
1062 :
1063 0 : PacketBufferHandle responseBuf = System::PacketBufferHandle::New(kCapabilitiesResponseLength);
1064 0 : VerifyOrReturnError(!responseBuf.IsNull(), CHIP_ERROR_NO_MEMORY);
1065 :
1066 : // Determine BLE connection's negotiated ATT MTU, if possible.
1067 0 : if (req.mMtu > 0) // If MTU was observed and provided by central...
1068 : {
1069 0 : mtu = req.mMtu; // Accept central's observation of the MTU.
1070 : }
1071 : else // Otherwise, retrieve it via the platform delegate...
1072 : {
1073 0 : mtu = mBle->mPlatformDelegate->GetMTU(mConnObj);
1074 : }
1075 :
1076 : // Select fragment size for connection based on ATT MTU.
1077 0 : if (mtu > 0) // If one or both device knows connection's MTU...
1078 : {
1079 0 : resp.mFragmentSize =
1080 0 : chip::min(static_cast<uint16_t>(mtu - 3), BtpEngine::sMaxFragmentSize); // Reserve 3 bytes of MTU for ATT header.
1081 : }
1082 : else // Else, if neither device knows MTU...
1083 : {
1084 0 : ChipLogProgress(Ble, "cannot determine ATT MTU; selecting default fragment size = %u", BtpEngine::sDefaultFragmentSize);
1085 0 : resp.mFragmentSize = BtpEngine::sDefaultFragmentSize;
1086 : }
1087 :
1088 : // Select local and remote max receive window size based on local resources available for both incoming writes AND
1089 : // GATT confirmations.
1090 0 : mRemoteReceiveWindowSize = mLocalReceiveWindowSize = mReceiveWindowMaxSize =
1091 0 : chip::min(req.mWindowSize, static_cast<uint8_t>(BLE_MAX_RECEIVE_WINDOW_SIZE));
1092 0 : resp.mWindowSize = mReceiveWindowMaxSize;
1093 :
1094 0 : ChipLogProgress(Ble, "local and remote recv window sizes = %u", resp.mWindowSize);
1095 :
1096 : // Select BLE transport protocol version from those supported by central, or none if no supported version found.
1097 0 : resp.mSelectedProtocolVersion = BleLayer::GetHighestSupportedProtocolVersion(req);
1098 0 : ChipLogProgress(Ble, "selected BTP version %d", resp.mSelectedProtocolVersion);
1099 :
1100 0 : if (resp.mSelectedProtocolVersion == kBleTransportProtocolVersion_None)
1101 : {
1102 : // If BLE transport protocol versions incompatible, prepare to close connection after subscription has been
1103 : // received and capabilities response has been sent.
1104 0 : ChipLogError(Ble, "incompatible BTP versions; peripheral expected between %d and %d",
1105 : CHIP_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION, CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION);
1106 0 : mState = kState_Aborting;
1107 : }
1108 : else
1109 : {
1110 : // Set Rx and Tx fragment sizes to the same value
1111 0 : mBtpEngine.SetRxFragmentSize(resp.mFragmentSize);
1112 0 : mBtpEngine.SetTxFragmentSize(resp.mFragmentSize);
1113 : }
1114 :
1115 0 : ChipLogProgress(Ble, "using BTP fragment sizes rx %d / tx %d.", mBtpEngine.GetRxFragmentSize(), mBtpEngine.GetTxFragmentSize());
1116 :
1117 0 : ReturnErrorOnFailure(resp.Encode(responseBuf));
1118 :
1119 : // Stash capabilities response payload and wait for subscription from central.
1120 0 : QueueTx(std::move(responseBuf), kType_Data);
1121 :
1122 : // Start receive timer. Canceled when end point freed or connection established.
1123 0 : return StartReceiveConnectionTimer();
1124 0 : }
1125 :
1126 0 : CHIP_ERROR BLEEndPoint::HandleCapabilitiesResponseReceived(PacketBufferHandle && data)
1127 : {
1128 : BleTransportCapabilitiesResponseMessage resp;
1129 :
1130 0 : VerifyOrReturnError(!data.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
1131 :
1132 : // Decode BTP capabilities response.
1133 0 : ReturnErrorOnFailure(BleTransportCapabilitiesResponseMessage::Decode(data, resp));
1134 :
1135 0 : VerifyOrReturnError(resp.mFragmentSize > 0, BLE_ERROR_INVALID_FRAGMENT_SIZE);
1136 :
1137 0 : ChipLogProgress(Ble, "peripheral chose BTP version %d; central expected between %d and %d", resp.mSelectedProtocolVersion,
1138 : CHIP_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION, CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION);
1139 :
1140 0 : if ((resp.mSelectedProtocolVersion < CHIP_BLE_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION) ||
1141 0 : (resp.mSelectedProtocolVersion > CHIP_BLE_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION))
1142 : {
1143 0 : return BLE_ERROR_INCOMPATIBLE_PROTOCOL_VERSIONS;
1144 : }
1145 :
1146 : // Set fragment size as minimum of (reported ATT MTU, BTP characteristic size)
1147 0 : resp.mFragmentSize = chip::min(resp.mFragmentSize, BtpEngine::sMaxFragmentSize);
1148 :
1149 0 : mBtpEngine.SetRxFragmentSize(resp.mFragmentSize);
1150 0 : mBtpEngine.SetTxFragmentSize(resp.mFragmentSize);
1151 :
1152 0 : ChipLogProgress(Ble, "using BTP fragment sizes rx %d / tx %d.", mBtpEngine.GetRxFragmentSize(), mBtpEngine.GetTxFragmentSize());
1153 :
1154 : // Select local and remote max receive window size based on local resources available for both incoming indications
1155 : // AND GATT confirmations.
1156 0 : mRemoteReceiveWindowSize = mLocalReceiveWindowSize = mReceiveWindowMaxSize = resp.mWindowSize;
1157 :
1158 0 : ChipLogProgress(Ble, "local and remote recv window size = %u", resp.mWindowSize);
1159 :
1160 : // Shrink local receive window counter by 1, since connect handshake indication requires acknowledgement.
1161 0 : mLocalReceiveWindowSize = static_cast<SequenceNumber_t>(mLocalReceiveWindowSize - 1);
1162 : ChipLogDebugBleEndPoint(Ble, "decremented local rx window, new size = %u", mLocalReceiveWindowSize);
1163 :
1164 : // Send ack for connection handshake indication when timer expires. Sequence numbers always start at 0,
1165 : // and the reassembler's "last received seq num" is initialized to 0 and updated when new fragments are
1166 : // received from the peripheral, so we don't need to explicitly mark the ack num to send here.
1167 0 : ReturnErrorOnFailure(StartSendAckTimer());
1168 :
1169 : // We've sent a capabilities request write and received a compatible response, so the connect
1170 : // operation has completed successfully.
1171 0 : return HandleConnectComplete();
1172 : }
1173 :
1174 : // Returns number of open slots in remote receive window given the input values.
1175 0 : SequenceNumber_t BLEEndPoint::AdjustRemoteReceiveWindow(SequenceNumber_t lastReceivedAck, SequenceNumber_t maxRemoteWindowSize,
1176 : SequenceNumber_t newestUnackedSentSeqNum)
1177 : {
1178 : // Assumption: SequenceNumber_t is uint8_t.
1179 : // Assumption: Maximum possible sequence number value is UINT8_MAX.
1180 : // Assumption: Sequence numbers incremented past maximum value wrap to 0.
1181 : // Assumption: newest unacked sent sequence number never exceeds current (and by extension, new and un-wrapped)
1182 : // window boundary, so it never wraps relative to last received ack, if new window boundary would not
1183 : // also wrap.
1184 :
1185 : // Define new window boundary (inclusive) as uint16_t, so its value can temporarily exceed UINT8_MAX.
1186 0 : uint16_t newRemoteWindowBoundary = static_cast<uint16_t>(lastReceivedAck + maxRemoteWindowSize);
1187 :
1188 0 : if (newRemoteWindowBoundary > UINT8_MAX && newestUnackedSentSeqNum < lastReceivedAck)
1189 : {
1190 : // New window boundary WOULD wrap, and latest unacked seq num already HAS wrapped, so add offset to difference.
1191 0 : return static_cast<uint8_t>(newRemoteWindowBoundary - (newestUnackedSentSeqNum + UINT8_MAX));
1192 : }
1193 :
1194 : // Neither values would or have wrapped, OR new boundary WOULD wrap but latest unacked seq num does not, so no
1195 : // offset required.
1196 0 : return static_cast<uint8_t>(newRemoteWindowBoundary - newestUnackedSentSeqNum);
1197 : }
1198 :
1199 0 : CHIP_ERROR BLEEndPoint::Receive(PacketBufferHandle && data)
1200 : {
1201 : ChipLogDebugBleEndPoint(Ble, "+++++++++++++++++++++ entered receive");
1202 0 : CHIP_ERROR err = CHIP_NO_ERROR;
1203 0 : SequenceNumber_t receivedAck = 0;
1204 0 : uint8_t closeFlags = kBleCloseFlag_AbortTransmission;
1205 0 : bool didReceiveAck = false;
1206 :
1207 : #if CHIP_ENABLE_CHIPOBLE_TEST
1208 : if (mBtpEngine.IsCommandPacket(data))
1209 : {
1210 : ChipLogDebugBleEndPoint(Ble, "%s: Received Control frame: Flags %x", __FUNCTION__, *(data->Start()));
1211 : }
1212 : else
1213 : #endif
1214 : { // This is a special handling on the first CHIPoBLE data packet, the CapabilitiesRequest.
1215 : // Suppress error logging if peer's send overlaps with our unsubscribe on final close.
1216 0 : if (IsUnsubscribePending())
1217 : {
1218 : ChipLogDebugBleEndPoint(Ble, "characteristic rx'd while unsubscribe in flight");
1219 0 : ExitNow();
1220 : }
1221 :
1222 : // If we're receiving the first inbound packet of a BLE transport connection handshake...
1223 0 : if (!mConnStateFlags.Has(ConnectionStateFlag::kCapabilitiesMsgReceived))
1224 : {
1225 0 : if (mRole == kBleRole_Central) // If we're a central receiving a capabilities response indication...
1226 : {
1227 : // Ensure end point's in the right state before continuing.
1228 0 : VerifyOrExit(mState == kState_Connecting, err = CHIP_ERROR_INCORRECT_STATE);
1229 0 : mConnStateFlags.Set(ConnectionStateFlag::kCapabilitiesMsgReceived);
1230 :
1231 0 : err = HandleCapabilitiesResponseReceived(std::move(data));
1232 0 : SuccessOrExit(err);
1233 : }
1234 : else // Or, a peripheral receiving a capabilities request write...
1235 : {
1236 : // Ensure end point's in the right state before continuing.
1237 0 : VerifyOrExit(mState == kState_Ready, err = CHIP_ERROR_INCORRECT_STATE);
1238 0 : mConnStateFlags.Set(ConnectionStateFlag::kCapabilitiesMsgReceived);
1239 :
1240 0 : err = HandleCapabilitiesRequestReceived(std::move(data));
1241 :
1242 0 : if (err != CHIP_NO_ERROR)
1243 : {
1244 : // If an error occurred decoding and handling the capabilities request, release the BLE connection.
1245 : // Central's connect attempt will time out if peripheral's application decides to keep the BLE
1246 : // connection open, or fail immediately if the application closes the connection.
1247 0 : closeFlags = closeFlags | kBleCloseFlag_SuppressCallback;
1248 0 : ExitNow();
1249 : }
1250 : }
1251 :
1252 : // If received data was handshake packet, don't feed it to message reassembler.
1253 0 : ExitNow();
1254 : }
1255 : } // End handling the CapabilitiesRequest
1256 :
1257 : ChipLogDebugBleEndPoint(Ble, "prepared to rx post-handshake btp packet");
1258 :
1259 : // We've received a post-handshake BTP packet.
1260 : // Ensure end point's in the right state before continuing.
1261 0 : if (!IsConnected(mState))
1262 : {
1263 0 : ChipLogError(Ble, "ep rx'd packet in bad state");
1264 0 : err = CHIP_ERROR_INCORRECT_STATE;
1265 :
1266 0 : ExitNow();
1267 : }
1268 :
1269 : ChipLogDebugBleEndPoint(Ble, "BTP about to rx characteristic, state before:");
1270 0 : mBtpEngine.LogStateDebug();
1271 :
1272 : // Pass received packet into BTP protocol engine.
1273 0 : err = mBtpEngine.HandleCharacteristicReceived(std::move(data), receivedAck, didReceiveAck);
1274 :
1275 : ChipLogDebugBleEndPoint(Ble, "BTP rx'd characteristic, state after:");
1276 0 : mBtpEngine.LogStateDebug();
1277 :
1278 0 : SuccessOrExit(err);
1279 :
1280 : // Protocol engine accepted the fragment, so shrink local receive window counter by 1.
1281 0 : mLocalReceiveWindowSize = static_cast<SequenceNumber_t>(mLocalReceiveWindowSize - 1);
1282 : ChipLogDebugBleEndPoint(Ble, "decremented local rx window, new size = %u", mLocalReceiveWindowSize);
1283 :
1284 : // Respond to received ack, if any.
1285 0 : if (didReceiveAck)
1286 : {
1287 : ChipLogDebugBleEndPoint(Ble, "got btp ack = %u", receivedAck);
1288 :
1289 : // If ack was rx'd for neweset unacked sent fragment, stop ack received timer.
1290 0 : if (!mBtpEngine.ExpectingAck())
1291 : {
1292 : ChipLogDebugBleEndPoint(Ble, "got ack for last outstanding fragment");
1293 0 : StopAckReceivedTimer();
1294 :
1295 0 : if (mState == kState_Closing && mSendQueue.IsNull() && mBtpEngine.TxState() == BtpEngine::kState_Idle)
1296 : {
1297 : // If end point closing, got confirmation for last send, and waiting for last ack, finalize close.
1298 0 : FinalizeClose(mState, kBleCloseFlag_SuppressCallback, CHIP_NO_ERROR);
1299 0 : ExitNow();
1300 : }
1301 : }
1302 : else // Else there are still sent fragments for which acks are expected, so restart ack received timer.
1303 : {
1304 : ChipLogDebugBleEndPoint(Ble, "still expecting ack(s), restarting timer...");
1305 0 : err = RestartAckReceivedTimer();
1306 0 : SuccessOrExit(err);
1307 : }
1308 :
1309 : ChipLogDebugBleEndPoint(Ble, "about to adjust remote rx window; got ack num = %u, newest unacked sent seq num = %u, \
1310 : old window size = %u, max window size = %u",
1311 : receivedAck, mBtpEngine.GetNewestUnackedSentSequenceNumber(), mRemoteReceiveWindowSize,
1312 : mReceiveWindowMaxSize);
1313 :
1314 : // Open remote device's receive window according to sequence number it just acknowledged.
1315 0 : mRemoteReceiveWindowSize =
1316 0 : AdjustRemoteReceiveWindow(receivedAck, mReceiveWindowMaxSize, mBtpEngine.GetNewestUnackedSentSequenceNumber());
1317 :
1318 : ChipLogDebugBleEndPoint(Ble, "adjusted remote rx window, new size = %u", mRemoteReceiveWindowSize);
1319 :
1320 : // Restart message transmission if it was previously paused due to window exhaustion.
1321 0 : err = DriveSending();
1322 0 : SuccessOrExit(err);
1323 : }
1324 :
1325 : // The previous DriveSending() might have generated a piggyback acknowledgement if there was
1326 : // previously un-acked data. Otherwise, prepare to send acknowledgement for newly received fragment.
1327 : //
1328 : // If local receive window is below immediate ack threshold, AND there is no previous stand-alone ack in
1329 : // flight, AND there is no pending outbound message fragment on which the ack can and will be piggybacked,
1330 : // send immediate stand-alone ack to reopen window for sender.
1331 : //
1332 : // The "GATT operation in flight" check below covers "pending outbound message fragment" by extension, as when
1333 : // a message has been passed to the end point via Send(), its next outbound fragment must either be in flight
1334 : // itself, or awaiting the completion of another in-flight GATT operation.
1335 : //
1336 : // If any GATT operation is in flight that is NOT a stand-alone ack, the window size will be checked against
1337 : // this threshold again when the GATT operation is confirmed.
1338 0 : if (mBtpEngine.HasUnackedData())
1339 : {
1340 0 : if (mLocalReceiveWindowSize <= BLE_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD &&
1341 0 : !mConnStateFlags.Has(ConnectionStateFlag::kGattOperationInFlight))
1342 : {
1343 : ChipLogDebugBleEndPoint(Ble, "sending immediate ack");
1344 0 : err = DriveStandAloneAck();
1345 0 : SuccessOrExit(err);
1346 : }
1347 : else
1348 : {
1349 : ChipLogDebugBleEndPoint(Ble, "starting send-ack timer");
1350 :
1351 : // Send ack when timer expires.
1352 0 : err = StartSendAckTimer();
1353 0 : SuccessOrExit(err);
1354 : }
1355 : }
1356 :
1357 : // If we've reassembled a whole message...
1358 0 : if (mBtpEngine.RxState() == BtpEngine::kState_Complete)
1359 : {
1360 : // Take ownership of message buffer
1361 0 : System::PacketBufferHandle full_packet = mBtpEngine.TakeRxPacket();
1362 :
1363 : ChipLogDebugBleEndPoint(Ble, "reassembled whole msg, len = %d", full_packet->DataLength());
1364 :
1365 : #if CHIP_ENABLE_CHIPOBLE_TEST
1366 : // If we have a control message received callback, and end point is not closing...
1367 : if (mBtpEngine.RxPacketType() == kType_Control && OnCommandReceived && mState != kState_Closing)
1368 : {
1369 : ChipLogDebugBleEndPoint(Ble, "%s: calling OnCommandReceived, seq# %u, len = %u, type %u", __FUNCTION__, receivedAck,
1370 : full_packet->DataLength(), mBtpEngine.RxPacketType());
1371 : // Pass received control message up the stack.
1372 : mBtpEngine.SetRxPacketSeq(receivedAck);
1373 : OnCommandReceived(this, std::move(full_packet));
1374 : }
1375 : else
1376 : #endif
1377 : // If we have a message received callback, and end point is not closing...
1378 0 : if (mBleTransport != nullptr && mState != kState_Closing)
1379 : {
1380 : // Pass received message up the stack.
1381 0 : mBleTransport->OnEndPointMessageReceived(this, std::move(full_packet));
1382 : }
1383 0 : }
1384 :
1385 0 : exit:
1386 0 : if (err != CHIP_NO_ERROR)
1387 : {
1388 0 : DoClose(closeFlags, err);
1389 : }
1390 :
1391 0 : return err;
1392 : }
1393 :
1394 0 : bool BLEEndPoint::SendWrite(PacketBufferHandle && buf)
1395 : {
1396 0 : mConnStateFlags.Set(ConnectionStateFlag::kGattOperationInFlight);
1397 :
1398 0 : return mBle->mPlatformDelegate->SendWriteRequest(mConnObj, &CHIP_BLE_SVC_ID, &mBle->CHIP_BLE_CHAR_1_ID, std::move(buf));
1399 : }
1400 :
1401 0 : bool BLEEndPoint::SendIndication(PacketBufferHandle && buf)
1402 : {
1403 0 : mConnStateFlags.Set(ConnectionStateFlag::kGattOperationInFlight);
1404 :
1405 0 : return mBle->mPlatformDelegate->SendIndication(mConnObj, &CHIP_BLE_SVC_ID, &mBle->CHIP_BLE_CHAR_2_ID, std::move(buf));
1406 : }
1407 :
1408 0 : CHIP_ERROR BLEEndPoint::StartConnectTimer()
1409 : {
1410 : const CHIP_ERROR timerErr =
1411 0 : mBle->mSystemLayer->StartTimer(System::Clock::Milliseconds32(BTP_CONN_RSP_TIMEOUT_MS), HandleConnectTimeout, this);
1412 0 : ReturnErrorOnFailure(timerErr);
1413 0 : mTimerStateFlags.Set(TimerStateFlag::kConnectTimerRunning);
1414 :
1415 0 : return CHIP_NO_ERROR;
1416 : }
1417 :
1418 0 : CHIP_ERROR BLEEndPoint::StartReceiveConnectionTimer()
1419 : {
1420 0 : const CHIP_ERROR timerErr = mBle->mSystemLayer->StartTimer(System::Clock::Milliseconds32(BTP_CONN_RSP_TIMEOUT_MS),
1421 : HandleReceiveConnectionTimeout, this);
1422 0 : ReturnErrorOnFailure(timerErr);
1423 0 : mTimerStateFlags.Set(TimerStateFlag::kReceiveConnectionTimerRunning);
1424 :
1425 0 : return CHIP_NO_ERROR;
1426 : }
1427 :
1428 0 : CHIP_ERROR BLEEndPoint::StartAckReceivedTimer()
1429 : {
1430 0 : if (!mTimerStateFlags.Has(TimerStateFlag::kAckReceivedTimerRunning))
1431 : {
1432 : const CHIP_ERROR timerErr =
1433 0 : mBle->mSystemLayer->StartTimer(System::Clock::Milliseconds32(BTP_ACK_TIMEOUT_MS), HandleAckReceivedTimeout, this);
1434 0 : ReturnErrorOnFailure(timerErr);
1435 :
1436 0 : mTimerStateFlags.Set(TimerStateFlag::kAckReceivedTimerRunning);
1437 : }
1438 :
1439 0 : return CHIP_NO_ERROR;
1440 : }
1441 :
1442 0 : CHIP_ERROR BLEEndPoint::RestartAckReceivedTimer()
1443 : {
1444 0 : VerifyOrReturnError(mTimerStateFlags.Has(TimerStateFlag::kAckReceivedTimerRunning), CHIP_ERROR_INCORRECT_STATE);
1445 :
1446 0 : StopAckReceivedTimer();
1447 :
1448 0 : return StartAckReceivedTimer();
1449 : }
1450 :
1451 0 : CHIP_ERROR BLEEndPoint::StartSendAckTimer()
1452 : {
1453 : ChipLogDebugBleEndPoint(Ble, "entered StartSendAckTimer");
1454 :
1455 0 : if (!mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning))
1456 : {
1457 : ChipLogDebugBleEndPoint(Ble, "starting new SendAckTimer");
1458 : const CHIP_ERROR timerErr =
1459 0 : mBle->mSystemLayer->StartTimer(System::Clock::Milliseconds32(BTP_ACK_SEND_TIMEOUT_MS), HandleSendAckTimeout, this);
1460 0 : ReturnErrorOnFailure(timerErr);
1461 :
1462 0 : mTimerStateFlags.Set(TimerStateFlag::kSendAckTimerRunning);
1463 : }
1464 :
1465 0 : return CHIP_NO_ERROR;
1466 : }
1467 :
1468 0 : CHIP_ERROR BLEEndPoint::StartUnsubscribeTimer()
1469 : {
1470 : const CHIP_ERROR timerErr =
1471 0 : mBle->mSystemLayer->StartTimer(System::Clock::Milliseconds32(BLE_UNSUBSCRIBE_TIMEOUT_MS), HandleUnsubscribeTimeout, this);
1472 0 : ReturnErrorOnFailure(timerErr);
1473 0 : mTimerStateFlags.Set(TimerStateFlag::kUnsubscribeTimerRunning);
1474 :
1475 0 : return CHIP_NO_ERROR;
1476 : }
1477 :
1478 0 : void BLEEndPoint::StopConnectTimer()
1479 : {
1480 : // Cancel any existing connect timer.
1481 0 : mBle->mSystemLayer->CancelTimer(HandleConnectTimeout, this);
1482 0 : mTimerStateFlags.Clear(TimerStateFlag::kConnectTimerRunning);
1483 0 : }
1484 :
1485 0 : void BLEEndPoint::StopReceiveConnectionTimer()
1486 : {
1487 : // Cancel any existing receive connection timer.
1488 0 : mBle->mSystemLayer->CancelTimer(HandleReceiveConnectionTimeout, this);
1489 0 : mTimerStateFlags.Clear(TimerStateFlag::kReceiveConnectionTimerRunning);
1490 0 : }
1491 :
1492 0 : void BLEEndPoint::StopAckReceivedTimer()
1493 : {
1494 : // Cancel any existing ack-received timer.
1495 0 : mBle->mSystemLayer->CancelTimer(HandleAckReceivedTimeout, this);
1496 0 : mTimerStateFlags.Clear(TimerStateFlag::kAckReceivedTimerRunning);
1497 0 : }
1498 :
1499 0 : void BLEEndPoint::StopSendAckTimer()
1500 : {
1501 : // Cancel any existing send-ack timer.
1502 0 : mBle->mSystemLayer->CancelTimer(HandleSendAckTimeout, this);
1503 0 : mTimerStateFlags.Clear(TimerStateFlag::kSendAckTimerRunning);
1504 0 : }
1505 :
1506 0 : void BLEEndPoint::StopUnsubscribeTimer()
1507 : {
1508 : // Cancel any existing unsubscribe timer.
1509 0 : mBle->mSystemLayer->CancelTimer(HandleUnsubscribeTimeout, this);
1510 0 : mTimerStateFlags.Clear(TimerStateFlag::kUnsubscribeTimerRunning);
1511 0 : }
1512 :
1513 0 : void BLEEndPoint::HandleConnectTimeout(chip::System::Layer * systemLayer, void * appState)
1514 : {
1515 0 : BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1516 :
1517 : // Check for event-based timer race condition.
1518 0 : if (ep->mTimerStateFlags.Has(TimerStateFlag::kConnectTimerRunning))
1519 : {
1520 0 : ChipLogError(Ble, "connect handshake timed out, closing ep %p", ep);
1521 0 : ep->mTimerStateFlags.Clear(TimerStateFlag::kConnectTimerRunning);
1522 0 : ep->DoClose(kBleCloseFlag_AbortTransmission, BLE_ERROR_CONNECT_TIMED_OUT);
1523 : }
1524 0 : }
1525 :
1526 0 : void BLEEndPoint::HandleReceiveConnectionTimeout(chip::System::Layer * systemLayer, void * appState)
1527 : {
1528 0 : BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1529 :
1530 : // Check for event-based timer race condition.
1531 0 : if (ep->mTimerStateFlags.Has(TimerStateFlag::kReceiveConnectionTimerRunning))
1532 : {
1533 0 : ChipLogError(Ble, "receive handshake timed out, closing ep %p", ep);
1534 0 : ep->mTimerStateFlags.Clear(TimerStateFlag::kReceiveConnectionTimerRunning);
1535 0 : ep->DoClose(kBleCloseFlag_SuppressCallback | kBleCloseFlag_AbortTransmission, BLE_ERROR_RECEIVE_TIMED_OUT);
1536 : }
1537 0 : }
1538 :
1539 0 : void BLEEndPoint::HandleAckReceivedTimeout(chip::System::Layer * systemLayer, void * appState)
1540 : {
1541 0 : BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1542 :
1543 : // Check for event-based timer race condition.
1544 0 : if (ep->mTimerStateFlags.Has(TimerStateFlag::kAckReceivedTimerRunning))
1545 : {
1546 0 : ChipLogError(Ble, "ack recv timeout, closing ep %p", ep);
1547 0 : ep->mBtpEngine.LogStateDebug();
1548 0 : ep->mTimerStateFlags.Clear(TimerStateFlag::kAckReceivedTimerRunning);
1549 0 : ep->DoClose(kBleCloseFlag_AbortTransmission, BLE_ERROR_FRAGMENT_ACK_TIMED_OUT);
1550 : }
1551 0 : }
1552 :
1553 0 : void BLEEndPoint::HandleSendAckTimeout(chip::System::Layer * systemLayer, void * appState)
1554 : {
1555 0 : BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1556 :
1557 : // Check for event-based timer race condition.
1558 0 : if (ep->mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning))
1559 : {
1560 0 : ep->mTimerStateFlags.Clear(TimerStateFlag::kSendAckTimerRunning);
1561 :
1562 : // If previous stand-alone ack isn't still in flight...
1563 0 : if (!ep->mConnStateFlags.Has(ConnectionStateFlag::kStandAloneAckInFlight))
1564 : {
1565 0 : CHIP_ERROR sendErr = ep->DriveStandAloneAck();
1566 :
1567 0 : if (sendErr != CHIP_NO_ERROR)
1568 : {
1569 0 : ep->DoClose(kBleCloseFlag_AbortTransmission, sendErr);
1570 : }
1571 : }
1572 : }
1573 0 : }
1574 :
1575 0 : void BLEEndPoint::HandleUnsubscribeTimeout(chip::System::Layer * systemLayer, void * appState)
1576 : {
1577 0 : BLEEndPoint * ep = static_cast<BLEEndPoint *>(appState);
1578 :
1579 : // Check for event-based timer race condition.
1580 0 : if (ep->mTimerStateFlags.Has(TimerStateFlag::kUnsubscribeTimerRunning))
1581 : {
1582 0 : ChipLogError(Ble, "unsubscribe timed out, ble ep %p", ep);
1583 0 : ep->mTimerStateFlags.Clear(TimerStateFlag::kUnsubscribeTimerRunning);
1584 0 : ep->HandleUnsubscribeComplete();
1585 : }
1586 0 : }
1587 :
1588 : } /* namespace Ble */
1589 : } /* namespace chip */
1590 :
1591 : #endif /* CONFIG_NETWORK_LAYER_BLE */
|