Coverage Report

Created: 2026-01-24 06:26

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