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