Matter SDK Coverage Report
Current view: top level - ble - BLEEndPoint.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 49.2 % 537 264
Test Date: 2025-01-17 19:00:11 Functions: 62.3 % 53 33

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

Generated by: LCOV version 2.0-1