summaryrefslogtreecommitdiff
path: root/system/stack/acl/acl.h
blob: 1e65b242cbe5c52c6f78423c9db59ddd0034a91e (plain)
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
/*
 * Copyright 2020 The Android Open Source Project
 *
 * Licensed 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.
 */

#pragma once

#include <cstdint>
#include <string>
#include <unordered_set>
#include <vector>

#include "stack/acl/peer_packet_types.h"
#include "stack/include/acl_api_types.h"
#include "stack/include/bt_types.h"
#include "stack/include/btm_api_types.h"
#include "stack/include/hcimsgs.h"
#include "types/bt_transport.h"
#include "types/hci_role.h"
#include "types/raw_address.h"

enum btm_acl_encrypt_state_t {
  BTM_ACL_ENCRYPT_STATE_IDLE = 0,
  BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF = 1,
  BTM_ACL_ENCRYPT_STATE_TEMP_FUNC = 2,
  BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON = 3,
};

enum btm_acl_swkey_state_t {
  BTM_ACL_SWKEY_STATE_IDLE = 0,
  BTM_ACL_SWKEY_STATE_MODE_CHANGE = 1,
  BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF = 2,
  BTM_ACL_SWKEY_STATE_SWITCHING = 3,
  BTM_ACL_SWKEY_STATE_ENCRYPTION_ON = 4,
  BTM_ACL_SWKEY_STATE_IN_PROGRESS = 5,
};

enum btm_data_direction {
  HOST_TO_CONTROLLER = 0,
  CONTROLLER_TO_HOST = 1,
};

/* Policy settings status */
typedef enum : uint16_t {
  HCI_DISABLE_ALL_LM_MODES = 0,
  HCI_ENABLE_CENTRAL_PERIPHERAL_SWITCH = (1u << 0),
  HCI_ENABLE_HOLD_MODE = (1u << 1),
  HCI_ENABLE_SNIFF_MODE = (1u << 2),
  HCI_ENABLE_PARK_MODE = (1u << 3),
} tLINK_POLICY_BITMASK;
typedef uint16_t tLINK_POLICY;

constexpr tLINK_POLICY kAllLinkPoliciesEnabled =
    (HCI_ENABLE_CENTRAL_PERIPHERAL_SWITCH | HCI_ENABLE_HOLD_MODE |
     HCI_ENABLE_SNIFF_MODE);

static const char* link_policy_string[] = {
    " role_switch ",
    " hold_mode ",
    " sniff_mode ",
    " park_mode ",
};

inline std::string link_policy_text(tLINK_POLICY policy) {
  std::ostringstream os;
  os << "0x" << loghex(static_cast<uint16_t>(policy)) << " :";
  std::string s = os.str();
  for (uint16_t i = 0; i < 4; i++) {
    if (policy & (0x1 << i)) s += link_policy_string[i];
  }
  return s;
}

// Power mode states.
// Used as both value and bitmask
enum : uint8_t {
  BTM_PM_ST_ACTIVE = HCI_MODE_ACTIVE,      // 0x00
  BTM_PM_ST_HOLD = HCI_MODE_HOLD,          // 0x01
  BTM_PM_ST_SNIFF = HCI_MODE_SNIFF,        // 0x02
  BTM_PM_ST_PARK = HCI_MODE_PARK,          // 0x03
  BTM_PM_ST_UNUSED,                        // 0x04
  BTM_PM_ST_PENDING = BTM_PM_STS_PENDING,  // 0x05
  BTM_PM_ST_INVALID = 0x7F,
  BTM_PM_STORED_MASK = 0x80, /* set this mask if the command is stored */
};
typedef uint8_t tBTM_PM_STATE;

inline std::string power_mode_state_text(tBTM_PM_STATE state) {
  std::string s =
      std::string((state & BTM_PM_STORED_MASK) ? "stored:" : "immediate:");
  switch (state & ~BTM_PM_STORED_MASK) {
    case BTM_PM_ST_ACTIVE:
      return s + std::string("active");
    case BTM_PM_ST_HOLD:
      return s + std::string("hold");
    case BTM_PM_ST_SNIFF:
      return s + std::string("sniff");
    case BTM_PM_ST_PARK:
      return s + std::string("park");
    case BTM_PM_ST_UNUSED:
      return s + std::string("WARN:UNUSED");
    case BTM_PM_ST_PENDING:
      return s + std::string("pending");
    case BTM_PM_ST_INVALID:
      return s + std::string("invalid");
    default:
      return s + std::string("UNKNOWN");
  }
}

