WXK
2025-01-21 8f1a91a8ec98e430cfe4357bda099d495917198e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
 
#ifndef H_BLE_LL_CONN_
#define H_BLE_LL_CONN_
 
#include "os/os.h"
#include "nimble/ble.h"
#include "nimble/hci_common.h"
#include "nimble/nimble_npl.h"
#include "controller/ble_ll.h"
#include "controller/ble_ll_sched.h"
#include "controller/ble_ll_ctrl.h"
#include "controller/ble_phy.h"
 
#ifdef __cplusplus
extern "C" {
#endif
 
/* Roles */
#define BLE_LL_CONN_ROLE_NONE           (0)
 
#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
#define BLE_LL_CONN_ROLE_CENTRAL        (1)
#endif
#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL)
#define BLE_LL_CONN_ROLE_PERIPHERAL     (2)
#endif
 
/* Connection states */
#define BLE_LL_CONN_STATE_IDLE          (0)
#define BLE_LL_CONN_STATE_CREATED       (1)
#define BLE_LL_CONN_STATE_ESTABLISHED   (2)
 
/* Definition for RSSI when the RSSI is unknown */
#define BLE_LL_CONN_UNKNOWN_RSSI        (127)
 
#define BLE_LL_CONN_HANDLE_ISO_OFFSET   (0x0100)
 
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/*
 * Encryption states for a connection
 *
 * NOTE: the states are ordered so that we can check to see if the state
 * is greater than ENCRYPTED. If so, it means that the start or pause
 * encryption procedure is running and we should not send data pdu's.
 */
enum conn_enc_state {
    CONN_ENC_S_UNENCRYPTED = 1,
    CONN_ENC_S_ENCRYPTED,
    CONN_ENC_S_ENC_RSP_TO_BE_SENT,
    CONN_ENC_S_ENC_RSP_WAIT,
    CONN_ENC_S_PAUSE_ENC_RSP_WAIT,
    CONN_ENC_S_PAUSED,
    CONN_ENC_S_START_ENC_REQ_WAIT,
    CONN_ENC_S_START_ENC_RSP_WAIT,
    CONN_ENC_S_LTK_REQ_WAIT,
    CONN_ENC_S_LTK_NEG_REPLY
};
 
/*
 * Note that the LTK is the key, the SDK is the plain text, and the
 * session key is the cipher text portion of the encryption block.
 *
 * NOTE: we have intentionally violated the specification by making the
 * transmit and receive packet counters 32-bits as opposed to 39 (as per the
 * specification). We do this to save code space, ram and calculation time. The
 * only drawback is that any encrypted connection that sends more than 2^32
 * packets will suffer a MIC failure and thus be disconnected.
 */
struct ble_ll_conn_enc_data
{
    uint8_t enc_state;
    uint8_t tx_encrypted;
    uint16_t enc_div;
    uint32_t tx_pkt_cntr;
    uint32_t rx_pkt_cntr;
    uint64_t host_rand_num;
    uint8_t iv[8];
    struct ble_encryption_block enc_block;
};
#endif
 
/* Connection state machine flags. */
union ble_ll_conn_sm_flags {
    struct {
        uint32_t pkt_rxd:1;
        uint32_t terminate_ind_txd:1;
        uint32_t terminate_ind_rxd:1;
        uint32_t terminate_ind_rxd_acked:1;
        uint32_t allow_periph_latency:1;
        uint32_t periph_set_last_anchor:1;
        uint32_t awaiting_host_reply:1;
        uint32_t terminate_started:1;
        uint32_t conn_update_sched:1;
        uint32_t host_expects_upd_event:1;
        uint32_t version_ind_sent:1;
        uint32_t rxd_version_ind:1;
        uint32_t chanmap_update_scheduled:1;
        uint32_t conn_empty_pdu_txd:1;
        uint32_t last_txd_md:1;
        uint32_t conn_req_txd:1;
        uint32_t send_ltk_req:1;
        uint32_t encrypted:1;
        uint32_t encrypt_chg_sent:1;
        uint32_t le_ping_supp:1;
        uint32_t csa2_supp:1;
        uint32_t host_phy_update: 1;
        uint32_t phy_update_sched: 1;
        uint32_t ctrlr_phy_update: 1;
        uint32_t phy_update_event: 1;
        uint32_t peer_phy_update: 1; /* XXX:combine with ctrlr udpate bit? */
        uint32_t aux_conn_req: 1;
        uint32_t rxd_features:1;
        uint32_t pending_hci_rd_features:1;
        uint32_t pending_initiate_dle:1;
        uint32_t subrate_trans:1;
        uint32_t subrate_ind_txd:1;
        uint32_t subrate_host_req:1;
    } cfbit;
    uint32_t conn_flags;
} __attribute__((packed));
 
/**
 * Structure used for PHY data inside a connection.
 *
 * NOTE: the new phy's are the phys we will change to when a phy update
 * procedure is ongoing and the event counter hits the instant.
 *
 * tx_phy_mode: chip specific phy mode for tx
 * rx_phy_mode: chip specific phy mode for rx
 * cur_tx_phy: value denoting current tx_phy (not a bitmask!)
 * cur_rx_phy: value denoting current rx phy (not a bitmask!)
 * new_tx_phy: value denoting new tx_phy (not a bitmask!)
 * new_rx_phy: value denoting new rx phy (not a bitmask!)
 * req_pref_tx_phy: tx phy sent in a phy request (may be different than host)
 * req_pref_rx_phy: rx phy sent in a phy request (may be different than host)
 * host_pref_tx_phys: bitmask of preferred transmit PHYs sent by host
 * host_pref_rx_phys: bitmask of preferred receive PHYs sent by host
 * phy_options: preferred phy options for coded phy
 */
struct ble_ll_conn_phy_data
{
    uint32_t tx_phy_mode: 2;
    uint32_t rx_phy_mode: 2;
    uint32_t cur_tx_phy: 2;
    uint32_t cur_rx_phy: 2;
    uint32_t new_tx_phy: 2;
    uint32_t new_rx_phy: 2;
    uint32_t pref_mask_tx: 3;
    uint32_t pref_mask_rx: 3;
    uint32_t pref_mask_tx_req: 3;
    uint32_t pref_mask_rx_req: 3;
    uint32_t pref_opts: 2;
}  __attribute__((packed));
 
#define CONN_CUR_TX_PHY_MASK(csm)   (1 << ((csm)->phy_data.cur_tx_phy - 1))
#define CONN_CUR_RX_PHY_MASK(csm)   (1 << ((csm)->phy_data.cur_rx_phy - 1))
 
struct hci_conn_update
{
    uint16_t handle;
    uint16_t conn_itvl_min;
    uint16_t conn_itvl_max;
    uint16_t conn_latency;
    uint16_t supervision_timeout;
    uint16_t min_ce_len;
    uint16_t max_ce_len;
};
 
struct ble_ll_conn_subrate_params {
    uint16_t subrate_factor;
    uint16_t subrate_base_event;
    uint16_t periph_latency;
    uint16_t cont_num;
    uint16_t supervision_tmo;
};
 
struct ble_ll_conn_subrate_req_params {
    uint16_t subrate_min;
    uint16_t subrate_max;
    uint16_t max_latency;
    uint16_t cont_num;
    uint16_t supervision_tmo;
};
 
/* Connection state machine */
struct ble_ll_conn_sm
{
    /* Connection state machine flags */
    union ble_ll_conn_sm_flags csmflags;
 
    /* Current connection handle, state and role */
    uint16_t conn_handle;
    uint8_t conn_state;
    uint8_t conn_role;          /* Can possibly be 1 bit */
 
    /* RSSI */
    int8_t conn_rssi;
 
    /* Connection data length management */
    uint8_t max_tx_octets;
    uint8_t max_rx_octets;
    uint8_t rem_max_tx_octets;
    uint8_t rem_max_rx_octets;
    uint8_t eff_max_tx_octets;
    uint8_t eff_max_rx_octets;
    uint16_t max_tx_time;
    uint16_t max_rx_time;
    uint16_t rem_max_tx_time;
    uint16_t rem_max_rx_time;
    uint16_t eff_max_tx_time;
    uint16_t eff_max_rx_time;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
    uint16_t host_req_max_tx_time;
#endif
 
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
    struct ble_ll_conn_phy_data phy_data;
    uint16_t phy_instant;
    uint8_t phy_tx_transition;
#endif
 
    /* Used to calculate data channel index for connection */
    uint8_t chanmap[BLE_LL_CHAN_MAP_LEN];
    uint8_t req_chanmap[BLE_LL_CHAN_MAP_LEN];
    uint16_t chanmap_instant;
    uint16_t channel_id; /* TODO could be union with hop and last chan used */
    uint8_t hop_inc;
    uint8_t data_chan_index;
    uint8_t last_unmapped_chan;
    uint8_t num_used_chans;
 
    /* Ack/Flow Control */
    uint8_t tx_seqnum;          /* note: can be 1 bit */
    uint8_t next_exp_seqnum;    /* note: can be 1 bit */
    uint8_t cons_rxd_bad_crc;   /* note: can be 1 bit */
    uint8_t last_rxd_sn;        /* note: cant be 1 bit given current code */
    uint8_t last_rxd_hdr_byte;  /* note: possibly can make 1 bit since we
                                   only use the MD bit now */
 
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
    uint16_t cth_flow_pending;
#endif
 
    /* connection event mgmt */
    uint8_t reject_reason;
    uint8_t host_reply_opcode;
    uint8_t central_sca;
    uint8_t tx_win_size;
    uint8_t cur_ctrl_proc;
    uint8_t disconnect_reason;
    uint8_t rxd_disconnect_reason;
    uint8_t vers_nr;
    uint8_t conn_features;
    uint8_t remote_features[7];
    uint16_t pending_ctrl_procs;
    uint16_t event_cntr;
    uint16_t completed_pkts;
    uint16_t comp_id;
    uint16_t sub_vers_nr;
    uint16_t auth_pyld_tmo;         /* could be ifdef'd. 10 msec units */
 
    uint32_t access_addr;
    uint32_t crcinit;               /* only low 24 bits used */
    /* XXX: do we need ce_end_time? Cant this be sched end time? */
    uint32_t ce_end_time;   /* cputime at which connection event should end */
    uint32_t terminate_timeout;
    uint32_t last_scheduled;
 
    /* Connection timing */
    uint16_t conn_itvl;
    uint16_t supervision_tmo;
    uint16_t min_ce_len;
    uint16_t max_ce_len;
    uint16_t tx_win_off;
    uint32_t anchor_point;
    uint8_t anchor_point_usecs;     /* XXX: can this be uint8_t ?*/
    uint8_t conn_itvl_usecs;
    uint32_t conn_itvl_ticks;
    uint32_t last_anchor_point;     /* Slave only */
    uint32_t periph_cur_tx_win_usecs;
    uint32_t periph_cur_window_widening;
    uint32_t last_rxd_pdu_cputime;  /* Used exclusively for supervision timer */
 
    uint16_t periph_latency;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
    uint16_t acc_subrate_min;
    uint16_t acc_subrate_max;
    uint16_t acc_max_latency;
    uint16_t acc_cont_num;
    uint16_t acc_supervision_tmo;
 
    uint16_t subrate_base_event;
    uint16_t subrate_factor;
    uint16_t cont_num;
    uint16_t last_pdu_event;
 
    union {
        struct ble_ll_conn_subrate_params subrate_trans;
        struct ble_ll_conn_subrate_req_params subrate_req;
    };
#endif
 
    /*
     * Used to mark that identity address was used as InitA
     */
    uint8_t inita_identity_used;
 
    /* address information */
    uint8_t own_addr_type;
    uint8_t peer_addr_type;
    uint8_t peer_addr[BLE_DEV_ADDR_LEN];
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
    uint8_t peer_addr_resolved;
#endif
 
    /*
     * XXX: TODO. Could save memory. Have single event at LL and put these
     * on a singly linked list. Only would need list pointer here.
     */
    /* Connection end event */
    struct ble_npl_event conn_ev_end;
 
    /* Packet transmit queue */
    struct os_mbuf *cur_tx_pdu;
    STAILQ_HEAD(conn_txq_head, os_mbuf_pkthdr) conn_txq;
 
    /* List entry for active/free connection pools */
    union {
        SLIST_ENTRY(ble_ll_conn_sm) act_sle;
        STAILQ_ENTRY(ble_ll_conn_sm) free_stqe;
    };
 
    /* LL control procedure response timer */
    struct ble_npl_callout ctrl_proc_rsp_timer;
 
    /* For scheduling connections */
    struct ble_ll_sched_item conn_sch;
 
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
    struct ble_npl_callout auth_pyld_timer;
#endif
 
    /*
     * XXX: a note on all these structures for control procedures. First off,
     * all of these need to be ifdef'd to save memory. Another thing to
     * consider is this: since most control procedures can only run when no
     * others are running, can I use just one structure (a union)? Should I
     * allocate these from a pool? Not sure what to do. For now, I just use
     * a large chunk of memory per connection.
     */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
    struct ble_ll_conn_enc_data enc_data;
#endif
    /*
     * For connection update procedure. XXX: can make this a pointer and
     * malloc it if we want to save space.
     */
    struct hci_conn_update conn_param_req;
 
    /* For connection update procedure */
    struct ble_ll_conn_upd_req conn_update_req;
 
    /* XXX: for now, just store them all */
    struct ble_ll_conn_params conn_cp;
 
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
    uint8_t  sync_transfer_mode;
    uint16_t sync_transfer_skip;
    uint32_t sync_transfer_sync_timeout;
#endif
 
#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED)
    uint16_t css_slot_idx;
    uint16_t css_slot_idx_pending;
    uint8_t css_period_idx;
#endif
};
 
/* Flags */
#define CONN_F_UPDATE_SCHED(csm)    ((csm)->csmflags.cfbit.conn_update_sched)
#define CONN_F_EMPTY_PDU_TXD(csm)   ((csm)->csmflags.cfbit.conn_empty_pdu_txd)
#define CONN_F_LAST_TXD_MD(csm)     ((csm)->csmflags.cfbit.last_txd_md)
#define CONN_F_CONN_REQ_TXD(csm)    ((csm)->csmflags.cfbit.conn_req_txd)
#define CONN_F_ENCRYPTED(csm)       ((csm)->csmflags.cfbit.encrypted)
#define CONN_F_ENC_CHANGE_SENT(csm) ((csm)->csmflags.cfbit.encrypt_chg_sent)
#define CONN_F_LE_PING_SUPP(csm)    ((csm)->csmflags.cfbit.le_ping_supp)
#define CONN_F_TERMINATE_STARTED(csm) ((csm)->csmflags.cfbit.terminate_started)
#define CONN_F_CSA2_SUPP(csm)       ((csm)->csmflags.cfbit.csa2_supp)
#define CONN_F_HOST_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.host_phy_update)
#define CONN_F_PHY_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.phy_update_sched)
#define CONN_F_CTRLR_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.ctrlr_phy_update)
#define CONN_F_PHY_UPDATE_EVENT(csm) ((csm)->csmflags.cfbit.phy_update_event)
#define CONN_F_PEER_PHY_UPDATE(csm)  ((csm)->csmflags.cfbit.peer_phy_update)
#define CONN_F_AUX_CONN_REQ(csm)  ((csm)->csmflags.cfbit.aux_conn_req)
 
/* Role */
#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
#define CONN_IS_CENTRAL(csm)        (csm->conn_role == BLE_LL_CONN_ROLE_CENTRAL)
#else
#define CONN_IS_CENTRAL(csm)        (false)
#endif
 
#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL)
#define CONN_IS_PERIPHERAL(csm)     (csm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL)
#else
#define CONN_IS_PERIPHERAL(csm)     (false)
#endif
 
static inline int
ble_ll_conn_rem_feature_check(struct ble_ll_conn_sm *connsm, uint64_t feature)
{
    uint8_t byte_idx;
 
    /* 8 lsb are conn features */
    feature >>= 8;
 
    byte_idx = __builtin_ctzll(feature) / 8;
    return connsm->remote_features[byte_idx] & (feature >> (byte_idx * 8));
}
 
 
static inline void
ble_ll_conn_rem_feature_add(struct ble_ll_conn_sm *connsm, uint64_t feature)
{
    uint8_t byte_idx;
 
    /* 8 lsb are conn features */
    feature >>= 8;
 
    byte_idx = __builtin_ctzll(feature) / 8;
    connsm->remote_features[byte_idx] |= (feature >> (byte_idx * 8));
}
 
 
struct ble_ll_conn_sm *ble_ll_conn_find_by_handle(uint16_t handle);
struct ble_ll_conn_sm *ble_ll_conn_find_by_peer_addr(const uint8_t* addr,
                                                     uint8_t addr_type);
 
/* required for unit testing */
uint8_t ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency);
 
