Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
SMPHandler.hpp
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 #ifndef SMP_HANDLER_HPP_
27 #define SMP_HANDLER_HPP_
28 
29 #include <cstring>
30 #include <string>
31 #include <cstdint>
32 
33 #include <mutex>
34 #include <atomic>
35 #include <thread>
36 
37 #include <jau/environment.hpp>
38 #include <jau/ringbuffer.hpp>
39 #include <jau/function_def.hpp>
40 #include <jau/darray.hpp>
41 #include <jau/cow_darray.hpp>
42 
43 #include "UUID.hpp"
44 #include "BTTypes0.hpp"
45 #include "L2CAPComm.hpp"
46 #include "SMPTypes.hpp"
47 
48 /**
49  * Linux/BlueZ prohibits access to the existing SMP implementation via L2CAP (socket).
50  */
51 #ifdef __linux__
52  #define SMP_SUPPORTED_BY_OS 0
53  #define USE_LINUX_BT_SECURITY 1
54 #else
55  #define SMP_SUPPORTED_BY_OS 1
56  #define USE_LINUX_BT_SECURITY 0
57 #endif
58 
59 /**
60  * - - - - - - - - - - - - - - -
61  *
62  * SMPHandler.hpp Module for SMPHandler using SMPPDUMsg types
63  *
64  * - BT Core Spec v5.2: Vol 3, Part H Security Manager Specification (SM): 2 Security Manager (SM)
65  * - BT Core Spec v5.2: Vol 3, Part H Security Manager Specification (SM): 3 Security Manager Protocol (SMP)
66  *
67  * Overall bookmark regarding BT Security
68  *
69  * - BT Core Spec v5.2: Vol 1, Part A Architecture: 5 Security architecture
70  * - BT Core Spec v5.2: Vol 1, Part A Architecture: 5.4 LE Security
71  * - BT Core Spec v5.2: Vol 1, Part A Architecture: 5.4.5 LE Privacy feature
72  * - device privacy mode (mixed mode, also accept other peer address)
73  * - network privacy mode (only private address - default!)
74  * - add device to resolving list, implying being added to device white list!
75  *
76  * - BT Core Spec v5.2: Vol 3, Part C GAP: 10.2 LE SECURITY MODES
77  *
78  * - BT Core Spec v5.2: Vol 3, Part H Security Manager Specification (SM): 2 Security Manager (SM)
79  * - 2.3.5 Pairing: 2.3.5.6 LE Secure Connections pairing phase 2
80  * - 2.3.5 Pairing: 2.3.5.6.3 LE Authentication stage 1 – Passkey Entry
81  * - BT Core Spec v5.2: Vol 3, Part H Security Manager Specification (SM): 3 Security Manager Protocol (SMP)
82  * - fixed channel over L2CAP
83  *
84  * - BT Core Spec v5.2: Vol 4, Part E HCI: 7.8.77 LE Set Privacy Mode command
85  *
86  * - BT Core Spec v5.2: Vol 6 LE Adapter, Part B Link Layer Spec: 4.7 Resolving List
87  */
88 namespace direct_bt {
89 
90  /**
91  * SMP Singleton runtime environment properties
92  * <p>
93  * Also see {@link DBTEnv::getExplodingProperties(const std::string & prefixDomain)}.
94  * </p>
95  */
96  class SMPEnv : public jau::root_environment {
97  private:
98  SMPEnv() noexcept;
99 
100  const bool exploding; // just to trigger exploding properties
101 
102  public:
103  /**
104  * Timeout for SMP read command replies, defaults to 500ms.
105  * <p>
106  * Environment variable is 'direct_bt.smp.cmd.read.timeout'.
107  * </p>
108  */
110 
111  /**
112  * Timeout for SMP write command replies, defaults to 500ms.
113  * <p>
114  * Environment variable is 'direct_bt.smp.cmd.write.timeout'.
115  * </p>
116  */
118 
119  /**
120  * Medium ringbuffer capacity, defaults to 128 messages.
121  * <p>
122  * Environment variable is 'direct_bt.smp.ringsize'.
123  * </p>
124  */
125  const int32_t SMPPDU_RING_CAPACITY;
126 
127  /**
128  * Debug all SMP Data communication
129  * <p>
130  * Environment variable is 'direct_bt.debug.smp.data'.
131  * </p>
132  */
133  const bool DEBUG_DATA;
134 
135  public:
136  static SMPEnv& get() noexcept {
137  /**
138  * Thread safe starting with C++11 6.7:
139  *
140  * If control enters the declaration concurrently while the variable is being initialized,
141  * the concurrent execution shall wait for completion of the initialization.
142  *
143  * (Magic Statics)
144  *
145  * Avoiding non-working double checked locking.
146  */
147  static SMPEnv e;
148  return e;
149  }
150  };
151 
152 
155 
156  /**
157  * A thread safe SMP handler associated to one device via one L2CAP connection.
158  * <p>
159  * Implementation utilizes a lock free ringbuffer receiving data within its separate thread.
160  * </p>
161  * <p>
162  * Controlling Environment variables, see {@link SMPEnv}.
163  * </p>
164  * See
165  *
166  * - BT Core Spec v5.2: Vol 3, Part H Security Manager Specification (SM): 2 Security Manager (SM)
167  * - BT Core Spec v5.2: Vol 3, Part H Security Manager Specification (SM): 3 Security Manager Protocol (SMP)
168  */
169  class SMPHandler {
170  public:
171  /**
172  * Linux/BlueZ prohibits access to the existing SMP implementation via L2CAP (socket).
173  */
174  static bool IS_SUPPORTED_BY_OS;
175 
176  enum class Defaults : int32_t {
177  /* Vol 3 (Host), Part H (SM): 3 (SMP), 3.2 Security Manager Channel Over L2CAP */
178  MIN_SMP_MTU = 23,
179 
180  /* Vol 3 (Host), Part H (SM): 3 (SMP), 3.2 Security Manager Channel Over L2CAP */
181  LE_SECURE_SMP_MTU = 65,
182 
183  SMP_MTU_BUFFER_SZ = 128
184  };
185  static constexpr int number(const Defaults d) { return static_cast<int>(d); }
186 
187  private:
188  const SMPEnv & env;
189 
190  /** GATTHandle's device weak back-reference */
191  std::weak_ptr<BTDevice> wbr_device;
192 
193  const std::string deviceString;
194  std::recursive_mutex mtx_command;
195  POctets rbuffer;
196 
197  L2CAPComm l2cap;
198  jau::sc_atomic_bool is_connected; // reflects state
199  jau::relaxed_atomic_bool has_ioerror; // reflects state
200 
202  jau::sc_atomic_bool l2capReaderShallStop;
203 
204  std::mutex mtx_l2capReaderLifecycle;
205  std::condition_variable cv_l2capReaderInit;
206  pthread_t l2capReaderThreadId;
207  jau::relaxed_atomic_bool l2capReaderRunning;
208 
209  SMPSecurityReqCallbackList smpSecurityReqCallbackList;
210 
211  uint16_t mtu;
212 
213  bool validateConnected() noexcept;
214 
215  void l2capReaderThreadImpl();
216 
217  void send(const SMPPDUMsg & msg);
218  std::unique_ptr<const SMPPDUMsg> sendWithReply(const SMPPDUMsg & msg, const int timeout);
219 
220  void clearAllCallbacks() noexcept;
221 
222  public:
223  SMPHandler(const std::shared_ptr<BTDevice> & device) noexcept;
224 
225  SMPHandler(const SMPHandler&) = delete;
226  void operator=(const SMPHandler&) = delete;
227 
228  /** Destructor closing this instance including L2CAP channel, see {@link #disconnect()}. */
229  ~SMPHandler() noexcept;
230 
231  std::shared_ptr<BTDevice> getDeviceUnchecked() const noexcept { return wbr_device.lock(); }
232  std::shared_ptr<BTDevice> getDeviceChecked() const;
233 
234  bool isConnected() const noexcept { return is_connected ; }
235  bool hasIOError() const noexcept { return has_ioerror; }
236  std::string getStateString() const noexcept { return L2CAPComm::getStateString(is_connected, has_ioerror); }
237 
238  /**
239  * If sec_level > ::BTSecurityLevel::UNSET, change security level per L2CAP connection.
240  *
241  * @param sec_level sec_level < ::BTSecurityLevel::NONE will not set security level and returns false.
242  * @return true if a security level > ::BTSecurityLevel::UNSET has been set successfully, false if no security level has been set or if it failed.
243  */
244  bool establishSecurity(const BTSecurityLevel sec_level);
245 
246  /**
247  * Disconnect this GATTHandler and optionally the associated device
248  * @param disconnectDevice if true, associated device will also be disconnected, otherwise not.
249  * @param ioErrorCause if true, reason for disconnection is an IO error
250  * @return true if successful, otherwise false
251  */
252  bool disconnect(const bool disconnectDevice, const bool ioErrorCause) noexcept;
253 
256  };
257 
258 } // namespace direct_bt
259 
260 #endif /* SMP_HANDLER_HPP_ */
261 
direct_bt::SMPEnv::SMP_WRITE_COMMAND_REPLY_TIMEOUT
const int32_t SMP_WRITE_COMMAND_REPLY_TIMEOUT
Timeout for SMP write command replies, defaults to 500ms.
Definition: SMPHandler.hpp:117
direct_bt::SMPHandler::disconnect
bool disconnect(const bool disconnectDevice, const bool ioErrorCause) noexcept
Disconnect this GATTHandler and optionally the associated device.
Definition: SMPHandler.cpp:210
direct_bt::SMPHandler::Defaults
Defaults
Definition: SMPHandler.hpp:176
L2CAPComm.hpp
direct_bt::SMPEnv::SMP_READ_COMMAND_REPLY_TIMEOUT
const int32_t SMP_READ_COMMAND_REPLY_TIMEOUT
Timeout for SMP read command replies, defaults to 500ms.
Definition: SMPHandler.hpp:109
direct_bt::SMPHandler::Defaults::LE_SECURE_SMP_MTU
@ LE_SECURE_SMP_MTU
direct_bt::SMPHandler::addSMPSecurityReqCallback
void addSMPSecurityReqCallback(const SMPSecurityReqCallback &l)
Definition: SMPHandler.cpp:325
darray.hpp
direct_bt::SMPHandler::getStateString
std::string getStateString() const noexcept
Definition: SMPHandler.hpp:236
direct_bt::SMPHandler
A thread safe SMP handler associated to one device via one L2CAP connection.
Definition: SMPHandler.hpp:169
direct_bt::SMPHandler::removeSMPSecurityReqCallback
int removeSMPSecurityReqCallback(const SMPSecurityReqCallback &l)
Definition: SMPHandler.cpp:328
jau::root_environment
Base jau environment class, merely to tag all environment settings by inheritance and hence documenta...
Definition: environment.hpp:51
function_def.hpp
direct_bt
Definition: ATTPDUTypes.hpp:171
direct_bt::L2CAPComm
Read/Write L2CAP communication channel.
Definition: L2CAPComm.hpp:113
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::SMPHandler::Defaults::SMP_MTU_BUFFER_SZ
@ SMP_MTU_BUFFER_SZ
direct_bt::BTSecurityLevel
BTSecurityLevel
Bluetooth Security Level.
Definition: BTTypes0.hpp:211
direct_bt::SMPHandler::Defaults::MIN_SMP_MTU
@ MIN_SMP_MTU
jau::FunctionDef
Definition: function_def.hpp:309
direct_bt::L2CAPComm::getStateString
std::string getStateString() const
Definition: L2CAPComm.hpp:178
jau::ordered_atomic< bool, std::memory_order::memory_order_seq_cst >
cow_darray.hpp
direct_bt::SMPHandler::isConnected
bool isConnected() const noexcept
Definition: SMPHandler.hpp:234
direct_bt::SMPPDUMsg
Handles the Security Manager Protocol (SMP) using Protocol Data Unit (PDU) encoded messages over L2CA...
Definition: SMPTypes.hpp:644
direct_bt::SMPHandler::getDeviceUnchecked
std::shared_ptr< BTDevice > getDeviceUnchecked() const noexcept
Definition: SMPHandler.hpp:231
BTTypes0.hpp
jau::ringbuffer
Ring buffer implementation, a.k.a circular buffer, exposing lock-free get*(..) and put*(....
Definition: ringbuffer.hpp:115
UUID.hpp
direct_bt::SMPSecurityReqCallbackList
jau::cow_darray< SMPSecurityReqCallback > SMPSecurityReqCallbackList
Definition: SMPHandler.hpp:154
jau::cow_darray< SMPSecurityReqCallback >
SMPTypes.hpp
direct_bt::SMPHandler::number
static constexpr int number(const Defaults d)
Definition: SMPHandler.hpp:185
direct_bt::SMPEnv::get
static SMPEnv & get() noexcept
Definition: SMPHandler.hpp:136
jau::nsize_t
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:44
ringbuffer.hpp
direct_bt::SMPEnv
SMP Singleton runtime environment properties.
Definition: SMPHandler.hpp:96
direct_bt::SMPHandler::getDeviceChecked
std::shared_ptr< BTDevice > getDeviceChecked() const
Definition: SMPHandler.cpp:75
direct_bt::SMPHandler::hasIOError
bool hasIOError() const noexcept
Definition: SMPHandler.hpp:235
direct_bt::SMPEnv::DEBUG_DATA
const bool DEBUG_DATA
Debug all SMP Data communication.
Definition: SMPHandler.hpp:133
direct_bt::SMPSecurityReqCallback
jau::FunctionDef< bool, const SMPPDUMsg & > SMPSecurityReqCallback
Definition: SMPHandler.hpp:153
direct_bt::SMPHandler::establishSecurity
bool establishSecurity(const BTSecurityLevel sec_level)
If sec_level > BTSecurityLevel::UNSET, change security level per L2CAP connection.
Definition: SMPHandler.cpp:203
direct_bt::POctets
Persistent octet data, i.e.
Definition: OctetTypes.hpp:451
direct_bt::SMPEnv::SMPPDU_RING_CAPACITY
const int32_t SMPPDU_RING_CAPACITY
Medium ringbuffer capacity, defaults to 128 messages.
Definition: SMPHandler.hpp:125
direct_bt::BTDevice
Definition: BTDevice.hpp:57
environment.hpp