namespace bluetooth {
namespace shim {
tBTM_STATUS BTM_SetPowerMode(uint16_t handle, const tBTM_PM_PWR_MD& new_mode);
tBTM_STATUS BTM_SetSsrParams(uint16_t handle, uint16_t max_lat,
                             uint16_t min_rmt_to, uint16_t min_loc_to);
void btm_pm_on_mode_change(tHCI_STATUS status, uint16_t handle,
                           tHCI_MODE hci_mode, uint16_t interval);
void btm_pm_on_sniff_subrating(tHCI_STATUS status, uint16_t handle,
                               uint16_t maximum_transmit_latency,
                               uint16_t maximum_receive_latency,
                               uint16_t minimum_remote_timeout,
                               uint16_t minimum_local_timeout);
}  // namespace shim
}  // namespace bluetooth

typedef struct {
  uint16_t max_xmit_latency;
  uint16_t max_recv_latency;
  uint16_t min_remote_timeout;
  uint16_t min_local_timeout;
} tSSR_PARAMS;

#define BTM_PM_REC_NOT_USED 0
typedef struct {
  tBTM_PM_STATUS_CBACK* cback =
      nullptr;      /* to notify the registered party of mode change event */
  uint8_t mask = 0; /* registered request mask. 0, if this entry is not used */
} tBTM_PM_RCB;

/* Structure returned with Role Switch information (in tBTM_CMPL_CB callback
 * function) in response to BTM_SwitchRoleToCentral call.
 */
typedef struct {
  RawAddress remote_bd_addr; /* Remote BD addr involved with the switch */
  tHCI_STATUS hci_status;    /* HCI status returned with the event */
  tHCI_ROLE role;            /* HCI_ROLE_CENTRAL or HCI_ROLE_PERIPHERAL */
} tBTM_ROLE_SWITCH_CMPL;

struct tBTM_PM_MCB {
  bool chg_ind = false;
  tBTM_PM_PWR_MD req_mode;
  tBTM_PM_PWR_MD set_mode;
  tBTM_PM_STATE state = BTM_PM_ST_ACTIVE;  // 0
  uint16_t interval = 0;
  uint16_t max_lat = 0;
  uint16_t min_loc_to = 0;
  uint16_t min_rmt_to = 0;
  void Init(RawAddress bda, uint16_t handle) {
    bda_ = bda;
    handle_ = handle;
  }
  RawAddress bda_;
  uint16_t handle_;
};

struct tACL_CONN {
  BD_FEATURES peer_le_features;
  bool peer_le_features_valid;
  BD_FEATURES peer_lmp_feature_pages[HCI_EXT_FEATURES_PAGE_MAX + 1];
  bool peer_lmp_feature_valid[HCI_EXT_FEATURES_PAGE_MAX + 1];

  RawAddress active_remote_addr;
  tBLE_ADDR_TYPE active_remote_addr_type;
  RawAddress conn_addr;
  tBLE_ADDR_TYPE conn_addr_type;

  RawAddress remote_addr;
  bool in_use{false};

 public:
  bool InUse() const { return in_use; }
  const RawAddress RemoteAddress() const { return remote_addr; }

  bool link_up_issued;
  tBT_TRANSPORT transport;
  bool is_transport_br_edr() const { return transport == BT_TRANSPORT_BR_EDR; }
  bool is_transport_ble() const { return transport == BT_TRANSPORT_LE; }
  bool is_transport_valid() const {
    return is_transport_ble() || is_transport_br_edr();
  }

  uint16_t flush_timeout_in_ticks;
  uint16_t hci_handle;
  tLINK_POLICY link_policy;

 public:
  uint16_t Handle() const { return hci_handle; }
  uint16_t link_super_tout;
  uint16_t pkt_types_mask;
  uint8_t disconnect_reason;

 private:
  btm_acl_encrypt_state_t encrypt_state_;

