Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
BTDevice.cpp
Go to the documentation of this file.
1 /*
2  * Author: Sven Gothel <sgothel@jausoft.com>
3  * Copyright (c) 2020 Gothel Software e.K.
4  * Copyright (c) 2020 ZAFENA AB
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include <cstring>
27 #include <string>
28 #include <memory>
29 #include <cstdint>
30 #include <cstdio>
31 
32 #include <algorithm>
33 
34 // #define VERBOSE_ON 1
35 #include <jau/environment.hpp>
36 #include <jau/debug.hpp>
37 
38 #include "HCIComm.hpp"
39 
40 #include "BTAdapter.hpp"
41 #include "BTDevice.hpp"
42 #include "BTManager.hpp"
43 
44 
45 using namespace direct_bt;
46 
47 BTDevice::BTDevice(const ctor_cookie& cc, BTAdapter & a, EInfoReport const & r)
48 : adapter(a),
49  l2cap_att(adapter.getAddressAndType(), L2CAP_PSM::UNDEFINED, L2CAP_CID::ATT),
50  ts_creation(r.getTimestamp()),
51  addressAndType{r.getAddress(), r.getAddressType()}
52 {
53  (void)cc;
54  ts_last_discovery = ts_creation;
55  hciConnHandle = 0;
56  le_features = LE_Features::NONE;
57  isConnected = false;
58  allowDisconnect = false;
59  clearSMPStates(false /* connected */);
60  if( !r.isSet(EIRDataType::BDADDR) ) {
61  throw jau::IllegalArgumentException("Address not set: "+r.toString(), E_FILE_LINE);
62  }
63  if( !r.isSet(EIRDataType::BDADDR_TYPE) ) {
64  throw jau::IllegalArgumentException("AddressType not set: "+r.toString(), E_FILE_LINE);
65  }
66  update(r);
67 
68  const BLERandomAddressType leRandomAddressType = addressAndType.getBLERandomAddressType();
69  if( BDAddressType::BDADDR_LE_RANDOM == addressAndType.type ) {
70  if( BLERandomAddressType::UNDEFINED == leRandomAddressType ) {
71  throw jau::IllegalArgumentException("BDADDR_LE_RANDOM: Invalid BLERandomAddressType "+
72  to_string(leRandomAddressType)+": "+toString(), E_FILE_LINE);
73  }
74  } else {
75  if( BLERandomAddressType::UNDEFINED != leRandomAddressType ) {
76  throw jau::IllegalArgumentException("Not BDADDR_LE_RANDOM: Invalid given native BLERandomAddressType "+
77  to_string(leRandomAddressType)+": "+toString(), E_FILE_LINE);
78  }
79  }
80 }
81 
82 BTDevice::~BTDevice() noexcept {
83  DBG_PRINT("BTDevice::dtor: ... %p %s", this, addressAndType.toString().c_str());
84  advServices.clear();
85  advMSD = nullptr;
86  adapter.removeAllStatusListener(*this);
87  DBG_PRINT("BTDevice::dtor: XXX %p %s", this, addressAndType.toString().c_str());
88 }
89 
90 std::shared_ptr<BTDevice> BTDevice::getSharedInstance() const noexcept {
91  return adapter.getSharedDevice(*this);
92 }
93 
94 bool BTDevice::addAdvService(std::shared_ptr<uuid_t> const &uuid) noexcept
95 {
96  if( 0 > findAdvService(uuid) ) {
97  advServices.push_back(uuid);
98  return true;
99  }
100  return false;
101 }
102 bool BTDevice::addAdvServices(jau::darray<std::shared_ptr<uuid_t>> const & services) noexcept
103 {
104  bool res = false;
105  for(size_t j=0; j<services.size(); j++) {
106  const std::shared_ptr<uuid_t> uuid = services.at(j);
107  res = addAdvService(uuid) || res;
108  }
109  return res;
110 }
111 
112 int BTDevice::findAdvService(std::shared_ptr<uuid_t> const &uuid) const noexcept
113 {
114  const size_t size = advServices.size();
115  for (size_t i = 0; i < size; i++) {
116  const std::shared_ptr<uuid_t> & e = advServices[i];
117  if ( nullptr != e && *uuid == *e ) {
118  return i;
119  }
120  }
121  return -1;
122 }
123 
124 std::string const BTDevice::getName() const noexcept {
125  jau::sc_atomic_critical sync(sync_data);
126  std::string res = name;
127  return res;
128 }
129 
130 std::shared_ptr<ManufactureSpecificData> const BTDevice::getManufactureSpecificData() const noexcept {
131  jau::sc_atomic_critical sync(sync_data);
132  std::shared_ptr<ManufactureSpecificData> res = advMSD;
133  return res;
134 }
135 
137  jau::sc_atomic_critical sync(sync_data);
138  jau::darray<std::shared_ptr<uuid_t>> res = advServices;
139  return res;
140 }
141 
142 std::string BTDevice::toString(bool includeDiscoveredServices) const noexcept {
143  const uint64_t t0 = jau::getCurrentMilliseconds();
144  jau::sc_atomic_critical sync(sync_data);
145  std::string msdstr = nullptr != advMSD ? advMSD->toString() : "MSD[null]";
146  std::string out("Device["+addressAndType.toString()+", name['"+name+
147  "'], age[total "+std::to_string(t0-ts_creation)+", ldisc "+std::to_string(t0-ts_last_discovery)+", lup "+std::to_string(t0-ts_last_update)+
148  "]ms, connected["+std::to_string(allowDisconnect)+"/"+std::to_string(isConnected)+", handle "+jau::to_hexstring(hciConnHandle)+
149  ", sec[lvl "+to_string(pairing_data.sec_level_conn)+", io "+to_string(pairing_data.ioCap_conn)+
150  ", auto "+to_string(pairing_data.ioCap_auto)+", pairing "+to_string(pairing_data.mode)+", state "+to_string(pairing_data.state)+"]], rssi "+std::to_string(getRSSI())+
151  ", tx-power "+std::to_string(tx_power)+
152  ", appearance "+jau::to_hexstring(static_cast<uint16_t>(appearance))+" ("+to_string(appearance)+
153  "), "+msdstr+", "+javaObjectToString()+"]");
154  if( includeDiscoveredServices ) {
155  jau::darray<std::shared_ptr<uuid_t>> _advServices = getAdvertisedServices();
156  if( _advServices.size() > 0 ) {
157  out.append("\n");
158  const size_t size = _advServices.size();
159  for (size_t i = 0; i < size; i++) {
160  const std::shared_ptr<uuid_t> & e = _advServices[i];
161  if( 0 < i ) {
162  out.append("\n");
163  }
164  out.append(" ").append(e->toUUID128String()).append(", ").append(std::to_string(static_cast<int>(e->getTypeSize()))).append(" bytes");
165  }
166  }
167  }
168  return out;
169 }
170 
171 EIRDataType BTDevice::update(EInfoReport const & data) noexcept {
172  const std::lock_guard<std::mutex> lock(mtx_data); // RAII-style acquire and relinquish via destructor
173  jau::sc_atomic_critical sync(sync_data); // redundant due to mutex-lock cache-load operation, leaving it for doc
174 
176  ts_last_update = data.getTimestamp();
177  if( data.isSet(EIRDataType::BDADDR) ) {
178  if( data.getAddress() != this->addressAndType.address ) {
179  WARN_PRINT("BTDevice::update:: BDADDR update not supported: %s for %s",
180  data.toString().c_str(), this->toString().c_str());
181  }
182  }
183  if( data.isSet(EIRDataType::BDADDR_TYPE) ) {
184  if( data.getAddressType() != this->addressAndType.type ) {
185  WARN_PRINT("BTDevice::update:: BDADDR_TYPE update not supported: %s for %s",
186  data.toString().c_str(), this->toString().c_str());
187  }
188  }
189  if( data.isSet(EIRDataType::NAME) ) {
190  if( 0 == name.length() || data.getName().length() > name.length() ) {
191  name = data.getName();
193  }
194  }
195  if( data.isSet(EIRDataType::NAME_SHORT) ) {
196  if( 0 == name.length() ) {
197  name = data.getShortName();
199  }
200  }
201  if( data.isSet(EIRDataType::RSSI) ) {
202  if( rssi != data.getRSSI() ) {
203  rssi = data.getRSSI();
205  }
206  }
207  if( data.isSet(EIRDataType::TX_POWER) ) {
208  if( tx_power != data.getTxPower() ) {
209  tx_power = data.getTxPower();
211  }
212  }
213  if( data.isSet(EIRDataType::APPEARANCE) ) {
214  if( appearance != data.getAppearance() ) {
215  appearance = data.getAppearance();
217  }
218  }
219  if( data.isSet(EIRDataType::MANUF_DATA) ) {
220  if( advMSD != data.getManufactureSpecificData() ) {
221  advMSD = data.getManufactureSpecificData();
223  }
224  }
225  if( addAdvServices( data.getServices() ) ) {
227  }
228  return res;
229 }
230 
231 EIRDataType BTDevice::update(GattGenericAccessSvc const &data, const uint64_t timestamp) noexcept {
232  const std::lock_guard<std::mutex> lock(mtx_data); // RAII-style acquire and relinquish via destructor
233  jau::sc_atomic_critical sync(sync_data); // redundant due to mutex-lock cache-load operation, leaving it for doc
234 
236  ts_last_update = timestamp;
237  if( 0 == name.length() || data.deviceName.length() > name.length() ) {
238  name = data.deviceName;
240  }
241  if( appearance != data.appearance ) {
242  appearance = data.appearance;
244  }
245  return res;
246 }
247 
248 bool BTDevice::addStatusListener(std::shared_ptr<AdapterStatusListener> l) {
249  return adapter.addStatusListener(*this, l);
250 }
251 
252 bool BTDevice::removeStatusListener(std::shared_ptr<AdapterStatusListener> l) {
253  return adapter.removeStatusListener(l);
254 }
255 
256 std::shared_ptr<ConnectionInfo> BTDevice::getConnectionInfo() noexcept {
257  BTManager & mgmt = adapter.getManager();
258  std::shared_ptr<ConnectionInfo> connInfo = mgmt.getConnectionInfo(adapter.dev_id, addressAndType);
259  if( nullptr != connInfo ) {
260  EIRDataType updateMask = EIRDataType::NONE;
261  if( rssi != connInfo->getRSSI() ) {
262  rssi = connInfo->getRSSI();
264  }
265  if( tx_power != connInfo->getTxPower() ) {
266  tx_power = connInfo->getTxPower();
268  }
269  if( EIRDataType::NONE != updateMask ) {
270  std::shared_ptr<BTDevice> sharedInstance = getSharedInstance();
271  if( nullptr == sharedInstance ) {
272  ERR_PRINT("BTDevice::getConnectionInfo: Device unknown to adapter and not tracked: %s", toString().c_str());
273  } else {
274  adapter.sendDeviceUpdated("getConnectionInfo", sharedInstance, jau::getCurrentMilliseconds(), updateMask);
275  }
276  }
277  }
278  return connInfo;
279 }
280 
281 // #define TEST_NOENC 1
282 
284  uint16_t conn_interval_min, uint16_t conn_interval_max,
285  uint16_t conn_latency, uint16_t supervision_timeout) noexcept
286 {
287  const std::lock_guard<std::recursive_mutex> lock_conn(mtx_connect); // RAII-style acquire and relinquish via destructor
288  if( !adapter.isPowered() ) {
289  WARN_PRINT("BTDevice::connectLE: Adapter not powered: %s, %s", adapter.toString().c_str(), toString().c_str());
291  }
292  HCILEOwnAddressType hci_own_mac_type;
293  HCILEPeerAddressType hci_peer_mac_type;
294 
295  switch( addressAndType.type ) {
297  hci_peer_mac_type = HCILEPeerAddressType::PUBLIC;
298  hci_own_mac_type = HCILEOwnAddressType::PUBLIC;
299  break;
301  const BLERandomAddressType leRandomAddressType = addressAndType.getBLERandomAddressType();
302  switch( leRandomAddressType ) {
304  hci_peer_mac_type = HCILEPeerAddressType::RANDOM;
305  hci_own_mac_type = HCILEOwnAddressType::RANDOM;
306  ERR_PRINT("LE Random address type '%s' not supported yet: %s",
307  to_string(leRandomAddressType).c_str(), toString().c_str());
310  hci_peer_mac_type = HCILEPeerAddressType::PUBLIC_IDENTITY;
312  ERR_PRINT("LE Random address type '%s' not supported yet: %s",
313  to_string(leRandomAddressType).c_str(), toString().c_str());
316  // FIXME: This only works for a static random address not changing at all,
317  // i.e. between power-cycles - hence a temporary hack.
318  // We need to use 'resolving list' and/or LE Set Privacy Mode (HCI) for all devices.
319  hci_peer_mac_type = HCILEPeerAddressType::RANDOM;
320  hci_own_mac_type = HCILEOwnAddressType::PUBLIC;
321  break;
322  default: {
323  ERR_PRINT("Can't connectLE to LE Random address type '%s': %s",
324  to_string(leRandomAddressType).c_str(), toString().c_str());
326  }
327  }
328  } break;
329  default: {
330  ERR_PRINT("Can't connectLE to address type '%s': %s", to_string(addressAndType.type).c_str(), toString().c_str());
332  }
333  }
334 
335  if( isConnected ) {
336  ERR_PRINT("BTDevice::connectLE: Already connected: %s", toString().c_str());
338  }
339 
340  HCIHandler &hci = adapter.getHCI();
341  if( !hci.isOpen() ) {
342  ERR_PRINT("BTDevice::connectLE: HCI closed: %s", toString().c_str());
344  }
345 
346  HCIStatusCode statusConnect; // HCI le_create_conn result
347  const SMPIOCapability smp_auto_io_cap = pairing_data.ioCap_auto; // cache against clearSMPState
348  const bool smp_auto = SMPIOCapability::UNSET != smp_auto_io_cap; // logical cached state
349  bool smp_auto_done = !smp_auto;
350  int smp_auto_count = 0;
351  BTSecurityLevel sec_level = pairing_data.sec_level_user; // iterate down
352  SMPIOCapability io_cap = pairing_data.ioCap_user; // iterate down
354 
355  do {
356  smp_auto_count++;
357 
358  if( !smp_auto_done ) {
359  BTSecurityLevel sec_level_pre = sec_level;
360  SMPIOCapability io_cap_pre = io_cap;
361  if( BTSecurityLevel::UNSET == sec_level && SMPIOCapability::NO_INPUT_NO_OUTPUT != smp_auto_io_cap ) {
362  sec_level = BTSecurityLevel::ENC_AUTH_FIPS;
363  io_cap = smp_auto_io_cap;
364  } else if( BTSecurityLevel::ENC_AUTH_FIPS == sec_level && SMPIOCapability::NO_INPUT_NO_OUTPUT != smp_auto_io_cap ) {
365  sec_level = BTSecurityLevel::ENC_AUTH;
366  io_cap = smp_auto_io_cap;
367  } else if( BTSecurityLevel::ENC_AUTH == sec_level || BTSecurityLevel::UNSET == sec_level ) {
368 #if TEST_NOENC
369  sec_level = BTSecurityLevel::NONE;
371  smp_auto_done = true;
372 #else
373  sec_level = BTSecurityLevel::ENC_ONLY;
375 #endif
376  } else if( BTSecurityLevel::ENC_ONLY == sec_level ) {
377  sec_level = BTSecurityLevel::NONE;
379  smp_auto_done = true;
380  }
381  pairing_data.ioCap_auto = smp_auto_io_cap; // reload against clearSMPState
382  pairing_data.sec_level_user = sec_level;
383  pairing_data.ioCap_user = io_cap;
384  DBG_PRINT("BTDevice::connectLE: SEC AUTO.%d.1: lvl %s -> %s, io %s -> %s, %s", smp_auto_count,
385  to_string(sec_level_pre).c_str(), to_string(sec_level).c_str(),
386  to_string(io_cap_pre).c_str(), to_string(io_cap).c_str(),
387  toString().c_str());
388  }
389 
390  {
391  jau::sc_atomic_critical sync(sync_data);
392  if( !adapter.lockConnect(*this, true /* wait */, pairing_data.ioCap_user) ) {
393  ERR_PRINT("BTDevice::connectLE: adapter::lockConnect() failed: %s", toString().c_str());
395  }
396  }
397  statusConnect = hci.le_create_conn(addressAndType.address,
398  hci_peer_mac_type, hci_own_mac_type,
399  le_scan_interval, le_scan_window, conn_interval_min, conn_interval_max,
400  conn_latency, supervision_timeout);
401  allowDisconnect = true;
402  if( HCIStatusCode::COMMAND_DISALLOWED == statusConnect ) {
403  WARN_PRINT("BTDevice::connectLE: Could not yet create connection: status 0x%2.2X (%s), errno %d, hci-atype[peer %s, own %s] %s on %s",
404  static_cast<uint8_t>(statusConnect), to_string(statusConnect).c_str(), errno, strerror(errno),
405  to_string(hci_peer_mac_type).c_str(),
406  to_string(hci_own_mac_type).c_str(),
407  toString().c_str());
408  adapter.unlockConnect(*this);
409  smp_auto_done = true; // premature end of potential SMP auto-negotiation
410  } else if ( HCIStatusCode::SUCCESS != statusConnect ) {
411  ERR_PRINT("BTDevice::connectLE: Could not create connection: status 0x%2.2X (%s), errno %d %s, hci-atype[peer %s, own %s] on %s",
412  static_cast<uint8_t>(statusConnect), to_string(statusConnect).c_str(), errno, strerror(errno),
413  to_string(hci_peer_mac_type).c_str(),
414  to_string(hci_own_mac_type).c_str(),
415  toString().c_str());
416  adapter.unlockConnect(*this);
417  smp_auto_done = true; // premature end of potential SMP auto-negotiation
418  } else if( smp_auto ) { // implies HCIStatusCode::SUCCESS
419  // Waiting for PairingState
420  bool pairing_timeout = false;
421  {
422  std::unique_lock<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor
423  jau::sc_atomic_critical sync1(sync_data);
424 
425  while( !hasSMPPairingFinished( pairing_data.state ) ) {
426  std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
427  std::cv_status s = cv_pairing_state_changed.wait_until(lock, t0 + std::chrono::milliseconds(hci.env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT));
428  DBG_PRINT("BTDevice::connectLE: SEC AUTO.%d.2c Wait for SMPPairing: state %s, %s",
429  smp_auto_count, to_string(pairing_data.state).c_str(), toString().c_str());
430  if( std::cv_status::timeout == s && !hasSMPPairingFinished( pairing_data.state ) ) {
431  // timeout
432  ERR_PRINT("BTDevice::connectLE: SEC AUTO.%d.X Timeout SMPPairing: Disconnecting %s", smp_auto_count, toString().c_str());
433  smp_auto_done = true;
434  pairing_data.ioCap_auto = SMPIOCapability::UNSET;
435  pairing_timeout = true;
436  break;
437  }
438  }
439  pstate = pairing_data.state;
440  DBG_PRINT("BTDevice::connectLE: SEC AUTO.%d.2d Wait for SMPPairing: state %s, %s",
441  smp_auto_count, to_string(pstate).c_str(), toString().c_str());
442  }
443  if( pairing_timeout ) {
444  pairing_data.ioCap_auto = SMPIOCapability::UNSET;
446  statusConnect = HCIStatusCode::INTERNAL_TIMEOUT;
447  adapter.unlockConnect(*this);
448  smp_auto_done = true;
449  } else if( SMPPairingState::COMPLETED == pstate ) {
450  DBG_PRINT("BTDevice::connectLE: SEC AUTO.%d.X Done: %s", smp_auto_count, toString().c_str());
451  smp_auto_done = true;
452  break;
453  } else if( SMPPairingState::FAILED == pstate ) {
454  if( !smp_auto_done ) { // not last one
455  // disconnect for next smp_auto mode test
456  int32_t td_disconnect = 0;
457  DBG_PRINT("BTDevice::connectLE: SEC AUTO.%d.3 Failed SMPPairing -> Disconnect: %s", smp_auto_count, toString().c_str());
459  if( HCIStatusCode::SUCCESS == dres ) {
460  while( isConnected && hci.env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT > td_disconnect ) {
461  jau::sc_atomic_critical sync2(sync_data);
462  td_disconnect += hci.env.HCI_COMMAND_POLL_PERIOD;
463  std::this_thread::sleep_for(std::chrono::milliseconds(hci.env.HCI_COMMAND_POLL_PERIOD));
464  }
465  }
466  if( hci.env.HCI_COMMAND_COMPLETE_REPLY_TIMEOUT <= td_disconnect ) {
467  // timeout
468  ERR_PRINT("BTDevice::connectLE: SEC AUTO.%d.4 Timeout Disconnect td_pairing %d ms: %s",
469  smp_auto_count, td_disconnect, toString().c_str());
470  pairing_data.ioCap_auto = SMPIOCapability::UNSET;
471  statusConnect = HCIStatusCode::INTERNAL_TIMEOUT;
472  adapter.unlockConnect(*this);
473  smp_auto_done = true;
474  }
475  }
476  }
477  }
478  } while( !smp_auto_done );
479  if( smp_auto ) {
480  jau::sc_atomic_critical sync(sync_data);
481  if( HCIStatusCode::SUCCESS == statusConnect && SMPPairingState::FAILED == pstate ) {
482  ERR_PRINT("BTDevice::connectLE: SEC AUTO.%d.X Failed SMPPairing -> Disconnect: %s", smp_auto_count, toString().c_str());
483  pairing_data.ioCap_auto = SMPIOCapability::UNSET;
485  statusConnect = HCIStatusCode::AUTH_FAILED;
486  }
487  pairing_data.ioCap_auto = SMPIOCapability::UNSET; // always clear post-auto-action: Allow normal notification.
488  }
489  return statusConnect;
490 }
491 
492 HCIStatusCode BTDevice::connectBREDR(const uint16_t pkt_type, const uint16_t clock_offset, const uint8_t role_switch) noexcept
493 {
494  const std::lock_guard<std::recursive_mutex> lock_conn(mtx_connect); // RAII-style acquire and relinquish via destructor
495  if( !adapter.isPowered() ) {
496  WARN_PRINT("BTDevice::connectBREDR: Adapter not powered: %s, %s", adapter.toString().c_str(), toString().c_str());
498  }
499 
500  if( isConnected ) {
501  ERR_PRINT("BTDevice::connectBREDR: Already connected: %s", toString().c_str());
503  }
504  if( !addressAndType.isBREDRAddress() ) {
505  ERR_PRINT("BTDevice::connectBREDR: Not a BDADDR_BREDR address: %s", toString().c_str());
507  }
508 
509  HCIHandler &hci = adapter.getHCI();
510  if( !hci.isOpen() ) {
511  ERR_PRINT("BTDevice::connectBREDR: HCI closed: %s", toString().c_str());
513  }
514 
515  {
516  jau::sc_atomic_critical sync(sync_data);
517  if( !adapter.lockConnect(*this, true /* wait */, pairing_data.ioCap_user) ) {
518  ERR_PRINT("BTDevice::connectBREDR: adapter::lockConnect() failed: %s", toString().c_str());
520  }
521  }
522  HCIStatusCode status = hci.create_conn(addressAndType.address, pkt_type, clock_offset, role_switch);
523  allowDisconnect = true;
524  if ( HCIStatusCode::SUCCESS != status ) {
525  ERR_PRINT("BTDevice::connectBREDR: Could not create connection: status 0x%2.2X (%s), errno %d %s on %s",
526  static_cast<uint8_t>(status), to_string(status).c_str(), errno, strerror(errno), toString().c_str());
527  adapter.unlockConnect(*this);
528  }
529  return status;
530 }
531 
533 {
534  switch( addressAndType.type ) {
536  [[fallthrough]];
538  return connectLE();
540  return connectBREDR();
541  default:
542  ERR_PRINT("BTDevice::connectDefault: Not a valid address type: %s", toString().c_str());
544  }
545 }
546 
547 void BTDevice::notifyConnected(std::shared_ptr<BTDevice> sthis, const uint16_t handle, const SMPIOCapability io_cap) noexcept {
548  // coming from connected callback, update state and spawn-off connectGATT in background if appropriate (LE)
549  jau::sc_atomic_critical sync(sync_data);
550  DBG_PRINT("BTDevice::notifyConnected: handle %s -> %s, io %s -> %s, %s",
551  jau::to_hexstring(hciConnHandle).c_str(), jau::to_hexstring(handle).c_str(),
552  to_string(pairing_data.ioCap_conn).c_str(), to_string(io_cap).c_str(),
553  toString().c_str());
554  clearSMPStates(true /* connected */);
555  allowDisconnect = true;
556  isConnected = true;
557  hciConnHandle = handle;
558  if( SMPIOCapability::UNSET == pairing_data.ioCap_conn ) {
559  pairing_data.ioCap_conn = io_cap;
560  }
561  (void)sthis; // not used yet
562 }
563 
564 void BTDevice::notifyLEFeatures(std::shared_ptr<BTDevice> sthis, const LE_Features features) noexcept {
565  DBG_PRINT("BTDevice::notifyLEFeatures: %s, %s",
566  direct_bt::to_string(features).c_str(), toString().c_str());
567  le_features = features;
568 
569  if( addressAndType.isLEAddress() && !l2cap_att.isOpen() ) {
570  std::thread bg(&BTDevice::processL2CAPSetup, this, sthis); // @suppress("Invalid arguments")
571  bg.detach();
572  }
573 }
574 
575 void BTDevice::processL2CAPSetup(std::shared_ptr<BTDevice> sthis) {
576  bool callProcessDeviceReady = false;
577 
578  if( addressAndType.isLEAddress() && !l2cap_att.isOpen() ) {
579  const std::unique_lock<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor
580  jau::sc_atomic_critical sync(sync_data);
581 
582  DBG_PRINT("BTDevice::processL2CAPSetup: Start %s", toString().c_str());
583 
584  const BTSecurityLevel sec_level_user = pairing_data.sec_level_user;
585  const SMPIOCapability io_cap_conn = pairing_data.ioCap_conn;
587 
588  const bool responderLikesEncryption = pairing_data.res_requested_sec || isLEFeaturesBitSet(le_features, LE_Features::LE_Encryption);
589  if( BTSecurityLevel::UNSET != sec_level_user ) {
590  sec_level = sec_level_user;
591  } else if( responderLikesEncryption && SMPIOCapability::UNSET != io_cap_conn ) {
592  if( SMPIOCapability::NO_INPUT_NO_OUTPUT == io_cap_conn ) {
593  sec_level = BTSecurityLevel::ENC_ONLY; // no auth w/o I/O
594  } else if( adapter.hasSecureConnections() ) {
595  sec_level = BTSecurityLevel::ENC_AUTH_FIPS;
596  } else if( responderLikesEncryption ) {
597  sec_level = BTSecurityLevel::ENC_AUTH;
598  }
599  } else {
600  sec_level = BTSecurityLevel::NONE;
601  }
602  pairing_data.sec_level_conn = sec_level;
603  DBG_PRINT("BTDevice::processL2CAPSetup: sec_level_user %s, io_cap_conn %s -> sec_level %s",
604  to_string(sec_level_user).c_str(),
605  to_string(io_cap_conn).c_str(),
606  to_string(sec_level).c_str());
607 
608  const bool l2cap_open = l2cap_att.open(*this, sec_level); // initiates hciSMPMsgCallback() if sec_level > BT_SECURITY_LOW
609  const bool l2cap_enc = l2cap_open && BTSecurityLevel::NONE < sec_level;
610 #if SMP_SUPPORTED_BY_OS
611  const bool smp_enc = connectSMP(sthis, sec_level) && BTSecurityLevel::NONE < sec_level;
612 #else
613  const bool smp_enc = false;
614 #endif
615  DBG_PRINT("BTDevice::processL2CAPSetup: lvl %s, connect[smp_enc %d, l2cap[open %d, enc %d]]",
616  to_string(sec_level).c_str(), smp_enc, l2cap_open, l2cap_enc);
617 
618  adapter.unlockConnect(*this);
619 
620  if( !l2cap_open ) {
621  pairing_data.sec_level_conn = BTSecurityLevel::NONE;
623  } else if( !l2cap_enc ) {
624  callProcessDeviceReady = true;
625  }
626  } else {
627  DBG_PRINT("BTDevice::processL2CAPSetup: Skipped (not LE) %s", toString().c_str());
628  }
629  if( callProcessDeviceReady ) {
630  // call out of scope of locked mtx_pairing
631  processDeviceReady(sthis, jau::getCurrentMilliseconds());
632  }
633  DBG_PRINT("BTDevice::processL2CAPSetup: End %s", toString().c_str());
634 }
635 
636 void BTDevice::processDeviceReady(std::shared_ptr<BTDevice> sthis, const uint64_t timestamp) {
637  DBG_PRINT("BTDevice::processDeviceReady: %s", toString().c_str());
638  PairingMode pmode;
639  {
640  jau::sc_atomic_critical sync(sync_data);
641  pmode = pairing_data.mode;
642  }
644 
645  if( PairingMode::PRE_PAIRED == pmode ) {
646  // Delay GATT processing when re-using encryption keys.
647  // Here we lack of further processing / state indication
648  // and a too fast GATT access leads to disconnection.
649  // (Empirical delay figured by accident.)
650  std::this_thread::sleep_for(std::chrono::milliseconds(100));
651  }
652 
653  const bool res1 = connectGATT(sthis); // may close connection and hence clear pairing_data
654 
655  if( !res1 && PairingMode::PRE_PAIRED == pmode ) {
656  // Need to repair as GATT communication failed
657  unpair_res = unpair();
658  }
659  DBG_PRINT("BTDevice::processDeviceReady: ready[GATT %d, unpair %s], %s",
660  res1, to_string(unpair_res).c_str(), toString().c_str());
661  if( res1 ) {
662  adapter.sendDeviceReady(sthis, timestamp);
663  }
664 }
665 
666 
669 
670 bool BTDevice::checkPairingKeyDistributionComplete(const std::string& timestamp) const noexcept {
671  bool res = false;
672 
673  if( SMPPairingState::KEY_DISTRIBUTION == pairing_data.state ) {
674  // Spec allows responder to not distribute the keys,
675  // hence distribution is complete with initiator (LL master) keys!
676  // Impact of missing responder keys: Requires new pairing each connection.
677  if( pairing_data.use_sc ) {
678  if( pairing_data.keys_init_has == ( pairing_data.keys_init_exp & _key_mask_sc ) ) {
679  // pairing_data.keys_resp_has == ( pairing_data.keys_resp_exp & key_mask_sc )
680  res = true;
681  }
682  } else {
683  if( pairing_data.keys_init_has == ( pairing_data.keys_init_exp & _key_mask_legacy ) ) {
684  // pairing_data.keys_resp_has == ( pairing_data.keys_resp_exp & key_mask_legacy )
685  res = true;
686  }
687  }
688 
689  if( jau::environment::get().debug ) {
690  jau::PLAIN_PRINT(false, "[%s] Debug: BTDevice:SMP:KEY_DISTRIBUTION: done %d, address%s",
691  timestamp.c_str(), res,
692  addressAndType.toString().c_str());
693  jau::PLAIN_PRINT(false, "[%s] - keys[init %s / %s, resp %s / %s]",
694  timestamp.c_str(),
695  to_string(pairing_data.keys_init_has).c_str(),
696  to_string(pairing_data.keys_init_exp).c_str(),
697  to_string(pairing_data.keys_resp_has).c_str(),
698  to_string(pairing_data.keys_resp_exp).c_str());
699  }
700  }
701 
702  return res;
703 }
704 
705 bool BTDevice::updatePairingState(std::shared_ptr<BTDevice> sthis, const MgmtEvent& evt, const HCIStatusCode evtStatus, SMPPairingState claimed_state) noexcept {
706  const std::unique_lock<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor
707  jau::sc_atomic_critical sync(sync_data);
708 
709  const SMPIOCapability iocap = pairing_data.ioCap_conn;
710  const MgmtEvent::Opcode mgmtEvtOpcode = evt.getOpcode();
711  PairingMode mode = pairing_data.mode;
712  bool is_device_ready = false;
713 
714  if( pairing_data.state != claimed_state ) {
715  // Potentially force update PairingMode by forced state change, assuming being the initiator.
716  switch( claimed_state ) {
718  // no change
719  claimed_state = pairing_data.state;
720  break;
721  case SMPPairingState::FAILED: { /* Next: disconnect(..) by user or auto-mode */
722  mode = PairingMode::NONE;
723  } break;
725  if( hasSMPIOCapabilityFullInput( iocap ) ) {
727  } else {
728  // BT core requesting passkey input w/o full input caps is nonsense (bug?)
729  // Reply with a default value '0' off-thread ASAP
730  DBG_PRINT("BTDevice::updatePairingState.1a: state %s [ignored %s, sending dummy reply], mode %s, %s",
731  to_string(pairing_data.state).c_str(), to_string(claimed_state).c_str(),
732  to_string(pairing_data.mode).c_str(), evt.toString().c_str());
733  claimed_state = pairing_data.state; // suppress
734  std::thread dc(&BTDevice::setPairingPasskey, sthis, 0);
735  dc.detach();
736  }
737  break;
739  if( hasSMPIOCapabilityBinaryInput( iocap ) ) {
741  } else {
742  // BT core requesting binary input w/o input caps is nonsense (bug?)
743  // Reply with a default value 'true' off-thread ASAP
744  DBG_PRINT("BTDevice::updatePairingState.1b: state %s [ignored %s, sending dummy reply], mode %s, %s",
745  to_string(pairing_data.state).c_str(), to_string(claimed_state).c_str(),
746  to_string(pairing_data.mode).c_str(), evt.toString().c_str());
747  claimed_state = pairing_data.state; // suppress
748  std::thread dc(&BTDevice::setPairingNumericComparison, sthis, true);
749  dc.detach();
750  }
751  break;
754  break;
756  if( MgmtEvent::Opcode::HCI_ENC_CHANGED == mgmtEvtOpcode &&
757  HCIStatusCode::SUCCESS == evtStatus &&
758  SMPPairingState::FEATURE_EXCHANGE_STARTED > pairing_data.state )
759  {
760  // No SMP pairing in process (maybe REQUESTED_BY_RESPONDER at maximum),
761  // i.e. already paired, reusing keys and usable connection
763  is_device_ready = true;
764  } else if( MgmtEvent::Opcode::PAIR_DEVICE_COMPLETE == mgmtEvtOpcode &&
765  HCIStatusCode::ALREADY_PAIRED == evtStatus &&
766  SMPPairingState::FEATURE_EXCHANGE_STARTED > pairing_data.state )
767  {
768  // No SMP pairing in process (maybe REQUESTED_BY_RESPONDER at maximum),
769  // i.e. already paired, reusing keys and usable connection
771  is_device_ready = true;
772  } else if( MgmtEvent::Opcode::NEW_LONG_TERM_KEY == mgmtEvtOpcode &&
773  HCIStatusCode::SUCCESS == evtStatus &&
774  SMPPairingState::KEY_DISTRIBUTION == pairing_data.state )
775  {
776  // SMP pairing has started, mngr issued new LTK key command
777  const MgmtEvtNewLongTermKey& event = *static_cast<const MgmtEvtNewLongTermKey *>(&evt);
778  const MgmtLongTermKeyInfo& ltk_info = event.getLongTermKey();
779  const SMPLongTermKeyInfo smp_ltk = ltk_info.toSMPLongTermKeyInfo();
780  if( smp_ltk.isValid() ) {
781  const std::string timestamp = jau::to_decstring(jau::environment::getElapsedMillisecond(evt.getTimestamp()), ',', 9);
782 
783  if( smp_ltk.isResponder() ) {
784  if( ( SMPKeyType::ENC_KEY & pairing_data.keys_resp_has ) == SMPKeyType::NONE ) { // no overwrite
785  if( jau::environment::get().debug ) {
786  jau::PLAIN_PRINT(false, "[%s] BTDevice::updatePairingState.2a: ENC_KEY responder set", timestamp.c_str());
787  jau::PLAIN_PRINT(false, "[%s] - old %s", timestamp.c_str(), pairing_data.ltk_resp.toString().c_str());
788  jau::PLAIN_PRINT(false, "[%s] - new %s", timestamp.c_str(), smp_ltk.toString().c_str());
789  }
790  pairing_data.ltk_resp = smp_ltk;
791  pairing_data.keys_resp_has |= SMPKeyType::ENC_KEY;
792  if( checkPairingKeyDistributionComplete(timestamp) ) {
793  is_device_ready = true;
794  }
795  }
796  } else {
797  if( ( SMPKeyType::ENC_KEY & pairing_data.keys_init_has ) == SMPKeyType::NONE ) { // no overwrite
798  if( jau::environment::get().debug ) {
799  jau::PLAIN_PRINT(false, "[%s] BTDevice::updatePairingState.2b: ENC_KEY initiator set", timestamp.c_str());
800  jau::PLAIN_PRINT(false, "[%s] - old %s", timestamp.c_str(), pairing_data.ltk_init.toString().c_str());
801  jau::PLAIN_PRINT(false, "[%s] - new %s", timestamp.c_str(), smp_ltk.toString().c_str());
802  }
803  pairing_data.ltk_init = smp_ltk;
804  pairing_data.keys_init_has |= SMPKeyType::ENC_KEY;
805  if( checkPairingKeyDistributionComplete(timestamp) ) {
806  is_device_ready = true;
807  }
808  }
809  }
810  if( !is_device_ready ) {
811  claimed_state = pairing_data.state; // not yet
812  }
813  }
814  } else {
815  // Ignore: Undesired event or SMP pairing is in process, which needs to be completed.
816  claimed_state = pairing_data.state;
817  }
818  break;
819  default: // use given state as-is
820  break;
821  }
822  }
823 
824  if( pairing_data.state != claimed_state ) {
825  DBG_PRINT("BTDevice::updatePairingState.3: state %s -> %s, mode %s -> %s, ready %d, %s",
826  to_string(pairing_data.state).c_str(), to_string(claimed_state).c_str(),
827  to_string(pairing_data.mode).c_str(), to_string(mode).c_str(),
828  is_device_ready, evt.toString().c_str());
829 
830  pairing_data.mode = mode;
831  pairing_data.state = claimed_state;
832 
833  adapter.sendDevicePairingState(sthis, claimed_state, mode, evt.getTimestamp());
834 
835  if( is_device_ready ) {
836  std::thread dc(&BTDevice::processDeviceReady, this, sthis, evt.getTimestamp()); // @suppress("Invalid arguments")
837  dc.detach();
838  }
839  DBG_PRINT("BTDevice::updatePairingState.4: End Complete: state %s, %s",
840  to_string(claimed_state).c_str(), toString().c_str());
841 
842  cv_pairing_state_changed.notify_all();
843 
844  return true;
845  } else {
846  DBG_PRINT("BTDevice::updatePairingState.5: End Unchanged: state %s, %s, %s",
847  to_string(pairing_data.state).c_str(),
848  evt.toString().c_str(), toString().c_str());
849  }
850  return false;
851 }
852 
853 void BTDevice::hciSMPMsgCallback(std::shared_ptr<BTDevice> sthis, const SMPPDUMsg& msg, const HCIACLData::l2cap_frame& source) noexcept {
854  const std::unique_lock<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor
855  jau::sc_atomic_critical sync(sync_data);
856 
857  const SMPPairingState old_pstate = pairing_data.state;
858  const PairingMode old_pmode = pairing_data.mode;
859  const std::string timestamp = jau::to_decstring(jau::environment::getElapsedMillisecond(msg.getTimestamp()), ',', 9);
860 
861  SMPPairingState pstate = old_pstate;
862  PairingMode pmode = old_pmode;
863  bool is_device_ready = false;
864 
865  if( jau::environment::get().debug ) {
866  jau::PLAIN_PRINT(false, "[%s] Debug: BTDevice:hci:SMP.0: address%s",
867  timestamp.c_str(),
868  addressAndType.toString().c_str());
869  jau::PLAIN_PRINT(false, "[%s] - %s", timestamp.c_str(), msg.toString().c_str());
870  jau::PLAIN_PRINT(false, "[%s] - %s", timestamp.c_str(), source.toString().c_str());
871  jau::PLAIN_PRINT(false, "[%s] - %s", timestamp.c_str(), toString().c_str());
872  }
873 
874  const SMPPDUMsg::Opcode opc = msg.getOpcode();
875 
876  switch( opc ) {
877  // Phase 1: SMP Negotiation phase
878 
880  pmode = PairingMode::NEGOTIATING;
882  pairing_data.res_requested_sec = true;
883  break;
884 
886  if( HCIACLData::l2cap_frame::PBFlag::START_NON_AUTOFLUSH_HOST == source.pb_flag ) { // from initiator (master)
887  const SMPPairingMsg & msg1 = *static_cast<const SMPPairingMsg *>( &msg );
888  pairing_data.authReqs_init = msg1.getAuthReqMask();
889  pairing_data.ioCap_init = msg1.getIOCapability();
890  pairing_data.oobFlag_init = msg1.getOOBDataFlag();
891  pairing_data.maxEncsz_init = msg1.getMaxEncryptionKeySize();
892  pairing_data.keys_init_exp = msg1.getInitKeyDist();
893  pmode = PairingMode::NEGOTIATING;
895  }
896  break;
897 
899  if( HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH == source.pb_flag ) { // from responder (slave)
900  const SMPPairingMsg & msg1 = *static_cast<const SMPPairingMsg *>( &msg );
901  pairing_data.authReqs_resp = msg1.getAuthReqMask();
902  pairing_data.ioCap_resp = msg1.getIOCapability();
903  pairing_data.oobFlag_resp = msg1.getOOBDataFlag();
904  pairing_data.maxEncsz_resp = msg1.getMaxEncryptionKeySize();
905  pairing_data.keys_init_exp = msg1.getInitKeyDist(); // responding device overrides initiator's request!
906  pairing_data.keys_resp_exp = msg1.getRespKeyDist();
907 
908  const bool use_sc = isSMPAuthReqBitSet( pairing_data.authReqs_init, SMPAuthReqs::SECURE_CONNECTIONS ) &&
909  isSMPAuthReqBitSet( pairing_data.authReqs_resp, SMPAuthReqs::SECURE_CONNECTIONS );
910  pairing_data.use_sc = use_sc;
911 
912  pmode = ::getPairingMode(use_sc,
913  pairing_data.authReqs_init, pairing_data.ioCap_init, pairing_data.oobFlag_init,
914  pairing_data.authReqs_resp, pairing_data.ioCap_resp, pairing_data.oobFlag_resp);
915 
917 
918  if( jau::environment::get().debug ) {
919  jau::PLAIN_PRINT(false, "[%s] ", timestamp.c_str());
920  jau::PLAIN_PRINT(false, "[%s] Debug: BTDevice:hci:SMP.2: address%s: State %s, Mode %s, using SC %d:", timestamp.c_str() ,
921  addressAndType.toString().c_str(),
922  to_string(pstate).c_str(), to_string(pmode).c_str(), use_sc);
923  jau::PLAIN_PRINT(false, "[%s] - oob: init %s", timestamp.c_str(), to_string(pairing_data.oobFlag_init).c_str());
924  jau::PLAIN_PRINT(false, "[%s] - oob: resp %s", timestamp.c_str(), to_string(pairing_data.oobFlag_resp).c_str());
925  jau::PLAIN_PRINT(false, "[%s] ", timestamp.c_str());
926  jau::PLAIN_PRINT(false, "[%s] - auth: init %s", timestamp.c_str(), to_string(pairing_data.authReqs_init).c_str());
927  jau::PLAIN_PRINT(false, "[%s] - auth: resp %s", timestamp.c_str(), to_string(pairing_data.authReqs_resp).c_str());
928  jau::PLAIN_PRINT(false, "[%s] ", timestamp.c_str());
929  jau::PLAIN_PRINT(false, "[%s] - iocap: init %s", timestamp.c_str(), to_string(pairing_data.ioCap_init).c_str());
930  jau::PLAIN_PRINT(false, "[%s] - iocap: resp %s", timestamp.c_str(), to_string(pairing_data.ioCap_resp).c_str());
931  jau::PLAIN_PRINT(false, "[%s] ", timestamp.c_str());
932  jau::PLAIN_PRINT(false, "[%s] - encsz: init %d", timestamp.c_str(), (int)pairing_data.maxEncsz_init);
933  jau::PLAIN_PRINT(false, "[%s] - encsz: resp %d", timestamp.c_str(), (int)pairing_data.maxEncsz_resp);
934  jau::PLAIN_PRINT(false, "[%s] ", timestamp.c_str());
935  jau::PLAIN_PRINT(false, "[%s] - keys: init %s", timestamp.c_str(), to_string(pairing_data.keys_init_exp).c_str());
936  jau::PLAIN_PRINT(false, "[%s] - keys: resp %s", timestamp.c_str(), to_string(pairing_data.keys_resp_exp).c_str());
937  }
938  }
939  } break;
940 
941  // Phase 2: SMP Authentication and Encryption
942 
944  [[fallthrough]];
946  [[fallthrough]];
948  pmode = old_pmode;
950  break;
951 
952  case SMPPDUMsg::Opcode::PAIRING_FAILED: { /* Next: disconnect(..) by user or auto-mode */
953  pmode = PairingMode::NONE;
954  pstate = SMPPairingState::FAILED;
955  } break;
956 
957  // Phase 3: SMP Key & Value Distribution phase
958 
959  case SMPPDUMsg::Opcode::ENCRYPTION_INFORMATION: { /* Legacy: 1 */
960  // LTK: First part for SMPKeyDistFormat::ENC_KEY, followed by MASTER_IDENTIFICATION (EDIV + RAND)
961  const SMPEncInfoMsg & msg1 = *static_cast<const SMPEncInfoMsg *>( &msg );
962  if( HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH == source.pb_flag ) {
963  // from responder (LL slave)
964  pairing_data.ltk_resp.properties |= SMPLongTermKeyInfo::Property::RESPONDER;
965  if( BTSecurityLevel::ENC_AUTH <= pairing_data.sec_level_conn ) {
966  pairing_data.ltk_resp.properties |= SMPLongTermKeyInfo::Property::AUTH;
967  }
968  if( pairing_data.use_sc ) {
969  pairing_data.ltk_resp.properties |= SMPLongTermKeyInfo::Property::SC;
970  }
971  pairing_data.ltk_resp.enc_size = pairing_data.maxEncsz_resp;
972  pairing_data.ltk_resp.ltk = msg1.getLTK();
973  } else {
974  // from initiator (LL master)
975  // pairing_data.ltk_resp.properties |= SMPLongTermKeyInfo::Property::INITIATOR;
976  if( BTSecurityLevel::ENC_AUTH <= pairing_data.sec_level_conn ) {
977  pairing_data.ltk_init.properties |= SMPLongTermKeyInfo::Property::AUTH;
978  }
979  if( pairing_data.use_sc ) {
980  pairing_data.ltk_init.properties |= SMPLongTermKeyInfo::Property::SC;
981  }
982  pairing_data.ltk_init.enc_size = pairing_data.maxEncsz_init;
983  pairing_data.ltk_init.ltk = msg1.getLTK();
984  }
985  } break;
986 
987  case SMPPDUMsg::Opcode::MASTER_IDENTIFICATION: { /* Legacy: 2 */
988  // EDIV + RAND, completing SMPKeyDistFormat::ENC_KEY
989  const SMPMasterIdentMsg & msg1 = *static_cast<const SMPMasterIdentMsg *>( &msg );
990  if( HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH == source.pb_flag ) {
991  // from responder (LL slave)
992  pairing_data.keys_resp_has |= SMPKeyType::ENC_KEY;
993  pairing_data.ltk_resp.ediv = msg1.getEDIV();
994  pairing_data.ltk_resp.rand = msg1.getRand();
995  } else {
996  // from initiator (LL master)
997  pairing_data.keys_init_has |= SMPKeyType::ENC_KEY;
998  pairing_data.ltk_init.ediv = msg1.getEDIV();
999  pairing_data.ltk_init.rand = msg1.getRand();
1000  }
1001  } break;
1002 
1003  case SMPPDUMsg::Opcode::IDENTITY_INFORMATION: { /* Legacy: 3; SC: 1 */
1004  // IRK: First part of SMPKeyDist::ID_KEY, followed by IDENTITY_ADDRESS_INFORMATION
1005  const SMPIdentInfoMsg & msg1 = *static_cast<const SMPIdentInfoMsg *>( &msg );
1006  if( HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH == source.pb_flag ) {
1007  // from responder (LL slave)
1008  pairing_data.irk_resp = msg1.getIRK();
1009  } else {
1010  // from initiator (LL master)
1011  pairing_data.irk_init = msg1.getIRK();
1012  }
1013  } break;
1014 
1015  case SMPPDUMsg::Opcode::IDENTITY_ADDRESS_INFORMATION:{/* Lecacy: 4; SC: 2 */
1016  // Public device or static random, completing SMPKeyDist::ID_KEY
1017  const SMPIdentAddrInfoMsg & msg1 = *static_cast<const SMPIdentAddrInfoMsg *>( &msg );
1018  if( HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH == source.pb_flag ) {
1019  // from responder (LL slave)
1020  pairing_data.keys_resp_has |= SMPKeyType::ID_KEY;
1021  pairing_data.address = msg1.getAddress();
1022  pairing_data.is_static_random_address = msg1.isStaticRandomAddress();
1023  } else {
1024  // from initiator (LL master)
1025  pairing_data.keys_init_has |= SMPKeyType::ID_KEY;
1026  pairing_data.address = msg1.getAddress();
1027  pairing_data.is_static_random_address = msg1.isStaticRandomAddress();
1028  }
1029  } break;
1030 
1031  case SMPPDUMsg::Opcode::SIGNING_INFORMATION: { /* Legacy: 5; SC: 3; Last value. */
1032  // CSRK
1033  const SMPSignInfoMsg & msg1 = *static_cast<const SMPSignInfoMsg *>( &msg );
1034  if( HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH == source.pb_flag ) {
1035  // from responder (LL slave)
1036  pairing_data.keys_resp_has |= SMPKeyType::SIGN_KEY;
1037 
1038  pairing_data.csrk_resp.properties |= SMPSignatureResolvingKeyInfo::Property::RESPONDER;
1039  if( BTSecurityLevel::ENC_AUTH <= pairing_data.sec_level_conn ) {
1040  pairing_data.csrk_resp.properties |= SMPSignatureResolvingKeyInfo::Property::AUTH;
1041  }
1042  pairing_data.csrk_resp.csrk = msg1.getCSRK();
1043  } else {
1044  // from initiator (LL master)
1045  pairing_data.keys_init_has |= SMPKeyType::SIGN_KEY;
1046 
1047  // pairing_data.csrk_init.properties |= SMPSignatureResolvingKeyInfo::Property::INITIATOR;
1048  if( BTSecurityLevel::ENC_AUTH <= pairing_data.sec_level_conn ) {
1049  pairing_data.csrk_init.properties |= SMPSignatureResolvingKeyInfo::Property::AUTH;
1050  }
1051  pairing_data.csrk_init.csrk = msg1.getCSRK();
1052  }
1053  } break;
1054 
1055  default:
1056  break;
1057  }
1058 
1059  if( checkPairingKeyDistributionComplete(timestamp) ) {
1060  pstate = SMPPairingState::COMPLETED;
1061  is_device_ready = true;
1062  }
1063 
1064  if( jau::environment::get().debug ) {
1065  if( old_pstate == pstate /* && old_pmode == pmode */ ) {
1066  jau::PLAIN_PRINT(false, "[%s] Debug: BTDevice:hci:SMP.4: Unchanged: address%s",
1067  timestamp.c_str(),
1068  addressAndType.toString().c_str());
1069  } else {
1070  jau::PLAIN_PRINT(false, "[%s] Debug: BTDevice:hci:SMP.5: Updated: address%s",
1071  timestamp.c_str(),
1072  addressAndType.toString().c_str());
1073  }
1074  jau::PLAIN_PRINT(false, "[%s] - state %s -> %s, mode %s -> %s, ready %d",
1075  timestamp.c_str(),
1076  to_string(old_pstate).c_str(), to_string(pstate).c_str(),
1077  to_string(old_pmode).c_str(), to_string(pmode).c_str(),
1078  is_device_ready);
1079  jau::PLAIN_PRINT(false, "[%s] - keys[init %s / %s, resp %s / %s]",
1080  timestamp.c_str(),
1081  to_string(pairing_data.keys_init_has).c_str(),
1082  to_string(pairing_data.keys_init_exp).c_str(),
1083  to_string(pairing_data.keys_resp_has).c_str(),
1084  to_string(pairing_data.keys_resp_exp).c_str());
1085  }
1086 
1087  if( old_pstate == pstate /* && old_pmode == pmode */ ) {
1088  return;
1089  }
1090 
1091  pairing_data.mode = pmode;
1092  pairing_data.state = pstate;
1093 
1094  adapter.sendDevicePairingState(sthis, pstate, pmode, msg.getTimestamp());
1095 
1096  if( is_device_ready ) {
1097  std::thread dc(&BTDevice::processDeviceReady, this, sthis, msg.getTimestamp()); // @suppress("Invalid arguments")
1098  dc.detach();
1099  }
1100  if( jau::environment::get().debug ) {
1101  jau::PLAIN_PRINT(false, "[%s] Debug: BTDevice:hci:SMP.6: End", timestamp.c_str());
1102  jau::PLAIN_PRINT(false, "[%s] - %s", timestamp.c_str(), toString().c_str());
1103  }
1104  cv_pairing_state_changed.notify_all();
1105 }
1106 
1107 SMPKeyType BTDevice::getAvailableSMPKeys(const bool responder) const noexcept {
1108  jau::sc_atomic_critical sync(sync_data);
1109  if( responder ) {
1110  return pairing_data.keys_resp_has;
1111  } else {
1112  return pairing_data.keys_init_has;
1113  }
1114 }
1115 
1116 SMPLongTermKeyInfo BTDevice::getLongTermKeyInfo(const bool responder) const noexcept {
1117  jau::sc_atomic_critical sync(sync_data);
1118  return responder ? pairing_data.ltk_resp : pairing_data.ltk_init;
1119 }
1120 
1122  if( isConnected ) {
1123  ERR_PRINT("BTDevice::setLongTermKeyInfo: Already connected: %s", toString().c_str());
1125  }
1126  const std::unique_lock<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor
1127  jau::sc_atomic_critical sync(sync_data);
1128  if( ltk.isResponder() ) {
1129  pairing_data.ltk_resp = ltk;
1130  } else {
1131  pairing_data.ltk_init = ltk;
1132  }
1133 #if USE_LINUX_BT_SECURITY
1134  BTManager & mngr = adapter.getManager();
1135  HCIStatusCode res = mngr.uploadLongTermKeyInfo(adapter.dev_id, addressAndType, ltk);
1136  return res;
1137 #elif SMP_SUPPORTED_BY_OS
1139 #else
1141 #endif
1142 }
1143 
1145  jau::sc_atomic_critical sync(sync_data);
1146  return responder ? pairing_data.csrk_resp : pairing_data.csrk_init;
1147 }
1148 
1150  /**
1151  * Experimental only.
1152  * <pre>
1153  * adapter.stopDiscovery(): Renders pairDevice(..) to fail: Busy!
1154  * pairDevice(..) behaves quite instable within our connected workflow: Not used!
1155  * </pre>
1156  */
1157  if( SMPIOCapability::UNSET == io_cap ) {
1158  DBG_PRINT("BTDevice::pairDevice: io %s, invalid value.", to_string(io_cap).c_str());
1160  }
1161 #if USE_LINUX_BT_SECURITY
1162  BTManager& mngr = adapter.getManager();
1163 
1164  DBG_PRINT("BTDevice::pairDevice: Start: io %s, %s", to_string(io_cap).c_str(), toString().c_str());
1165  mngr.uploadConnParam(adapter.dev_id, addressAndType);
1166 
1167  jau::sc_atomic_critical sync(sync_data);
1168  pairing_data.ioCap_conn = io_cap;
1169  const bool res = mngr.pairDevice(adapter.dev_id, addressAndType, io_cap);
1170  if( !res ) {
1171  pairing_data.ioCap_conn = SMPIOCapability::UNSET;
1172  }
1173  DBG_PRINT("BTDevice::pairDevice: End: io %s, %s", to_string(io_cap).c_str(), toString().c_str());
1175 #elif SMP_SUPPORTED_BY_OS
1177 #else
1179 #endif
1180 }
1181 
1182 bool BTDevice::setConnSecurityLevel(const BTSecurityLevel sec_level) noexcept {
1183  if( BTSecurityLevel::UNSET == sec_level ) {
1184  DBG_PRINT("DBTAdapter::setConnSecurityLevel: lvl %s, invalid value.", to_string(sec_level).c_str());
1185  return false;
1186  }
1187 
1188  if( !isValid() || isConnected || allowDisconnect ) {
1189  DBG_PRINT("BTDevice::setConnSecurityLevel: lvl %s failed, invalid state %s",
1190  to_string(sec_level).c_str(), toString().c_str());
1191  return false;
1192  }
1193  jau::sc_atomic_critical sync(sync_data);
1194  const bool res = true;
1195  pairing_data.sec_level_user = sec_level;
1196  pairing_data.ioCap_auto = SMPIOCapability::UNSET; // disable auto
1197 
1198  DBG_PRINT("BTDevice::setConnSecurityLevel: result %d: lvl %s, %s", res,
1199  to_string(sec_level).c_str(),
1200  toString().c_str());
1201  return res;
1202 }
1203 
1205  jau::sc_atomic_critical sync(sync_data);
1206  return pairing_data.sec_level_conn;
1207 }
1208 
1209 bool BTDevice::setConnIOCapability(const SMPIOCapability io_cap) noexcept {
1210  if( SMPIOCapability::UNSET == io_cap ) {
1211  DBG_PRINT("BTDevice::setConnIOCapability: io %s, invalid value.", to_string(io_cap).c_str());
1212  return false;
1213  }
1214 
1215  if( !isValid() || isConnected || allowDisconnect ) {
1216  DBG_PRINT("BTDevice::setConnIOCapability: io %s failed, invalid state %s",
1217  to_string(io_cap).c_str(), toString().c_str());
1218  return false;
1219  }
1220  jau::sc_atomic_critical sync(sync_data);
1221  const bool res = true;
1222  pairing_data.ioCap_user = io_cap;
1223  pairing_data.ioCap_auto = SMPIOCapability::UNSET; // disable auto
1224 
1225  DBG_PRINT("BTDevice::setConnIOCapability: result %d: io %s, %s", res,
1226  to_string(io_cap).c_str(),
1227  toString().c_str());
1228 
1229  return res;
1230 }
1231 
1233  jau::sc_atomic_critical sync(sync_data);
1234  return pairing_data.ioCap_conn;
1235 }
1236 
1237 bool BTDevice::setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap) noexcept {
1238  if( !isValid() || isConnected || allowDisconnect ) {
1239  DBG_PRINT("BTDevice::setConnSecurity: lvl %s, io %s failed, invalid state %s",
1240  to_string(sec_level).c_str(),
1241  to_string(io_cap).c_str(), toString().c_str());
1242  return false;
1243  }
1244  jau::sc_atomic_critical sync(sync_data);
1245  const bool res = true;
1246  pairing_data.ioCap_user = io_cap;
1247  pairing_data.sec_level_user = sec_level;
1248  pairing_data.ioCap_auto = SMPIOCapability::UNSET; // disable auto
1249 
1250  DBG_PRINT("BTDevice::setConnSecurity: result %d: lvl %s, io %s, %s", res,
1251  to_string(sec_level).c_str(),
1252  to_string(io_cap).c_str(),
1253  toString().c_str());
1254 
1255  return res;
1256 }
1257 
1258 bool BTDevice::setConnSecurityBest(const BTSecurityLevel sec_level, const SMPIOCapability io_cap) noexcept {
1259  if( BTSecurityLevel::UNSET < sec_level && SMPIOCapability::UNSET != io_cap ) {
1260  return setConnSecurity(sec_level, io_cap);
1261  } else if( BTSecurityLevel::UNSET < sec_level ) {
1262  if( BTSecurityLevel::ENC_ONLY >= sec_level ) {
1263  return setConnSecurity(sec_level, SMPIOCapability::NO_INPUT_NO_OUTPUT);
1264  } else {
1265  return setConnSecurityLevel(sec_level);
1266  }
1267  } else if( SMPIOCapability::UNSET != io_cap ) {
1268  return setConnIOCapability(io_cap);
1269  } else {
1270  return false;
1271  }
1272 }
1273 
1274 bool BTDevice::setConnSecurityAuto(const SMPIOCapability iocap_auto) noexcept {
1275  if( !isValid() || isConnected || allowDisconnect ) {
1276  DBG_PRINT("BTDevice::setConnSecurityAuto: io %s failed, invalid state %s",
1277  to_string(iocap_auto).c_str(), toString().c_str());
1278  return false;
1279  }
1280  if( BTSecurityLevel::UNSET != pairing_data.sec_level_user ||
1281  SMPIOCapability::UNSET != pairing_data.ioCap_user )
1282  {
1283  DBG_PRINT("BTDevice::setConnSecurityAuto: io %s failed, user connection sec_level %s or io %s set %s",
1284  to_string(iocap_auto).c_str(),
1285  to_string(pairing_data.sec_level_user).c_str(),
1286  to_string(pairing_data.ioCap_user).c_str(),
1287  toString().c_str());
1288  return false;
1289  }
1290 
1291  jau::sc_atomic_critical sync(sync_data);
1292  const bool res = true;
1293  pairing_data.ioCap_auto = iocap_auto;
1294  DBG_PRINT("BTDevice::setConnSecurityAuto: result %d: io %s, %s", res,
1295  to_string(iocap_auto).c_str(), toString().c_str());
1296  return res;
1297 }
1298 
1300  jau::sc_atomic_critical sync(sync_data);
1301  return SMPIOCapability::UNSET != pairing_data.ioCap_auto;
1302 }
1303 
1304 HCIStatusCode BTDevice::setPairingPasskey(const uint32_t passkey) noexcept {
1305  const std::unique_lock<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor
1306  jau::sc_atomic_critical sync(sync_data);
1307 
1309 #if USE_LINUX_BT_SECURITY
1310  BTManager& mngr = adapter.getManager();
1311  MgmtStatus res = mngr.userPasskeyReply(adapter.dev_id, addressAndType, passkey);
1312  DBG_PRINT("BTDevice:mgmt:SMP: PASSKEY '%d', state %s, result %s",
1313  passkey, to_string(pairing_data.state).c_str(), to_string(res).c_str());
1314  return HCIStatusCode::SUCCESS;
1315 #elif SMP_SUPPORTED_BY_OS
1317 #else
1319 #endif
1320  } else {
1321  ERR_PRINT("BTDevice:mgmt:SMP: PASSKEY '%d', state %s, SKIPPED (wrong state)",
1322  passkey, to_string(pairing_data.state).c_str());
1323  return HCIStatusCode::UNKNOWN;
1324  }
1325 }
1326 
1328  const std::unique_lock<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor
1329  jau::sc_atomic_critical sync(sync_data);
1330 
1332 #if USE_LINUX_BT_SECURITY
1333  BTManager& mngr = adapter.getManager();
1335  DBG_PRINT("BTDevice:mgmt:SMP: PASSKEY NEGATIVE, state %s, result %s",
1336  to_string(pairing_data.state).c_str(), to_string(res).c_str());
1337  return HCIStatusCode::SUCCESS;
1338 #elif SMP_SUPPORTED_BY_OS
1340 #else
1342 #endif
1343  } else {
1344  ERR_PRINT("BTDevice:mgmt:SMP: PASSKEY NEGATIVE, state %s, SKIPPED (wrong state)",
1345  to_string(pairing_data.state).c_str());
1346  return HCIStatusCode::UNKNOWN;
1347  }
1348 }
1349 
1351  const std::unique_lock<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor
1352  jau::sc_atomic_critical sync(sync_data);
1353 
1355 #if USE_LINUX_BT_SECURITY
1356  BTManager& mngr = adapter.getManager();
1357  MgmtStatus res = mngr.userConfirmReply(adapter.dev_id, addressAndType, positive);
1358  DBG_PRINT("BTDevice:mgmt:SMP: CONFIRM '%d', state %s, result %s",
1359  positive, to_string(pairing_data.state).c_str(), to_string(res).c_str());
1360  return HCIStatusCode::SUCCESS;
1361 #elif SMP_SUPPORTED_BY_OS
1363 #else
1365 #endif
1366  } else {
1367  ERR_PRINT("BTDevice:mgmt:SMP: CONFIRM '%d', state %s, SKIPPED (wrong state)",
1368  positive, to_string(pairing_data.state).c_str());
1369  return HCIStatusCode::UNKNOWN;
1370  }
1371 }
1372 
1374  jau::sc_atomic_critical sync(sync_data);
1375  return pairing_data.mode;
1376 }
1377 
1379  jau::sc_atomic_critical sync(sync_data);
1380  return pairing_data.state;
1381 }
1382 
1383 void BTDevice::clearSMPStates(const bool connected) noexcept {
1384  const std::unique_lock<std::mutex> lock(mtx_pairing); // RAII-style acquire and relinquish via destructor
1385  jau::sc_atomic_critical sync(sync_data);
1386 
1387  DBG_PRINT("BTDevice::clearSMPStates: Had: %s", toString().c_str());
1388 
1389  if( !connected ) {
1390  // needs to survive connected, or will be set right @ connected
1391  pairing_data.ioCap_user = SMPIOCapability::UNSET;
1392  pairing_data.ioCap_conn = SMPIOCapability::UNSET;
1393  pairing_data.sec_level_user = BTSecurityLevel::UNSET;
1394  // Keep alive: pairing_data.ioCap_auto = SMPIOCapability::UNSET;
1395  }
1396  pairing_data.sec_level_conn = BTSecurityLevel::UNSET;
1397 
1398  pairing_data.state = SMPPairingState::NONE;
1399  pairing_data.mode = PairingMode::NONE;
1400  pairing_data.res_requested_sec = false;
1401  pairing_data.use_sc = false;
1402 
1403  pairing_data.authReqs_resp = SMPAuthReqs::NONE;
1404  pairing_data.ioCap_resp = SMPIOCapability::NO_INPUT_NO_OUTPUT;
1405  pairing_data.oobFlag_resp = SMPOOBDataFlag::OOB_AUTH_DATA_NOT_PRESENT;
1406  pairing_data.maxEncsz_resp = 0;
1407  pairing_data.keys_resp_exp = SMPKeyType::NONE;
1408  pairing_data.keys_resp_has = SMPKeyType::NONE;
1409  pairing_data.ltk_resp.clear();
1410  pairing_data.irk_resp.clear();
1411  // pairing_data.address;
1412  // pairing_data.is_static_random_address;
1413  pairing_data.csrk_resp.clear();
1414 
1415  pairing_data.authReqs_init = SMPAuthReqs::NONE;
1416  pairing_data.ioCap_init = SMPIOCapability::NO_INPUT_NO_OUTPUT;
1417  pairing_data.oobFlag_init = SMPOOBDataFlag::OOB_AUTH_DATA_NOT_PRESENT;
1418  pairing_data.maxEncsz_init = 0;
1419  pairing_data.keys_init_exp = SMPKeyType::NONE;
1420  pairing_data.keys_init_has = SMPKeyType::NONE;
1421  pairing_data.ltk_init.clear();
1422  pairing_data.irk_init.clear();
1423  pairing_data.csrk_init.clear();
1424 }
1425 
1426 void BTDevice::disconnectSMP(const int caller) noexcept {
1427  #if SMP_SUPPORTED_BY_OS
1428  const std::lock_guard<std::recursive_mutex> lock_conn(mtx_smpHandler);
1429  if( nullptr != smpHandler ) {
1430  DBG_PRINT("BTDevice::disconnectSMP: start (has smpHandler, caller %d)", caller);
1431  smpHandler->disconnect(false /* disconnectDevice */, false /* ioErrorCause */);
1432  } else {
1433  DBG_PRINT("BTDevice::disconnectSMP: start (nil smpHandler, caller %d)", caller);
1434  }
1435  smpHandler = nullptr;
1436  DBG_PRINT("BTDevice::disconnectSMP: end");
1437  #else
1438  (void)caller;
1439  #endif
1440 }
1441 
1442 bool BTDevice::connectSMP(std::shared_ptr<BTDevice> sthis, const BTSecurityLevel sec_level) noexcept {
1443  #if SMP_SUPPORTED_BY_OS
1444  if( !isConnected || !allowDisconnect) {
1445  ERR_PRINT("BTDevice::connectSMP(%u): Device not connected: %s", sec_level, toString().c_str());
1446  return false;
1447  }
1448 
1450  DBG_PRINT("BTDevice::connectSMP(%u): SMP Not supported by OS (1): %s", sec_level, toString().c_str());
1451  return false;
1452  }
1453 
1454  if( BTSecurityLevel::NONE >= sec_level ) {
1455  return false;
1456  }
1457 
1458  const std::lock_guard<std::recursive_mutex> lock_conn(mtx_gattHandler);
1459  if( nullptr != smpHandler ) {
1460  if( smpHandler->isConnected() ) {
1461  return smpHandler->establishSecurity(sec_level);
1462  }
1463  smpHandler = nullptr;
1464  }
1465 
1466  smpHandler = std::make_shared<SMPHandler>(sthis);
1467  if( !smpHandler->isConnected() ) {
1468  ERR_PRINT("BTDevice::connectSMP: Connection failed");
1469  smpHandler = nullptr;
1470  return false;
1471  }
1472  return smpHandler->establishSecurity(sec_level);
1473  #else
1474  DBG_PRINT("BTDevice::connectSMP: SMP Not supported by OS (0): %s", toString().c_str());
1475  (void)sthis;
1476  (void)sec_level;
1477  return false;
1478  #endif
1479 }
1480 
1481 void BTDevice::disconnectGATT(const int caller) noexcept {
1482  const std::lock_guard<std::recursive_mutex> lock_conn(mtx_gattHandler);
1483  if( nullptr != gattHandler ) {
1484  DBG_PRINT("BTDevice::disconnectGATT: start (has gattHandler, caller %d)", caller);
1485  gattHandler->disconnect(false /* disconnectDevice */, false /* ioErrorCause */);
1486  } else {
1487  DBG_PRINT("BTDevice::disconnectGATT: start (nil gattHandler, caller %d)", caller);
1488  }
1489  gattHandler = nullptr;
1490  DBG_PRINT("BTDevice::disconnectGATT: end");
1491 }
1492 
1493 bool BTDevice::connectGATT(std::shared_ptr<BTDevice> sthis) noexcept {
1494  if( !isConnected || !allowDisconnect) {
1495  ERR_PRINT("BTDevice::connectGATT: Device not connected: %s", toString().c_str());
1496  return false;
1497  }
1498  if( !l2cap_att.isOpen() ) {
1499  ERR_PRINT("BTDevice::connectGATT: L2CAP not open: %s", toString().c_str());
1500  return false;
1501  }
1502 
1503  const std::lock_guard<std::recursive_mutex> lock_conn(mtx_gattHandler);
1504  if( nullptr != gattHandler ) {
1505  if( gattHandler->isConnected() ) {
1506  return true;
1507  }
1508  gattHandler = nullptr;
1509  }
1510 
1511  gattHandler = std::make_shared<BTGattHandler>(sthis, l2cap_att);
1512  if( !gattHandler->isConnected() ) {
1513  ERR_PRINT2("BTDevice::connectGATT: Connection failed");
1514  gattHandler = nullptr;
1515  return false;
1516  }
1517  return true;
1518 }
1519 
1520 std::shared_ptr<BTGattHandler> BTDevice::getGattHandler() noexcept {
1521  const std::lock_guard<std::recursive_mutex> lock_conn(mtx_gattHandler);
1522  return gattHandler;
1523 }
1524 
1526  std::shared_ptr<BTGattHandler> gh = getGattHandler();
1527  if( nullptr == gh ) {
1528  ERR_PRINT("BTDevice::getGATTServices: GATTHandler nullptr");
1530  }
1532  if( gattServices.size() > 0 ) { // reuse previous discovery result
1533  return gattServices;
1534  }
1535  try {
1536  gattServices = gh->discoverCompletePrimaryServices(gh); // same reference of the GATTHandler's list
1537  if( gattServices.size() == 0 ) { // nothing discovered
1538  return gattServices;
1539  }
1540 
1541  // discovery success, parse GenericAccess
1542  std::shared_ptr<GattGenericAccessSvc> gattGenericAccess = gh->getGenericAccess();
1543  if( nullptr != gattGenericAccess ) {
1544  const uint64_t ts = jau::getCurrentMilliseconds();
1545  EIRDataType updateMask = update(*gattGenericAccess, ts);
1546  DBG_PRINT("BTDevice::getGATTServices: updated %s:\n %s\n -> %s",
1547  to_string(updateMask).c_str(), gattGenericAccess->toString().c_str(), toString().c_str());
1548  if( EIRDataType::NONE != updateMask ) {
1549  std::shared_ptr<BTDevice> sharedInstance = getSharedInstance();
1550  if( nullptr == sharedInstance ) {
1551  ERR_PRINT("BTDevice::getGATTServices: Device unknown to adapter and not tracked: %s", toString().c_str());
1552  } else {
1553  adapter.sendDeviceUpdated("getGATTServices", sharedInstance, ts, updateMask);
1554  }
1555  }
1556  }
1557  } catch (std::exception &e) {
1558  WARN_PRINT("BTDevice::getGATTServices: Caught exception: '%s' on %s", e.what(), toString().c_str());
1559  }
1560  return gattServices;
1561 }
1562 
1563 std::shared_ptr<BTGattService> BTDevice::findGattService(std::shared_ptr<uuid_t> const &uuid) {
1564  const jau::darray<std::shared_ptr<BTGattService>> & gattServices = getGattServices(); // reference of the GATTHandler's list
1565  const size_t size = gattServices.size();
1566  for (size_t i = 0; i < size; i++) {
1567  const std::shared_ptr<BTGattService> & e = gattServices[i];
1568  if ( nullptr != e && *uuid == *(e->type) ) {
1569  return e;
1570  }
1571  }
1572  return nullptr;
1573 }
1574 
1575 bool BTDevice::pingGATT() noexcept {
1576  std::shared_ptr<BTGattHandler> gh = getGattHandler();
1577  if( nullptr == gh || !gh->isConnected() ) {
1578  jau::INFO_PRINT("BTDevice::pingGATT: GATTHandler not connected -> disconnected on %s", toString().c_str());
1580  return false;
1581  }
1582  try {
1583  return gh->ping();
1584  } catch (std::exception &e) {
1585  IRQ_PRINT("BTDevice::pingGATT: Potential disconnect, exception: '%s' on %s", e.what(), toString().c_str());
1586  }
1587  return false;
1588 }
1589 
1590 std::shared_ptr<GattGenericAccessSvc> BTDevice::getGattGenericAccess() {
1591  std::shared_ptr<BTGattHandler> gh = getGattHandler();
1592  if( nullptr == gh ) {
1593  ERR_PRINT("BTDevice::getGATTGenericAccess: GATTHandler nullptr");
1594  return nullptr;
1595  }
1596  return gh->getGenericAccess();
1597 }
1598 
1599 bool BTDevice::addCharListener(std::shared_ptr<BTGattCharListener> l) {
1600  std::shared_ptr<BTGattHandler> gatt = getGattHandler();
1601  if( nullptr == gatt ) {
1602  throw jau::IllegalStateException("Device's GATTHandle not connected: "+
1603  toString(), E_FILE_LINE);
1604  }
1605  return gatt->addCharListener(l);
1606 }
1607 
1608 bool BTDevice::removeCharListener(std::shared_ptr<BTGattCharListener> l) noexcept {
1609  std::shared_ptr<BTGattHandler> gatt = getGattHandler();
1610  if( nullptr == gatt ) {
1611  // OK to have GATTHandler being shutdown @ disable
1612  DBG_PRINT("Device's GATTHandle not connected: %s", toString().c_str());
1613  return false;
1614  }
1615  return gatt->removeCharListener(l);
1616 }
1617 
1618 int BTDevice::removeAllAssociatedCharListener(std::shared_ptr<BTGattChar> associatedCharacteristic) noexcept {
1619  std::shared_ptr<BTGattHandler> gatt = getGattHandler();
1620  if( nullptr == gatt ) {
1621  // OK to have GATTHandler being shutdown @ disable
1622  DBG_PRINT("Device's GATTHandle not connected: %s", toString().c_str());
1623  return false;
1624  }
1625  return gatt->removeAllAssociatedCharListener( associatedCharacteristic );
1626 }
1627 
1628 int BTDevice::removeAllAssociatedCharListener(const BTGattChar * associatedCharacteristic) noexcept {
1629  std::shared_ptr<BTGattHandler> gatt = getGattHandler();
1630  if( nullptr == gatt ) {
1631  // OK to have GATTHandler being shutdown @ disable
1632  DBG_PRINT("Device's GATTHandle not connected: %s", toString().c_str());
1633  return false;
1634  }
1635  return gatt->removeAllAssociatedCharListener( associatedCharacteristic );
1636 }
1637 
1639  std::shared_ptr<BTGattHandler> gatt = getGattHandler();
1640  if( nullptr == gatt ) {
1641  // OK to have GATTHandler being shutdown @ disable
1642  DBG_PRINT("Device's GATTHandle not connected: %s", toString().c_str());
1643  return 0;
1644  }
1645  return gatt->removeAllCharListener();
1646 }
1647 
1649  const std::lock_guard<std::recursive_mutex> lock_conn(mtx_connect); // RAII-style acquire and relinquish via destructor
1650 
1652  HCIHandler &hci = adapter.getHCI();
1653 
1654  if( !isConnected ) { // should not happen
1656  goto errout;
1657  }
1658 
1659  if( 0 == hciConnHandle ) {
1661  goto errout;
1662  }
1663 
1664  if( !adapter.isPowered() ) {
1665  res = HCIStatusCode::NOT_POWERED; // powered-off
1666  goto errout;
1667  }
1668 
1669  res = hci.le_read_phy(hciConnHandle.load(), addressAndType, resRx, resTx);
1670  if( HCIStatusCode::SUCCESS == res ) {
1671  DBG_PRINT("BTDevice::getConnectedLE_PHY: status %s: RX %s, TX %s - %s",
1672  to_string(res).c_str(),
1673  to_string(resRx).c_str(), to_string(resTx).c_str(), toString().c_str());
1674  return res;
1675  }
1676 
1677 errout:
1678  ERR_PRINT("BTDevice::getConnectedLE_PHY: status %s: RX %s, TX %s - %s",
1679  to_string(res).c_str(),
1680  to_string(resRx).c_str(), to_string(resTx).c_str(), toString().c_str());
1681  return res;
1682 }
1683 
1684 void BTDevice::notifyDisconnected() noexcept {
1685  // coming from disconnect callback, ensure cleaning up!
1686  DBG_PRINT("BTDevice::notifyDisconnected: handle %s -> zero, %s",
1687  jau::to_hexstring(hciConnHandle).c_str(), toString().c_str());
1688  clearSMPStates(false /* connected */);
1689  allowDisconnect = false;
1690  isConnected = false;
1691  hciConnHandle = 0;
1692  disconnectGATT(1);
1693  disconnectSMP(1);
1694  l2cap_att.close();
1695 }
1696 
1697 void BTDevice::sendMgmtEvDeviceDisconnected(std::unique_ptr<MgmtEvent> evt) noexcept {
1698  adapter.mgmtEvDeviceDisconnectedHCI(*evt);
1699 }
1700 
1702  // Avoid disconnect re-entry lock-free
1703  bool expConn = true; // C++11, exp as value since C++20
1704  if( !allowDisconnect.compare_exchange_strong(expConn, false) ) {
1705  // Not connected or disconnect already in process.
1706  DBG_PRINT("BTDevice::disconnect: Not connected: isConnected %d/%d, reason 0x%X (%s), gattHandler %d, hciConnHandle %s",
1707  allowDisconnect.load(), isConnected.load(),
1708  static_cast<uint8_t>(reason), to_string(reason).c_str(),
1709  (nullptr != gattHandler), jau::to_hexstring(hciConnHandle).c_str());
1711  }
1712  if( !isConnected ) { // should not happen
1713  WARN_PRINT("BTDevice::disconnect: allowConnect true -> false, but !isConnected on %s", toString().c_str());
1714  return HCIStatusCode::SUCCESS;
1715  }
1716 
1717  // Disconnect GATT and SMP before device, keeping reversed initialization order intact if possible.
1718  // This outside mtx_connect, keeping same mutex lock order intact as well
1719  disconnectGATT(0);
1720  disconnectSMP(0);
1721 
1722  // Lock to avoid other threads connecting while disconnecting
1723  const std::lock_guard<std::recursive_mutex> lock_conn(mtx_connect); // RAII-style acquire and relinquish via destructor
1724 
1725  WORDY_PRINT("BTDevice::disconnect: Start: isConnected %d/%d, reason 0x%X (%s), gattHandler %d, hciConnHandle %s",
1726  allowDisconnect.load(), isConnected.load(),
1727  static_cast<uint8_t>(reason), to_string(reason).c_str(),
1728  (nullptr != gattHandler), jau::to_hexstring(hciConnHandle).c_str());
1729 
1730  HCIHandler &hci = adapter.getHCI();
1732 
1733  if( 0 == hciConnHandle ) {
1735  goto exit;
1736  }
1737 
1738  if( !adapter.isPowered() ) {
1739  WARN_PRINT("BTDevice::disconnect: Adapter not powered: %s, %s", adapter.toString().c_str(), toString().c_str());
1740  res = HCIStatusCode::NOT_POWERED; // powered-off
1741  goto exit;
1742  }
1743 
1744  res = hci.disconnect(hciConnHandle.load(), addressAndType, reason);
1745  if( HCIStatusCode::SUCCESS != res ) {
1746  ERR_PRINT("BTDevice::disconnect: status %s, handle 0x%X, isConnected %d/%d: errno %d %s on %s",
1747  to_string(res).c_str(), hciConnHandle.load(),
1748  allowDisconnect.load(), isConnected.load(),
1749  errno, strerror(errno),
1750  toString().c_str());
1751  }
1752 
1753 exit:
1754  if( HCIStatusCode::SUCCESS != res ) {
1755  // In case of an already pulled or disconnected HCIHandler (e.g. power-off)
1756  // or in case the hci->disconnect() itself fails,
1757  // send the DISCONN_COMPLETE event directly.
1758  // SEND_EVENT: Perform off-thread to avoid potential deadlock w/ application callbacks (similar when sent from HCIHandler's reader-thread)
1759  std::thread bg(&BTDevice::sendMgmtEvDeviceDisconnected, this, // @suppress("Invalid arguments")
1760  std::make_unique<MgmtEvtDeviceDisconnected>(adapter.dev_id, addressAndType, reason, hciConnHandle.load()) );
1761  bg.detach();
1762  // adapter.mgmtEvDeviceDisconnectedHCI( std::unique_ptr<MgmtEvent>( new MgmtEvtDeviceDisconnected(adapter.dev_id, address, addressType, reason, hciConnHandle.load()) ) );
1763  }
1764  WORDY_PRINT("BTDevice::disconnect: End: status %s, handle 0x%X, isConnected %d/%d on %s",
1765  to_string(res).c_str(),
1766  hciConnHandle.load(), allowDisconnect.load(), isConnected.load(),
1767  toString().c_str());
1768 
1769  return res;
1770 }
1771 
1773 #if USE_LINUX_BT_SECURITY
1774  const MgmtStatus res = adapter.getManager().unpairDevice(adapter.dev_id, addressAndType, false /* disconnect */);
1775  clearSMPStates(false /* connected */);
1776  return to_HCIStatusCode(res);
1777 #elif SMP_SUPPORTED_BY_OS
1779 #else
1781 #endif
1782 }
1783 
1784 void BTDevice::remove() noexcept {
1785  clearSMPStates(false /* connected */);
1786  adapter.removeDevice(*this);
1787 }
direct_bt::SMPIOCapability::UNSET
@ UNSET
Denoting unset value, i.e.
direct_bt::SMPPDUMsg::Opcode::PAIRING_CONFIRM
@ PAIRING_CONFIRM
direct_bt::SMPIdentAddrInfoMsg::getAddress
EUI48 getAddress() const noexcept
Returns the device address.
Definition: SMPTypes.hpp:1691
jau::environment::get
static environment & get(const std::string root_prefix_domain="jau") noexcept
Static singleton initialization of this project's environment with the given global root prefix_domai...
Definition: environment.hpp:234
direct_bt::BTDevice::connectDefault
HCIStatusCode connectDefault() noexcept
Establish a default HCI connection to this device, using certain default parameter.
Definition: BTDevice.cpp:532
direct_bt::MgmtEvent::Opcode::NEW_LONG_TERM_KEY
@ NEW_LONG_TERM_KEY
direct_bt::BTGattHandler::removeAllCharListener
int removeAllCharListener() noexcept
Remove all event listener from the list.
Definition: BTGattHandler.cpp:166
direct_bt::SMPMasterIdentMsg::getEDIV
constexpr uint16_t getEDIV() const noexcept
Returns the 16-bit EDIV value (2 octets) being distributed.
Definition: SMPTypes.hpp:1546
direct_bt::LE_Features::NONE
@ NONE
NONE.
direct_bt::HCIStatusCode::UNACCEPTABLE_CONNECTION_PARAM
@ UNACCEPTABLE_CONNECTION_PARAM
direct_bt::BTDevice::getPairingMode
PairingMode getPairingMode() const noexcept
Returns the current PairingMode used by the device.
Definition: BTDevice.cpp:1373
jau::to_decstring
std::string to_decstring(const value_type &v, const char separator=',', const nsize_t width=0) noexcept
Produce a decimal string representation of an integral integer value.
Definition: string_util.hpp:143
IRQ_PRINT
#define IRQ_PRINT(...)
Use for unconditional interruption messages, prefix '[elapsed_time] Interrupted @ FILE:LINE: '.
Definition: debug.hpp:138
direct_bt::BTDevice::remove
void remove() noexcept
Disconnects this device via disconnect(..) if getConnected()==true and explicitly removes its shared ...
Definition: BTDevice.cpp:1784
direct_bt::HCIStatusCode::ALREADY_PAIRED
@ ALREADY_PAIRED
direct_bt::BTGattHandler::getServices
jau::darray< BTGattServiceRef > & getServices() noexcept
Returns a reference of the internal kept BTGattService list.
Definition: BTGattHandler.hpp:314
direct_bt::BTDevice::getPairingState
SMPPairingState getPairingState() const noexcept
Returns the current SMPPairingState.
Definition: BTDevice.cpp:1378
direct_bt::GattGenericAccessSvc::toString
std::string toString() const noexcept
Definition: GATTNumbers.cpp:382
direct_bt::BTDevice::setConnSecurityAuto
bool setConnSecurityAuto(const SMPIOCapability iocap_auto) noexcept
Set automatic security negotiation of BTSecurityLevel and SMPIOCapability pairing mode.
Definition: BTDevice.cpp:1274
direct_bt::BTDevice::getSignatureResolvingKeyInfo
SMPSignatureResolvingKeyInfo getSignatureResolvingKeyInfo(const bool responder) const noexcept
Returns a copy of the Signature Resolving Key (LTK) info, valid after connection and SMP pairing has ...
Definition: BTDevice.cpp:1144
direct_bt::PairingMode::NUMERIC_COMPARE_ini
@ NUMERIC_COMPARE_ini
Visual comparison of digit sequence (PIN) input by initiator, shown on both devices.
direct_bt::ConnectionInfo::getRSSI
int8_t getRSSI() const noexcept
Definition: BTTypes1.hpp:91
le_scan_interval
static const uint16_t le_scan_interval
Definition: dbt_scanner10.cpp:633
direct_bt::HCIACLData::l2cap_frame
Representing ACL Datas' L2CAP Frame.
Definition: HCITypes.hpp:672
direct_bt::EIRDataType
EIRDataType
Bit mask of 'Extended Inquiry Response' (EIR) data fields, indicating a set of related data.
Definition: BTTypes0.hpp:752
ERR_PRINT2
#define ERR_PRINT2(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE: '.
Definition: debug.hpp:135
direct_bt::HCIACLData::l2cap_frame::PBFlag::START_AUTOFLUSH
@ START_AUTOFLUSH
0b10: Start of an automatically flushable PDU.
direct_bt::BTDevice::getLongTermKeyInfo
SMPLongTermKeyInfo getLongTermKeyInfo(const bool responder) const noexcept
Returns a copy of the Long Term Key (LTK) info, valid after connection and SMP pairing has been compl...
Definition: BTDevice.cpp:1116
direct_bt::L2CAP_CID
L2CAP_CID
Definition: BTTypes0.hpp:432
direct_bt::SMPKeyType
SMPKeyType
SMP Key Type for Distribution, indicates keys distributed in the Transport Specific Key Distribution ...
Definition: SMPTypes.hpp:385
direct_bt::EInfoReport
Collection of 'Extended Advertising Data' (EAD), 'Advertising Data' (AD) or 'Extended Inquiry Respons...
Definition: BTTypes0.hpp:803
direct_bt::SMPEncInfoMsg::getLTK
constexpr jau::uint128_t getLTK() const noexcept
Returns the 128-bit Long Term Key (16 octets)
Definition: SMPTypes.hpp:1477
direct_bt::SMPPairingState::PASSKEY_EXPECTED
@ PASSKEY_EXPECTED
Phase 2: Authentication (MITM) PASSKEY expected now, see PairingMode::PASSKEY_ENTRY_ini.
direct_bt::HCIHandler::create_conn
HCIStatusCode create_conn(const EUI48 &bdaddr, const uint16_t pkt_type=HCI_DM1|HCI_DM3|HCI_DM5|HCI_DH1|HCI_DH3|HCI_DH5, const uint16_t clock_offset=0x0000, const uint8_t role_switch=0x01) noexcept
Establish a connection to the given BREDR (non LE).
Definition: HCIHandler.cpp:1203
BTManager.hpp
direct_bt::HCIStatusCode::NOT_POWERED
@ NOT_POWERED
jau::IllegalArgumentException
Definition: basic_types.hpp:111
direct_bt::SMPLongTermKeyInfo::Property::AUTH
@ AUTH
Authentication used.
direct_bt::LE_Features::LE_Encryption
@ LE_Encryption
LE_Encryption.
direct_bt::BTDevice::~BTDevice
~BTDevice() noexcept
Releases this instance after calling remove().
Definition: BTDevice.cpp:82
direct_bt::SMPKeyType::ID_KEY
@ ID_KEY
Indicates that the device shall distribute IRK using the Identity Information command followed by its...
direct_bt::EIRDataType::BDADDR_TYPE
@ BDADDR_TYPE
direct_bt::EIRDataType::BDADDR
@ BDADDR
direct_bt::SMPLongTermKeyInfo::toString
std::string toString() const noexcept
Definition: SMPTypes.hpp:522
direct_bt::SMPEncInfoMsg
Vol 3, Part H: 3.6.2 Encryption Information message.
Definition: SMPTypes.hpp:1452
direct_bt::BTDevice::addCharListener
bool addCharListener(std::shared_ptr< BTGattCharListener > l)
Add the given BTGattCharListener to the listener list if not already present.
Definition: BTDevice.cpp:1599
direct_bt::SMPPDUMsg::Opcode::PAIRING_FAILED
@ PAIRING_FAILED
direct_bt::PairingMode::NONE
@ NONE
No pairing mode, implying no secure connections, no encryption and no MITM protection.
direct_bt::BLERandomAddressType
BLERandomAddressType
BT Core Spec v5.2: Vol 6 LE, Part B Link Layer Specification: 1.3 Device Address.
Definition: BTAddress.hpp:89
direct_bt
Definition: ATTPDUTypes.hpp:171
direct_bt::EIRDataType::SERVICE_UUID
@ SERVICE_UUID
jau::environment::getElapsedMillisecond
static uint64_t getElapsedMillisecond() noexcept
Returns current elapsed monotonic time in milliseconds since module startup, see startupTimeMilliseco...
Definition: environment.hpp:80
direct_bt::BTGattChar
Definition: BTGattChar.hpp:75
direct_bt::BTDevice::setConnSecurity
bool setConnSecurity(const BTSecurityLevel sec_level, const SMPIOCapability io_cap) noexcept
Sets the given BTSecurityLevel and SMPIOCapability used to connect to this device on the upcoming con...
Definition: BTDevice.cpp:1237
direct_bt::BTDevice::getConnectedLE_PHY
HCIStatusCode getConnectedLE_PHY(LE_PHYs &resRx, LE_PHYs &resTx) noexcept
Request and return LE_PHYs bit for the given connection.
Definition: BTDevice.cpp:1648
direct_bt::MgmtEvent::Opcode
Opcode
Definition: MgmtTypes.hpp:1085
direct_bt::BTDevice::setPairingNumericComparison
HCIStatusCode setPairingNumericComparison(const bool equal) noexcept
Method sets the numeric comparison result, see PairingMode::NUMERIC_COMPARE_ini.
Definition: BTDevice.cpp:1350
direct_bt::SMPPairingState::OOB_EXPECTED
@ OOB_EXPECTED
Phase 2: Authentication (MITM) OOB data expected now, see PairingMode::OUT_OF_BAND.
direct_bt::SMPPDUMsg::Opcode::SECURITY_REQUEST
@ SECURITY_REQUEST
direct_bt::BTDevice::pingGATT
bool pingGATT() noexcept
Issues a GATT ping to the device, validating whether it is still reachable.
Definition: BTDevice.cpp:1575
direct_bt::BTDevice::connectLE
HCIStatusCode connectLE(const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24, const uint16_t conn_interval_min=12, const uint16_t conn_interval_max=12, const uint16_t conn_latency=0, const uint16_t supervision_timeout=getHCIConnSupervisorTimeout(0, 15)) noexcept
Establish a HCI BDADDR_LE_PUBLIC or BDADDR_LE_RANDOM connection to this device.
Definition: BTDevice.cpp:283
direct_bt::HCIHandler::disconnect
HCIStatusCode disconnect(const uint16_t conn_handle, const BDAddressAndType &addressAndType, const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION) noexcept
Disconnect an established connection.
Definition: HCIHandler.cpp:1275
direct_bt::SMPPairingState::KEY_DISTRIBUTION
@ KEY_DISTRIBUTION
Phase 3: Key & value distribution started after SMPPairConfirmMsg or SMPPairPubKeyMsg (LE Secure Conn...
direct_bt::isSMPPairingAllowingInput
constexpr bool isSMPPairingAllowingInput(const SMPPairingState state, const SMPPairingState inputSpec) noexcept
Returns true if the given SMPPairingState indicates a pairing process waiting for user input,...
Definition: SMPTypes.hpp:176
direct_bt::SMPIdentAddrInfoMsg
Vol 3, Part H: 3.6.5 Identity Address Information message.
Definition: SMPTypes.hpp:1664
direct_bt::SMPAuthReqs::NONE
@ NONE
direct_bt::BDAddressAndType::toString
std::string toString() const noexcept
Definition: BTTypes0.cpp:333
direct_bt::setEIRDataTypeSet
constexpr void setEIRDataTypeSet(EIRDataType &mask, const EIRDataType bit) noexcept
Definition: BTTypes0.hpp:785
direct_bt::BTDevice::getManufactureSpecificData
std::shared_ptr< ManufactureSpecificData > const getManufactureSpecificData() const noexcept
Return shared ManufactureSpecificData as recognized at discovery, pre GATT discovery.
Definition: BTDevice.cpp:130
direct_bt::BTDevice::getConnIOCapability
SMPIOCapability getConnIOCapability() const noexcept
Return the set SMPIOCapability value, determined when the connection is established.
Definition: BTDevice.cpp:1232
direct_bt::uuid_t::getTypeSize
TypeSize getTypeSize() const noexcept
Definition: UUID.hpp:88
direct_bt::SMPHandler::IS_SUPPORTED_BY_OS
static bool IS_SUPPORTED_BY_OS
Linux/BlueZ prohibits access to the existing SMP implementation via L2CAP (socket).
Definition: SMPHandler.hpp:174
direct_bt::BTSecurityLevel::NONE
@ NONE
No encryption and no authentication.
direct_bt::HCILEPeerAddressType::PUBLIC
@ PUBLIC
Public Device Address.
direct_bt::SMPKeyType::SIGN_KEY
@ SIGN_KEY
Indicates that the device shall distribute CSRK using the Signing Information command.
direct_bt::BTDevice::connectBREDR
HCIStatusCode connectBREDR(const uint16_t pkt_type=HCI_DM1|HCI_DM3|HCI_DM5|HCI_DH1|HCI_DH3|HCI_DH5, const uint16_t clock_offset=0x0000, const uint8_t role_switch=0x01) noexcept
Establish a HCI BDADDR_BREDR connection to this device.
Definition: BTDevice.cpp:492
direct_bt::EIRDataType::NONE
@ NONE
direct_bt::BTDevice::toString
std::string toString() const noexcept override
Definition: BTDevice.hpp:303
direct_bt::HCIHandler
A thread safe singleton handler of the HCI control channel to one controller (BT adapter)
Definition: HCIHandler.hpp:171
direct_bt::SMPPDUMsg::Opcode::MASTER_IDENTIFICATION
@ MASTER_IDENTIFICATION
direct_bt::BTAdapter::dev_id
const uint16_t dev_id
Adapter's internal temporary device id.
Definition: BTAdapter.hpp:273
jau::to_string
PRAGMA_DISABLE_WARNING_POP constexpr_cxx20 std::string to_string(const endian &v) noexcept
Return std::string representation of the given jau::endian.
Definition: byte_util.hpp:198
direct_bt::BTSecurityLevel::ENC_AUTH_FIPS
@ ENC_AUTH_FIPS
Authenticated Secure Connections.
direct_bt::EInfoReport::getAddressType
BDAddressType getAddressType() const noexcept
Definition: BTTypes0.hpp:940
jau::environment::debug
const bool debug
Debug logging enabled or disabled.
Definition: environment.hpp:269
direct_bt::SMPPDUMsg::Opcode::IDENTITY_ADDRESS_INFORMATION
@ IDENTITY_ADDRESS_INFORMATION
direct_bt::BTSecurityLevel
BTSecurityLevel
Bluetooth Security Level.
Definition: BTTypes0.hpp:211
direct_bt::SMPIOCapability::NO_INPUT_NO_OUTPUT
@ NO_INPUT_NO_OUTPUT
No input not output, value 3.
direct_bt::HCILEPeerAddressType::PUBLIC_IDENTITY
@ PUBLIC_IDENTITY
Public Resolved Identity Address.
direct_bt::BTManager::pairDevice
bool pairDevice(const uint16_t dev_id, const BDAddressAndType &addressAndType, const SMPIOCapability iocap) noexcept
Definition: BTManager.cpp:937
direct_bt::SMPLongTermKeyInfo::isResponder
bool isResponder() const noexcept
Definition: SMPTypes.cpp:318
direct_bt::MgmtEvent
uint16_t opcode, uint16_t dev-id, uint16_t param_size
Definition: MgmtTypes.hpp:1083
direct_bt::SMPPDUMsg::Opcode::SIGNING_INFORMATION
@ SIGNING_INFORMATION
direct_bt::HCIStatusCode
HCIStatusCode
BT Core Spec v5.2: Vol 1, Part F Controller Error Codes: 1.3 List of Error Codes.
Definition: HCITypes.hpp:124
direct_bt::BTAdapter::removeStatusListener
bool removeStatusListener(std::shared_ptr< AdapterStatusListener > l)
Remove the given listener from the list.
Definition: BTAdapter.cpp:585
E_FILE_LINE
#define E_FILE_LINE
Definition: basic_types.hpp:64
direct_bt::SMPAuthReqs::SECURE_CONNECTIONS
@ SECURE_CONNECTIONS
If LE Secure Connections pairing is supported by the device, then the SC field shall be set to 1,...
direct_bt::SMPOOBDataFlag::OOB_AUTH_DATA_NOT_PRESENT
@ OOB_AUTH_DATA_NOT_PRESENT
OOB_AUTH_DATA_NOT_PRESENT.
direct_bt::BTDevice::getAvailableSMPKeys
SMPKeyType getAvailableSMPKeys(const bool responder) const noexcept
Returns the available SMPKeyType mask for the responder (LL slave) or initiator (LL master).
Definition: BTDevice.cpp:1107
jau::darray
Implementation of a dynamic linear array storage, aka vector.
Definition: darray.hpp:102
direct_bt::SMPPDUMsg::Opcode::PAIRING_RESPONSE
@ PAIRING_RESPONSE
direct_bt::BTDevice::removeCharListener
bool removeCharListener(std::shared_ptr< BTGattCharListener > l) noexcept
Remove the given BTGattCharListener from the listener list.
Definition: BTDevice.cpp:1608
APPEARANCE
@ APPEARANCE
Definition: test_datatype02.hpp:67
direct_bt::BTDevice::setConnSecurityLevel
bool setConnSecurityLevel(const BTSecurityLevel sec_level) noexcept
Set the BTSecurityLevel used to connect to this device on the upcoming connection.
Definition: BTDevice.cpp:1182
direct_bt::BTDevice::getGattGenericAccess
std::shared_ptr< GattGenericAccessSvc > getGattGenericAccess()
Returns the shared GenericAccess instance, retrieved by getGattService() or nullptr if not available.
Definition: BTDevice.cpp:1590
direct_bt::MgmtStatus
MgmtStatus
Definition: MgmtTypes.hpp:77
direct_bt::BTDevice::removeAllAssociatedCharListener
int removeAllAssociatedCharListener(std::shared_ptr< BTGattChar > associatedCharacteristic) noexcept
Remove all BTGattCharListener from the list, which are associated to the given BTGattChar.
Definition: BTDevice.cpp:1618
direct_bt::HCIStatusCode::FAILED
@ FAILED
direct_bt::LE_Features
LE_Features
HCI Supported Commands.
Definition: BTTypes0.hpp:106
BTAdapter.hpp
direct_bt::SMPKeyType::ENC_KEY
@ ENC_KEY
LE legacy pairing: Indicates device shall distribute LTK using the Encryption Information command,...
direct_bt::HCILEOwnAddressType::RESOLVABLE_OR_PUBLIC
@ RESOLVABLE_OR_PUBLIC
Controller Resolved Private Address or Public Address.
direct_bt::isLEFeaturesBitSet
constexpr bool isLEFeaturesBitSet(const LE_Features mask, const LE_Features bit) noexcept
Definition: BTTypes0.hpp:163
le_scan_window
static const uint16_t le_scan_window
Definition: dbt_scanner10.cpp:634
direct_bt::BDAddressAndType::type
BDAddressType type
Definition: BTAddress.hpp:429
direct_bt::HCIHandler::le_read_phy
HCIStatusCode le_read_phy(const uint16_t conn_handle, const BDAddressAndType &addressAndType, LE_PHYs &resRx, LE_PHYs &resTx) noexcept
Request and return LE_PHYs bit for the given connection.
Definition: HCIHandler.cpp:1327
direct_bt::BTDevice::setPairingPasskey
HCIStatusCode setPairingPasskey(const uint32_t passkey) noexcept
Method sets the given passkey entry, see PairingMode::PASSKEY_ENTRY_ini.
Definition: BTDevice.cpp:1304
direct_bt::HCIStatusCode::AUTH_FAILED
@ AUTH_FAILED
direct_bt::GattGenericAccessSvc
Generic Access Service is a mandatory GATT service all peripherals are required to implement.
Definition: GattNumbers.hpp:264
direct_bt::EIRDataType::TX_POWER
@ TX_POWER
direct_bt::SMPPairingState::FAILED
@ FAILED
Pairing failed.
WARN_PRINT
#define WARN_PRINT(...)
Use for unconditional warning messages, prefix '[elapsed_time] Warning @ FILE:LINE: '.
Definition: debug.hpp:146
direct_bt::SMPPairingMsg
Vol 3, Part H: 3.5.1 Pairing Request message.
Definition: SMPTypes.hpp:876
direct_bt::SMPIdentAddrInfoMsg::isStaticRandomAddress
constexpr bool isStaticRandomAddress() const noexcept
Returns whether the device address is static random (true) or public (false).
Definition: SMPTypes.hpp:1686
direct_bt::HCILEOwnAddressType::RANDOM
@ RANDOM
Random Device Address.
direct_bt::HCIStatusCode::COMMAND_DISALLOWED
@ COMMAND_DISALLOWED
direct_bt::SMPPairingState::FEATURE_EXCHANGE_COMPLETED
@ FEATURE_EXCHANGE_COMPLETED
Phase 1: Pairing responded by responding (slave) device via SMPPairingMsg.
direct_bt::BTDevice::disconnect
HCIStatusCode disconnect(const HCIStatusCode reason=HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION) noexcept
Disconnect the LE or BREDR peer's GATT and HCI connection.
Definition: BTDevice.cpp:1701
direct_bt::BTDevice::removeStatusListener
bool removeStatusListener(std::shared_ptr< AdapterStatusListener > l)
Remove the given listener from the list.
Definition: BTDevice.cpp:252
direct_bt::HCIStatusCode::DISCONNECTED
@ DISCONNECTED
jau::sc_atomic_critical
This class provides a RAII-style Sequentially Consistent (SC) data race free (DRF) critical block.
Definition: ordered_atomic.hpp:314
direct_bt::SMPPDUMsg
Handles the Security Manager Protocol (SMP) using Protocol Data Unit (PDU) encoded messages over L2CA...
Definition: SMPTypes.hpp:644
direct_bt::EInfoReport::getAddress
EUI48 const & getAddress() const noexcept
Definition: BTTypes0.hpp:941
direct_bt::SMPMasterIdentMsg::getRand
constexpr uint64_t getRand() const noexcept
Returns the 64-bit Rand value (8 octets) being distributed.
Definition: SMPTypes.hpp:1554
direct_bt::BTGattHandler::ping
bool ping()
Issues a ping to the device, validating whether it is still reachable.
Definition: BTGattHandler.cpp:994
direct_bt::SMPPDUMsg::Opcode
Opcode
SMP Command Codes Vol 3, Part H (SM): 3.3.
Definition: SMPTypes.hpp:647
direct_bt::SMPSignatureResolvingKeyInfo
SMP Signature Resolving Key Info, used for platform agnostic persistence.
Definition: SMPTypes.hpp:598
direct_bt::BTSecurityLevel::UNSET
@ UNSET
Security Level not set, value 0.
direct_bt::L2CAP_PSM
L2CAP_PSM
Protocol Service Multiplexers (PSM) Assigned numbers https://www.bluetooth.com/specifications/assigne...
Definition: BTTypes0.hpp:458
direct_bt::SMPPairingMsg::getMaxEncryptionKeySize
constexpr uint8_t getMaxEncryptionKeySize() const noexcept
This value defines the maximum encryption key size in octets that the device can support.
Definition: SMPTypes.hpp:956
direct_bt::MgmtEvtNewLongTermKey
uint8_t store_hint, MgmtLongTermKeyInfo key
Definition: MgmtTypes.hpp:1460
direct_bt::hasSMPIOCapabilityFullInput
constexpr bool hasSMPIOCapabilityFullInput(const SMPIOCapability ioc) noexcept
Definition: SMPTypes.hpp:214
jau::darray::size
constexpr size_type size() const noexcept
Like std::vector::size().
Definition: darray.hpp:668
jau::INFO_PRINT
void INFO_PRINT(const char *format,...) noexcept
Use for unconditional informal messages, prefix '[elapsed_time] Info: '.
Definition: debug.cpp:166
direct_bt::HCIStatusCode::INVALID_PARAMS
@ INVALID_PARAMS
direct_bt::SMPPDUMsg::Opcode::ENCRYPTION_INFORMATION
@ ENCRYPTION_INFORMATION
direct_bt::PairingMode
PairingMode
Bluetooth secure pairing mode.
Definition: BTTypes0.hpp:261
direct_bt::BTDevice::removeAllCharListener
int removeAllCharListener() noexcept
Remove all BTGattCharListener from the list.
Definition: BTDevice.cpp:1638
direct_bt::BTManager
A thread safe singleton handler of the Linux Kernel's BlueZ manager control channel.
Definition: BTManager.hpp:201
direct_bt::BLERandomAddressType::STATIC_PUBLIC
@ STATIC_PUBLIC
Static public 'random' device address 0b11.
direct_bt::EIRDataType::MANUF_DATA
@ MANUF_DATA
direct_bt::SMPPairingState::REQUESTED_BY_RESPONDER
@ REQUESTED_BY_RESPONDER
Phase 0: Pairing requested by responding (slave) device via SMPSecurityReqMsg.
_key_mask_legacy
static const SMPKeyType _key_mask_legacy
Definition: BTDevice.cpp:667
direct_bt::SMPIdentInfoMsg
Vol 3, Part H: 3.6.4 Identify Information message.
Definition: SMPTypes.hpp:1599
direct_bt::BTDevice::setConnSecurityBest
bool setConnSecurityBest(const BTSecurityLevel sec_level, const SMPIOCapability io_cap) noexcept
Convenience method to determine the best practice BTSecurityLevel and SMPIOCapability based on the gi...
Definition: BTDevice.cpp:1258
direct_bt::BTGattService::type
std::unique_ptr< const uuid_t > type
Service type UUID.
Definition: BTGattService.hpp:94
direct_bt::SMPPairingMsg::getAuthReqMask
constexpr SMPAuthReqs getAuthReqMask() const noexcept
Returns the Authentication Requirements mask.
Definition: SMPTypes.hpp:945
direct_bt::BTDevice::getConnectionInfo
std::shared_ptr< ConnectionInfo > getConnectionInfo() noexcept
Retrieves the current connection info for this device and returns the ConnectionInfo reference if suc...
Definition: BTDevice.cpp:256
direct_bt::HCIHandler::le_create_conn
HCIStatusCode le_create_conn(const EUI48 &peer_bdaddr, const HCILEPeerAddressType peer_mac_type=HCILEPeerAddressType::PUBLIC, const HCILEOwnAddressType own_mac_type=HCILEOwnAddressType::PUBLIC, const uint16_t le_scan_interval=24, const uint16_t le_scan_window=24, const uint16_t conn_interval_min=12, const uint16_t conn_interval_max=12, const uint16_t conn_latency=0, const uint16_t supervision_timeout=getHCIConnSupervisorTimeout(0, 15)) noexcept
Establish a connection to the given LE peer.
Definition: HCIHandler.cpp:1074
direct_bt::SMPSignInfoMsg
Vol 3, Part H: 3.6.6 Signing Information message.
Definition: SMPTypes.hpp:1735
direct_bt::HCIStatusCode::INTERNAL_FAILURE
@ INTERNAL_FAILURE
direct_bt::PairingMode::NEGOTIATING
@ NEGOTIATING
Pairing mode in negotiating, i.e.
direct_bt::BTAdapter::addStatusListener
bool addStatusListener(std::shared_ptr< AdapterStatusListener > l)
Add the given listener to the list if not already present.
Definition: BTAdapter.cpp:548
direct_bt::EIRDataType::NAME_SHORT
@ NAME_SHORT
direct_bt::BTDevice::addressAndType
const BDAddressAndType addressAndType
Device's unique mac address and type tuple.
Definition: BTDevice.hpp:222
direct_bt::BTGattHandler::addCharListener
bool addCharListener(std::shared_ptr< BTGattCharListener > l)
Add the given listener to the list if not already present.
Definition: BTGattHandler.cpp:105
direct_bt::EIRDataType::RSSI
@ RSSI
direct_bt::L2CAPComm::open
bool open(const BTDevice &device, const BTSecurityLevel sec_level=BTSecurityLevel::NONE)
Opens and connects the L2CAP channel, locking mutex_write().
Definition: L2CAPComm.cpp:130
direct_bt::BTDevice::isConnSecurityAutoEnabled
bool isConnSecurityAutoEnabled() const noexcept
Returns true if automatic security negotiation has been enabled via setConnSecurityAuto(),...
Definition: BTDevice.cpp:1299
debug.hpp
direct_bt::BLERandomAddressType::RESOLVABLE_PRIVAT
@ RESOLVABLE_PRIVAT
Resolvable private random device address 0b01.
direct_bt::SMPPairingMsg::getRespKeyDist
constexpr SMPKeyType getRespKeyDist() const noexcept
Return the Responder Key Distribution field, which defines which keys the responder shall distribute ...
Definition: SMPTypes.hpp:982
direct_bt::SMPPDUMsg::Opcode::PAIRING_REQUEST
@ PAIRING_REQUEST
direct_bt::SMPPairingState::NUMERIC_COMPARE_EXPECTED
@ NUMERIC_COMPARE_EXPECTED
Phase 2: Authentication (MITM) Numeric Comparison Reply expected now, see PairingMode::NUMERIC_COMPAR...
direct_bt::ConnectionInfo::getTxPower
int8_t getTxPower() const noexcept
Definition: BTTypes1.hpp:92
direct_bt::HCILEPeerAddressType::RANDOM
@ RANDOM
Random Device Address.
direct_bt::HCIStatusCode::INTERNAL_TIMEOUT
@ INTERNAL_TIMEOUT
direct_bt::BTAdapter::hasSecureConnections
bool hasSecureConnections() const noexcept
Definition: BTAdapter.hpp:451
direct_bt::getPairingMode
PairingMode getPairingMode(const bool use_sc, const SMPAuthReqs authReqs_ini, const SMPIOCapability ioCap_ini, const SMPOOBDataFlag oobFlag_ini, const SMPAuthReqs authReqs_res, const SMPIOCapability ioCap_res, const SMPOOBDataFlag oobFlag_res) noexcept
Returns the PairingMode derived from both devices' sets of SMPAuthReqs, SMPIOCapability and SMPOOBDat...
Definition: SMPTypes.cpp:134
direct_bt::HCIHandler::isOpen
bool isOpen() const noexcept
Returns true if this mgmt instance is open, connected and hence valid, otherwise false.
Definition: HCIHandler.hpp:374
direct_bt::BTDevice::getAdvertisedServices
jau::darray< std::shared_ptr< uuid_t > > getAdvertisedServices() const noexcept
Return a list of advertised services as recognized at discovery, pre GATT discovery.
Definition: BTDevice.cpp:136
direct_bt::uuid_t::toUUID128String
virtual std::string toUUID128String(uuid128_t const &base_uuid=BT_BASE_UUID, jau::nsize_t const le_octet_index=12) const noexcept
Definition: UUID.cpp:68
direct_bt::SMPIdentInfoMsg::getIRK
constexpr jau::uint128_t getIRK() const noexcept
Returns the 128-bit Identity Resolving Key (IRK, 16 octets)
Definition: SMPTypes.hpp:1624
direct_bt::to_string
std::string to_string(const BDAddressType type) noexcept
Definition: BTTypes0.cpp:129
direct_bt::SMPSignInfoMsg::getCSRK
constexpr jau::uint128_t getCSRK() const noexcept
Returns the 128-bit Connection Signature Resolving Key (CSRK, 16 octets)
Definition: SMPTypes.hpp:1760
direct_bt::HCIStatusCode::UNSPECIFIED_ERROR
@ UNSPECIFIED_ERROR
direct_bt::BTAdapter
BTAdapter represents one Bluetooth Controller.
Definition: BTAdapter.hpp:250
direct_bt::BTDevice::getSharedInstance
std::shared_ptr< BTDevice > getSharedInstance() const noexcept
Returns the shared pointer of this instance managed by the adapter.
Definition: BTDevice.cpp:90
direct_bt::MgmtLongTermKeyInfo::toSMPLongTermKeyInfo
SMPLongTermKeyInfo toSMPLongTermKeyInfo() const noexcept
Definition: MgmtTypes.hpp:267
jau::IllegalStateException
Definition: basic_types.hpp:117
direct_bt::MgmtEvent::Opcode::PAIR_DEVICE_COMPLETE
@ PAIR_DEVICE_COMPLETE
direct_bt::PairingMode::PASSKEY_ENTRY_ini
@ PASSKEY_ENTRY_ini
Passkey Entry input by initiator.
jau::getCurrentMilliseconds
uint64_t getCurrentMilliseconds() noexcept
Returns current monotonic time in milliseconds.
Definition: basic_types.cpp:47
direct_bt::BLERandomAddressType::UNRESOLVABLE_PRIVAT
@ UNRESOLVABLE_PRIVAT
Non-resolvable private random device address 0b00.
direct_bt::BTSecurityLevel::ENC_AUTH
@ ENC_AUTH
Encryption and authentication (MITM).
jau::PLAIN_PRINT
void PLAIN_PRINT(const bool printPrefix, const char *format,...) noexcept
Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true.
Definition: debug.cpp:176
direct_bt::HCIStatusCode::UNKNOWN
@ UNKNOWN
direct_bt::BTAdapter::getManager
BTManager & getManager() const noexcept
Returns a reference to the used singleton BTManager instance, used to create this adapter.
Definition: BTAdapter.hpp:570
jau::to_hexstring
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
Definition: string_util.hpp:104
direct_bt::BTManager::getConnectionInfo
std::shared_ptr< ConnectionInfo > getConnectionInfo(const uint16_t dev_id, const BDAddressAndType &addressAndType) noexcept
Definition: BTManager.cpp:1072
direct_bt::BTDevice::setConnIOCapability
bool setConnIOCapability(const SMPIOCapability io_cap) noexcept
Sets the given SMPIOCapability used to connect to this device on the upcoming connection.
Definition: BTDevice.cpp:1209
direct_bt::BDAddressType::BDADDR_LE_RANDOM
@ BDADDR_LE_RANDOM
Bluetooth LE random address, see BLERandomAddressType.
direct_bt::hasSMPIOCapabilityBinaryInput
constexpr bool hasSMPIOCapabilityBinaryInput(const SMPIOCapability ioc) noexcept
Definition: SMPTypes.hpp:209
direct_bt::EIRDataType::NAME
@ NAME
direct_bt::SMPIOCapability
SMPIOCapability
Vol 3, Part H, 2.3.2 IO capabilities.
Definition: SMPTypes.hpp:185
_key_mask_sc
static const SMPKeyType _key_mask_sc
Definition: BTDevice.cpp:668
direct_bt::BTDevice::BTDevice
BTDevice(const BTDevice::ctor_cookie &cc, BTAdapter &adapter, EInfoReport const &r)
Private ctor for private BTDevice::make_shared() intended for friends.
Definition: BTDevice.cpp:47
ERR_PRINT
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE: '.
Definition: debug.hpp:132
direct_bt::BTDevice::getGattServices
jau::darray< std::shared_ptr< BTGattService > > getGattServices() noexcept
Returns a list of shared GATTService available on this device if successful, otherwise returns an emp...
Definition: BTDevice.cpp:1525
direct_bt::BTManager::uploadLongTermKeyInfo
HCIStatusCode uploadLongTermKeyInfo(const uint16_t dev_id, const BDAddressAndType &addressAndType, const SMPLongTermKeyInfo &ltk) noexcept
Definition: BTManager.cpp:858
direct_bt::SMPPDUMsg::Opcode::PAIRING_PUBLIC_KEY
@ PAIRING_PUBLIC_KEY
direct_bt::BTDevice::setPairingPasskeyNegative
HCIStatusCode setPairingPasskeyNegative() noexcept
Method replies with a negative passkey response, i.e.
Definition: BTDevice.cpp:1327
direct_bt::BTGattHandler::getGenericAccess
std::shared_ptr< GattGenericAccessSvc > getGenericAccess() noexcept
Returns the internal kept shared GattGenericAccessSvc instance.
Definition: BTGattHandler.hpp:322
direct_bt::BTGattHandler::isConnected
bool isConnected() const noexcept
Definition: BTGattHandler.hpp:253
direct_bt::SMPPairingState::NONE
@ NONE
No pairing in process.
direct_bt::L2CAP_CID::ATT
@ ATT
direct_bt::SMPPairingState::FEATURE_EXCHANGE_STARTED
@ FEATURE_EXCHANGE_STARTED
Phase 1: Pairing requested by initiating (master) device via SMPPairingMsg.
direct_bt::L2CAPComm::isOpen
bool isOpen() const
Definition: L2CAPComm.hpp:169
direct_bt::SMPPairingMsg::getIOCapability
constexpr SMPIOCapability getIOCapability() const noexcept
Returns the IO capability bit field.
Definition: SMPTypes.hpp:922
direct_bt::HCIHandler::env
const HCIEnv & env
Definition: HCIHandler.hpp:179
direct_bt::HCIStatusCode::SUCCESS
@ SUCCESS
direct_bt::SMPKeyType::LINK_KEY
@ LINK_KEY
SMP on the LE transport: Indicate that the device would like to derive the Link Key from the LTK.
direct_bt::BTManager::uploadConnParam
bool uploadConnParam(const uint16_t dev_id, const BDAddressAndType &addressAndType, const uint16_t conn_interval_min=12, const uint16_t conn_interval_max=12, const uint16_t conn_latency=0, const uint16_t supervision_timeout=getHCIConnSupervisorTimeout(0, 15)) noexcept
Uploads given connection parameter for given device to the kernel.
Definition: BTManager.cpp:806
direct_bt::BTDevice::addStatusListener
bool addStatusListener(std::shared_ptr< AdapterStatusListener > l)
Add the given AdapterStatusListener to the list if not already present, intended to listen only for e...
Definition: BTDevice.cpp:248
direct_bt::SMPPairingMsg::getOOBDataFlag
constexpr SMPOOBDataFlag getOOBDataFlag() const noexcept
Returns the OBB authenticate data flag.
Definition: SMPTypes.hpp:933
direct_bt::BTDevice::getGattHandler
std::shared_ptr< BTGattHandler > getGattHandler() noexcept
Returns the connected GATTHandler or nullptr, see connectGATT(), getGattService() and disconnect().
Definition: BTDevice.cpp:1520
direct_bt::SMPPairingMsg::getInitKeyDist
constexpr SMPKeyType getInitKeyDist() const noexcept
Returns the Initiator Key Distribution field, which defines which keys the initiator shall distribute...
Definition: SMPTypes.hpp:969
direct_bt::HCILEOwnAddressType::PUBLIC
@ PUBLIC
Public Device Address.
direct_bt::SMPLongTermKeyInfo::Property::SC
@ SC
Secure Connection used.
direct_bt::HCIEnv::HCI_COMMAND_POLL_PERIOD
const int32_t HCI_COMMAND_POLL_PERIOD
Poll period for certain HCI commands actively waiting for clearance, defaults to 125ms.
Definition: HCIHandler.hpp:111
direct_bt::BTManager::unpairDevice
MgmtStatus unpairDevice(const uint16_t dev_id, const BDAddressAndType &addressAndType, const bool disconnect) noexcept
Definition: BTManager.cpp:946
direct_bt::BLERandomAddressType::UNDEFINED
@ UNDEFINED
Undefined, e.g.
direct_bt::HCIStatusCode::CONNECTION_ALREADY_EXISTS
@ CONNECTION_ALREADY_EXISTS
direct_bt::BDAddressAndType::isLEAddress
constexpr bool isLEAddress() const noexcept
Returns true if the BDAddressType is a LE address type.
Definition: BTAddress.hpp:458
direct_bt::BTDevice::getName
std::string const getName() const noexcept
Definition: BTDevice.cpp:124
direct_bt::BTGattHandler::removeAllAssociatedCharListener
int removeAllAssociatedCharListener(std::shared_ptr< BTGattChar > associatedChar) noexcept
Remove all BTGattCharListener from the list, which are associated to the given BTGattChar.
Definition: BTGattHandler.cpp:137
HCIComm.hpp
direct_bt::BTDevice::pair
HCIStatusCode pair(const SMPIOCapability io_cap) noexcept
Experimental only.
Definition: BTDevice.cpp:1149
direct_bt::to_HCIStatusCode
HCIStatusCode to_HCIStatusCode(const MgmtStatus mstatus) noexcept
Definition: MgmtTypes.cpp:543
direct_bt::SMPMasterIdentMsg
Vol 3, Part H: 3.6.3 Master Identification message.
Definition: SMPTypes.hpp:1521
direct_bt::HCIStatusCode::CONNECTION_TERMINATED_BY_LOCAL_HOST
@ CONNECTION_TERMINATED_BY_LOCAL_HOST
direct_bt::HCILEPeerAddressType
HCILEPeerAddressType
HCI LE Address-Type is PUBLIC: 0x00, RANDOM: 0x01.
Definition: BTAddress.hpp:120
WORDY_PRINT
#define WORDY_PRINT(...)
Use for environment-variable environment::VERBOSE conditional verbose messages, prefix '[elapsed_time...
Definition: debug.hpp:91
direct_bt::SMPPDUMsg::Opcode::IDENTITY_INFORMATION
@ IDENTITY_INFORMATION
direct_bt::BTDevice::unpair
HCIStatusCode unpair() noexcept
Unpairs this device from the adapter while staying connected.
Definition: BTDevice.cpp:1772
direct_bt::SMPPairingState
SMPPairingState
SMP Pairing Process state definition.
Definition: SMPTypes.hpp:101
direct_bt::BTDevice::getConnSecurityLevel
BTSecurityLevel getConnSecurityLevel() const noexcept
Return the BTSecurityLevel, determined when the connection is established.
Definition: BTDevice.cpp:1204
direct_bt::HCIStatusCode::REMOTE_USER_TERMINATED_CONNECTION
@ REMOTE_USER_TERMINATED_CONNECTION
direct_bt::SMPPDUMsg::Opcode::PAIRING_RANDOM
@ PAIRING_RANDOM
direct_bt::BTDevice::setLongTermKeyInfo
HCIStatusCode setLongTermKeyInfo(const SMPLongTermKeyInfo &ltk) noexcept
Sets the long term ket (LTK) info of this device to reuse pre-paired encryption.
Definition: BTDevice.cpp:1121
direct_bt::LE_PHYs
LE_PHYs
LE Transport PHY bit values.
Definition: BTTypes0.hpp:175
direct_bt::BDAddressType::BDADDR_LE_PUBLIC
@ BDADDR_LE_PUBLIC
Bluetooth LE public address.
direct_bt::SMPSignatureResolvingKeyInfo::Property::AUTH
@ AUTH
Authentication used.
direct_bt::SMPLongTermKeyInfo::isValid
constexpr bool isValid() const noexcept
Definition: SMPTypes.hpp:522
BTDevice.hpp
direct_bt::BDAddressType::BDADDR_BREDR
@ BDADDR_BREDR
Bluetooth BREDR address.
direct_bt::L2CAPComm::close
bool close() noexcept
Closing the L2CAP channel, locking mutex_write().
Definition: L2CAPComm.cpp:241
direct_bt::BTManager::userConfirmReply
MgmtStatus userConfirmReply(const uint16_t dev_id, const BDAddressAndType &addressAndType, const bool positive) noexcept
Definition: BTManager.cpp:916
direct_bt::BTManager::userPasskeyReply
MgmtStatus userPasskeyReply(const uint16_t dev_id, const BDAddressAndType &addressAndType, const uint32_t passkey) noexcept
Definition: BTManager.cpp:886
direct_bt::HCIEnv::HCI_COMMAND_COMPLETE_REPLY_TIMEOUT
const int32_t HCI_COMMAND_COMPLETE_REPLY_TIMEOUT
Timeout for HCI command complete replies, defaults to 10s.
Definition: HCIHandler.hpp:98
direct_bt::HCIACLData::l2cap_frame::PBFlag::START_NON_AUTOFLUSH_HOST
@ START_NON_AUTOFLUSH_HOST
0b00: Start of a non-automatically-flushable PDU from Host to Controller.
direct_bt::PairingMode::PRE_PAIRED
@ PRE_PAIRED
Reusing encryption keys from previous pairing.
direct_bt::MgmtLongTermKeyInfo
Used for MgmtLoadLongTermKeyCmd and MgmtEvtNewLongTermKey.
Definition: MgmtTypes.hpp:267
direct_bt::BTGattHandler::discoverCompletePrimaryServices
jau::darray< BTGattServiceRef > & discoverCompletePrimaryServices(std::shared_ptr< BTGattHandler > shared_this)
Discover all primary services and all its characteristics declarations including their client config.
Definition: BTGattHandler.cpp:513
direct_bt::HCIStatusCode::NOT_SUPPORTED
@ NOT_SUPPORTED
DBG_PRINT
#define DBG_PRINT(...)
Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] De...
Definition: debug.hpp:78
direct_bt::BTSecurityLevel::ENC_ONLY
@ ENC_ONLY
Encryption and no authentication (no MITM).
direct_bt::BTManager::userPasskeyNegativeReply
MgmtStatus userPasskeyNegativeReply(const uint16_t dev_id, const BDAddressAndType &addressAndType) noexcept
Definition: BTManager.cpp:901
direct_bt::isSMPAuthReqBitSet
constexpr bool isSMPAuthReqBitSet(const SMPAuthReqs mask, const SMPAuthReqs bit) noexcept
Definition: SMPTypes.hpp:328
direct_bt::SMPPairingState::COMPLETED
@ COMPLETED
Phase 3: Key & value distribution completed by responding (slave) device sending SMPIdentInfoMsg (#1)...
direct_bt::HCILEOwnAddressType
HCILEOwnAddressType
Definition: BTAddress.hpp:135
direct_bt::hasSMPPairingFinished
constexpr bool hasSMPPairingFinished(const SMPPairingState state) noexcept
Returns true if the given SMPPairingState indicates a finished pairing process, i....
Definition: SMPTypes.hpp:164
direct_bt::BTDevice::findGattService
std::shared_ptr< BTGattService > findGattService(std::shared_ptr< uuid_t > const &uuid)
Returns the matching GATTService for the given uuid.
Definition: BTDevice.cpp:1563
environment.hpp
direct_bt::BTGattHandler::removeCharListener
bool removeCharListener(std::shared_ptr< BTGattCharListener > l) noexcept
Remove the given listener from the list.
Definition: BTGattHandler.cpp:112
direct_bt::MgmtEvent::Opcode::HCI_ENC_CHANGED
@ HCI_ENC_CHANGED
direct_bt::PairingMode::OUT_OF_BAND
@ OUT_OF_BAND
Utilizing a second factor secret to be used as a secret, e.g.
direct_bt::SMPLongTermKeyInfo
SMP Long Term Key Info, used for platform agnostic persistence.
Definition: SMPTypes.hpp:522
direct_bt::SMPKeyType::NONE
@ NONE