/* used to get anchor point for connection event specified */
void ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event,
                            uint32_t *anchor, uint8_t *anchor_usecs);
 
#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)
int ble_ll_conn_move_anchor(struct ble_ll_conn_sm *connsm, uint16_t offset);
#endif
 
struct ble_ll_scan_addr_data;
struct ble_ll_scan_pdu_data;
 
uint8_t ble_ll_conn_tx_connect_ind_pducb(uint8_t *dptr, void *pducb_arg,
                                         uint8_t *hdr_byte);
void ble_ll_conn_prepare_connect_ind(struct ble_ll_conn_sm *connsm,
                                     struct ble_ll_scan_pdu_data *pdu_data,
                                     struct ble_ll_scan_addr_data *addrd,
                                     uint8_t channel);
 
/* Send CONNECT_IND/AUX_CONNECT_REQ */
int ble_ll_conn_send_connect_req(struct os_mbuf *rxpdu,
                                 struct ble_ll_scan_addr_data *addrd,
                                 uint8_t ext);
/* Cancel connection after AUX_CONNECT_REQ was sent */
void ble_ll_conn_send_connect_req_cancel(void);
/* Signal connection created via CONNECT_IND */
void ble_ll_conn_created_on_legacy(struct os_mbuf *rxpdu,
                                   struct ble_ll_scan_addr_data *addrd,
                                   uint8_t *targeta);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
/* Signal connection created via AUX_CONNECT_REQ */
void ble_ll_conn_created_on_aux(struct os_mbuf *rxpdu,
                                struct ble_ll_scan_addr_data *addrd,
                                uint8_t *targeta);
#endif
 
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE)
int ble_ll_conn_subrate_req_hci(struct ble_ll_conn_sm *connsm,
                                struct ble_ll_conn_subrate_req_params *srp);
int ble_ll_conn_subrate_req_llcp(struct ble_ll_conn_sm *connsm,
                                 struct ble_ll_conn_subrate_req_params *srp);
void ble_ll_conn_subrate_set(struct ble_ll_conn_sm *connsm,
                             struct ble_ll_conn_subrate_params *sp);
#endif
 
#ifdef __cplusplus
}
#endif
 
#endif /* H_BLE_LL_CONN_ */