 public:
  void set_encryption_off() {
    if (encrypt_state_ != BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF) {
      btsnd_hcic_set_conn_encrypt(hci_handle, false);
      encrypt_state_ = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
    }
  }
  void set_encryption_on() {
    if (encrypt_state_ != BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON) {
      btsnd_hcic_set_conn_encrypt(hci_handle, true);
      encrypt_state_ = BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON;
    }
  }
  void set_encryption_idle() { encrypt_state_ = BTM_ACL_ENCRYPT_STATE_IDLE; }

  void set_encryption_switching() {
    encrypt_state_ = BTM_ACL_ENCRYPT_STATE_TEMP_FUNC;
  }

 public:
  bool is_encrypted = false;
  tHCI_ROLE link_role;
  uint8_t switch_role_failed_attempts;

  tREMOTE_VERSION_INFO remote_version_info;

#define BTM_SEC_RS_NOT_PENDING 0 /* Role Switch not in progress */
#define BTM_SEC_RS_PENDING 1     /* Role Switch in progress */
#define BTM_SEC_DISC_PENDING 2   /* Disconnect is pending */
 private:
  uint8_t rs_disc_pending = BTM_SEC_RS_NOT_PENDING;
  friend struct StackAclBtmAcl;
  friend tBTM_STATUS btm_remove_acl(const RawAddress& bd_addr,
                                    tBT_TRANSPORT transport);
  friend void acl_disconnect_after_role_switch(uint16_t conn_handle,
                                               tHCI_STATUS reason, std::string);
  friend void bluetooth::shim::btm_pm_on_mode_change(tHCI_STATUS status,
                                                     uint16_t handle,
                                                     tHCI_MODE hci_mode,
                                                     uint16_t interval);
  friend void btm_acl_encrypt_change(uint16_t handle, uint8_t status,
                                     uint8_t encr_enable);

 public:
  bool is_disconnect_pending() const {
    return rs_disc_pending == BTM_SEC_DISC_PENDING;
  }
  bool is_role_switch_pending() const {
    return rs_disc_pending == BTM_SEC_RS_PENDING;
  }

 private:
  uint8_t switch_role_state_;

 public:
  void reset_switch_role() { switch_role_state_ = BTM_ACL_SWKEY_STATE_IDLE; }
  void set_switch_role_changing() {
    switch_role_state_ = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
  }
  void set_switch_role_encryption_off() {
    switch_role_state_ = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
  }
  void set_switch_role_encryption_on() {
    switch_role_state_ = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
  }
  void set_switch_role_in_progress() {
    switch_role_state_ = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
  }
  void set_switch_role_switching() {
    switch_role_state_ = BTM_ACL_SWKEY_STATE_SWITCHING;
  }

  bool is_switch_role_idle() const {
    return switch_role_state_ == BTM_ACL_SWKEY_STATE_IDLE;
  }
  bool is_switch_role_encryption_off() const {
    return switch_role_state_ == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
  }
  bool is_switch_role_encryption_on() const {
    return switch_role_state_ == BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
  }
  bool is_switch_role_switching() const {
    return switch_role_state_ == BTM_ACL_SWKEY_STATE_SWITCHING;
  }
  bool is_switch_role_in_progress() const {
    return switch_role_state_ == BTM_ACL_SWKEY_STATE_IN_PROGRESS;
  }
  bool is_switch_role_mode_change() const {
    return switch_role_state_ == BTM_ACL_SWKEY_STATE_MODE_CHANGE;
  }
  bool is_switch_role_switching_or_in_progress() const {
    return is_switch_role_switching() || is_switch_role_in_progress();
  }

  friend void DumpsysL2cap(int fd);

 public:
  uint8_t sca; /* Sleep clock accuracy */

  void Reset();

  struct tPolicy {
    tBTM_PM_MODE Mode() const { return this->mode.mode_; }
    struct {
      bool IsPending() const { return pending_ != BTM_PM_MD_UNKNOWN; }
      tBTM_PM_MODE Pending() const { return pending_; }
      uint16_t Interval() const { return interval_; }

