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