     private:
      tBTM_PM_MODE mode_{BTM_PM_MD_ACTIVE};
      tBTM_PM_MODE pending_{BTM_PM_MD_UNKNOWN};
      uint16_t interval_{0};
      friend tBTM_STATUS bluetooth::shim::BTM_SetPowerMode(
          uint16_t, const tBTM_PM_PWR_MD& new_mode);
      friend void bluetooth::shim::btm_pm_on_mode_change(tHCI_STATUS status,
                                                         uint16_t handle,
                                                         tHCI_MODE hci_mode,
                                                         uint16_t interval);
      friend void tACL_CONN::Reset();
      friend tBTM_PM_MODE tACL_CONN::tPolicy::Mode() const;
    } mode;

    hci_role_t Role() const { return this->role.role_; }
    struct {
      unsigned RoleSwitchFailedCount() const { return role_switch_failed_cnt_; }

     private:
      hci_role_t role_{HCI_ROLE_CENTRAL};
      unsigned role_switch_failed_cnt_{0};
      friend void tACL_CONN::Reset();
      friend hci_role_t tACL_CONN::tPolicy::Role() const;
    } role;

    struct {
      bool IsPending() const { return pending_; }

     private:
      bool pending_{false};
      friend tBTM_STATUS bluetooth::shim::BTM_SetSsrParams(uint16_t handle,
                                                           uint16_t max_lat,
                                                           uint16_t min_rmt_to,
                                                           uint16_t min_loc_to);
      friend void bluetooth::shim::btm_pm_on_sniff_subrating(
          tHCI_STATUS status, uint16_t handle,
          uint16_t maximum_transmit_latency, uint16_t maximum_receive_latency,
          uint16_t minimum_remote_timeout, uint16_t minimum_local_timeout);
      friend void tACL_CONN::Reset();
    } sniff_subrating;

    tLINK_POLICY Settings() const { return settings_; }

   private:
    tLINK_POLICY settings_{kAllLinkPoliciesEnabled};
    friend void btm_set_link_policy(tACL_CONN* conn, tLINK_POLICY policy);
    friend void tACL_CONN::Reset();
  } policy;
};

struct controller_t;

/****************************************************
 **      ACL Management API
 ****************************************************/
constexpr uint16_t kDefaultPacketTypeMask =
    HCI_PKT_TYPES_MASK_DH1 | HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH3 |
    HCI_PKT_TYPES_MASK_DM3 | HCI_PKT_TYPES_MASK_DH5 | HCI_PKT_TYPES_MASK_DM5;

struct tACL_CB {
 private:
  friend uint8_t btm_handle_to_acl_index(uint16_t hci_handle);
  friend void btm_acl_device_down(void);
  friend void btm_acl_encrypt_change(uint16_t handle, uint8_t status,
                                     uint8_t encr_enable);

  friend void DumpsysL2cap(int fd);
  friend void DumpsysAcl(int fd);
  friend struct StackAclBtmAcl;

  tACL_CONN acl_db[MAX_L2CAP_LINKS];
  tBTM_ROLE_SWITCH_CMPL switch_role_ref_data;
  uint16_t btm_acl_pkt_types_supported = kDefaultPacketTypeMask;
  uint16_t btm_def_link_policy;
  tHCI_STATUS acl_disc_reason = HCI_ERR_UNDEFINED;

 public:
  void SetDefaultPacketTypeMask(uint16_t packet_type_mask) {
    btm_acl_pkt_types_supported = packet_type_mask;
  }

  tHCI_STATUS get_disconnect_reason() const { return acl_disc_reason; }
  void set_disconnect_reason(tHCI_STATUS reason) { acl_disc_reason = reason; }
  uint16_t DefaultPacketTypes() const { return btm_acl_pkt_types_supported; }
  uint16_t DefaultLinkPolicy() const { return btm_def_link_policy; }

  struct {
    std::vector<tBTM_PM_STATUS_CBACK*> clients;
  } link_policy;

  unsigned NumberOfActiveLinks() const {
    unsigned cnt = 0;
    for (int i = 0; i < MAX_L2CAP_LINKS; i++) {
      if (acl_db[i].InUse()) ++cnt;
    }
    return cnt;
  }
};

extern tACL_CONN* btm_acl_for_bda(const RawAddress& bd_addr,
                                  tBT_TRANSPORT transport);