1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtBluetooth module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QLOWENERGYCONTROLLERBLUEZ_P_H
41 #define QLOWENERGYCONTROLLERBLUEZ_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <qglobal.h>
55 #include <QtCore/QQueue>
56 #include <QtCore/QVector>
57 #include <QtBluetooth/qbluetooth.h>
58 #include <QtBluetooth/qlowenergycharacteristic.h>
59 #include "qlowenergycontroller.h"
60 #include "qlowenergycontrollerbase_p.h"
61 
62 #include <QtBluetooth/QBluetoothSocket>
63 #include <functional>
64 
65 QT_BEGIN_NAMESPACE
66 
67 class QLowEnergyServiceData;
68 class QTimer;
69 
70 class HciManager;
71 class LeCmacCalculator;
72 class QSocketNotifier;
73 class RemoteDeviceManager;
74 
75 extern void registerQLowEnergyControllerMetaType();
76 
77 class QLeAdvertiser;
78 
79 class QLowEnergyControllerPrivateBluez final: public QLowEnergyControllerPrivate
80 {
81     Q_OBJECT
82 public:
83     QLowEnergyControllerPrivateBluez();
84     ~QLowEnergyControllerPrivateBluez() override;
85 
86     void init() override;
87 
88     void connectToDevice() override;
89     void disconnectFromDevice() override;
90 
91     void discoverServices() override;
92     void discoverServiceDetails(const QBluetoothUuid &service) override;
93 
94     void startAdvertising(const QLowEnergyAdvertisingParameters &params,
95                           const QLowEnergyAdvertisingData &advertisingData,
96                           const QLowEnergyAdvertisingData &scanResponseData) override;
97     void stopAdvertising() override;
98 
99     void requestConnectionUpdate(const QLowEnergyConnectionParameters &params) override;
100 
101     // read data
102     void readCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
103                             const QLowEnergyHandle charHandle) override;
104     void readDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
105                         const QLowEnergyHandle charHandle,
106                         const QLowEnergyHandle descriptorHandle) override;
107 
108     // write data
109     void writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service,
110                              const QLowEnergyHandle charHandle,
111                              const QByteArray &newValue, QLowEnergyService::WriteMode mode) override;
112     void writeDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service,
113                          const QLowEnergyHandle charHandle,
114                          const QLowEnergyHandle descriptorHandle,
115                          const QByteArray &newValue) override;
116 
117     void addToGenericAttributeList(const QLowEnergyServiceData &service,
118                                    QLowEnergyHandle startHandle) override;
119 
120     struct Attribute {
AttributeAttribute121         Attribute() : handle(0) {}
122 
123         QLowEnergyHandle handle;
124         QLowEnergyHandle groupEndHandle;
125         QLowEnergyCharacteristic::PropertyTypes properties;
126         QBluetooth::AttAccessConstraints readConstraints;
127         QBluetooth::AttAccessConstraints writeConstraints;
128         QBluetoothUuid type;
129         QByteArray value;
130         int minLength;
131         int maxLength;
132     };
133     QVector<Attribute> localAttributes;
134 
135 private:
136     quint16 connectionHandle = 0;
137     QBluetoothSocket *l2cpSocket = nullptr;
138     struct Request {
139         quint8 command;
140         QByteArray payload;
141         // TODO reference below is ugly but until we know all commands and their
142         // requirements this is WIP
143         QVariant reference;
144         QVariant reference2;
145     };
146     QQueue<Request> openRequests;
147 
148     struct WriteRequest {
WriteRequestWriteRequest149         WriteRequest() {}
WriteRequestWriteRequest150         WriteRequest(quint16 h, quint16 o, const QByteArray &v)
151             : handle(h), valueOffset(o), value(v) {}
152         quint16 handle;
153         quint16 valueOffset;
154         QByteArray value;
155     };
156     QVector<WriteRequest> openPrepareWriteRequests;
157 
158     // Invariant: !scheduledIndications.isEmpty => indicationInFlight == true
159     QVector<QLowEnergyHandle> scheduledIndications;
160     bool indicationInFlight = false;
161 
162     struct TempClientConfigurationData {
163         TempClientConfigurationData(QLowEnergyServicePrivate::DescData *dd = nullptr,
164                                     QLowEnergyHandle chHndl = 0, QLowEnergyHandle coHndl = 0)
descDataTempClientConfigurationData165             : descData(dd), charValueHandle(chHndl), configHandle(coHndl) {}
166 
167         QLowEnergyServicePrivate::DescData *descData;
168         QLowEnergyHandle charValueHandle;
169         QLowEnergyHandle configHandle;
170     };
171 
172     struct ClientConfigurationData {
173         ClientConfigurationData(QLowEnergyHandle chHndl = 0, QLowEnergyHandle coHndl = 0,
174                                 quint16 val = 0)
charValueHandleClientConfigurationData175             : charValueHandle(chHndl), configHandle(coHndl), configValue(val) {}
176 
177         QLowEnergyHandle charValueHandle;
178         QLowEnergyHandle configHandle;
179         quint16 configValue;
180         bool charValueWasUpdated = false;
181     };
182     QHash<quint64, QVector<ClientConfigurationData>> clientConfigData;
183 
184     struct SigningData {
185         SigningData() = default;
186         SigningData(const quint128 &csrk, quint32 signCounter = quint32(-1))
keySigningData187             : key(csrk), counter(signCounter) {}
188 
189         quint128 key;
190         quint32 counter = quint32(-1);
191     };
192     QHash<quint64, SigningData> signingData;
193     LeCmacCalculator *cmacCalculator = nullptr;
194 
195     bool requestPending;
196     quint16 mtuSize;
197     int securityLevelValue;
198     bool encryptionChangePending;
199     bool receivedMtuExchangeRequest = false;
200 
201     HciManager *hciManager = nullptr;
202     QLeAdvertiser *advertiser = nullptr;
203     QSocketNotifier *serverSocketNotifier = nullptr;
204     QTimer *requestTimer = nullptr;
205     RemoteDeviceManager* device1Manager = nullptr;
206 
207     /*
208       Defines the maximum number of milliseconds the implementation will
209       wait for requests that require a response.
210 
211       This addresses the problem that some non-conformant BTLE devices
212       do not implement the request/response system properly. In such cases
213       the queue system would hang forever.
214 
215       Once timeout has been triggered we gracefully continue with the next request.
216       Depending on the type of the timed out ATT command we either ignore it
217       or artifically trigger an error response to ensure the API gives the
218       appropriate response. Potentially this can cause problems when the
219       response for the dropped requests arrives very late. That's why a big warning
220       is printed about the compromised state when a timeout is triggered.
221      */
222     int gattRequestTimeout = 20000;
223 
224     void handleConnectionRequest();
225     void closeServerSocket();
226 
227     bool isBonded() const;
228     QVector<TempClientConfigurationData> gatherClientConfigData();
229     void storeClientConfigurations();
230     void restoreClientConfigurations();
231 
232     enum SigningKeyType { LocalSigningKey, RemoteSigningKey };
233     void loadSigningDataIfNecessary(SigningKeyType keyType);
234     void storeSignCounter(SigningKeyType keyType) const;
235     QString signingKeySettingsGroup(SigningKeyType keyType) const;
236     QString keySettingsFilePath() const;
237 
238     void sendPacket(const QByteArray &packet);
239     void sendNextPendingRequest();
240     void processReply(const Request &request, const QByteArray &reply);
241 
242     void sendReadByGroupRequest(QLowEnergyHandle start, QLowEnergyHandle end,
243                                 quint16 type);
244     void sendReadByTypeRequest(QSharedPointer<QLowEnergyServicePrivate> serviceData,
245                                QLowEnergyHandle nextHandle, quint16 attributeType);
246     void sendReadValueRequest(QLowEnergyHandle attributeHandle, bool isDescriptor);
247     void readServiceValues(const QBluetoothUuid &service,
248                            bool readCharacteristics);
249     void readServiceValuesByOffset(uint handleData, quint16 offset,
250                                    bool isLastValue);
251 
252     void discoverServiceDescriptors(const QBluetoothUuid &serviceUuid);
253     void discoverNextDescriptor(QSharedPointer<QLowEnergyServicePrivate> serviceData,
254                                 const QList<QLowEnergyHandle> pendingCharHandles,
255                                 QLowEnergyHandle startingHandle);
256     void processUnsolicitedReply(const QByteArray &msg);
257     void exchangeMTU();
258     bool setSecurityLevel(int level);
259     int securityLevel() const;
260     void sendExecuteWriteRequest(const QLowEnergyHandle attrHandle,
261                                  const QByteArray &newValue,
262                                  bool isCancelation);
263     void sendNextPrepareWriteRequest(const QLowEnergyHandle handle,
264                                      const QByteArray &newValue, quint16 offset);
265     bool increaseEncryptLevelfRequired(quint8 errorCode);
266 
267     void resetController();
268 
269     void handleAdvertisingError();
270 
271     bool checkPacketSize(const QByteArray &packet, int minSize, int maxSize = -1);
272     bool checkHandle(const QByteArray &packet, QLowEnergyHandle handle);
273     bool checkHandlePair(quint8 request, QLowEnergyHandle startingHandle,
274                          QLowEnergyHandle endingHandle);
275 
276     void handleExchangeMtuRequest(const QByteArray &packet);
277     void handleFindInformationRequest(const QByteArray &packet);
278     void handleFindByTypeValueRequest(const QByteArray &packet);
279     void handleReadByTypeRequest(const QByteArray &packet);
280     void handleReadRequest(const QByteArray &packet);
281     void handleReadBlobRequest(const QByteArray &packet);
282     void handleReadMultipleRequest(const QByteArray &packet);
283     void handleReadByGroupTypeRequest(const QByteArray &packet);
284     void handleWriteRequestOrCommand(const QByteArray &packet);
285     void handlePrepareWriteRequest(const QByteArray &packet);
286     void handleExecuteWriteRequest(const QByteArray &packet);
287 
288     void sendErrorResponse(quint8 request, quint16 handle, quint8 code);
289 
290     using ElemWriter = std::function<void(const Attribute &, char *&)>;
291     void sendListResponse(const QByteArray &packetStart, int elemSize,
292                           const QVector<Attribute> &attributes, const ElemWriter &elemWriter);
293 
294     void sendNotification(QLowEnergyHandle handle);
295     void sendIndication(QLowEnergyHandle handle);
296     void sendNotificationOrIndication(quint8 opCode, QLowEnergyHandle handle);
297     void sendNextIndication();
298 
299     void ensureUniformAttributes(QVector<Attribute> &attributes, const std::function<int(const Attribute &)> &getSize);
300     void ensureUniformUuidSizes(QVector<Attribute> &attributes);
301     void ensureUniformValueSizes(QVector<Attribute> &attributes);
302 
303     using AttributePredicate = std::function<bool(const Attribute &)>;
304     QVector<Attribute> getAttributes(QLowEnergyHandle startHandle, QLowEnergyHandle endHandle,
305             const AttributePredicate &attributePredicate = [](const Attribute &) { return true; });
306 
307     int checkPermissions(const Attribute &attr, QLowEnergyCharacteristic::PropertyType type);
308     int checkReadPermissions(const Attribute &attr);
309     int checkReadPermissions(QVector<Attribute> &attributes);
310 
311     bool verifyMac(const QByteArray &message, const quint128 &csrk, quint32 signCounter,
312                    quint64 expectedMac);
313 
314     void updateLocalAttributeValue(
315             QLowEnergyHandle handle,
316             const QByteArray &value,
317             QLowEnergyCharacteristic &characteristic,
318             QLowEnergyDescriptor &descriptor);
319 
320     void writeCharacteristicForPeripheral(
321             QLowEnergyServicePrivate::CharData &charData,
322             const QByteArray &newValue);
323     void writeCharacteristicForCentral(const QSharedPointer<QLowEnergyServicePrivate> &service,
324             QLowEnergyHandle charHandle,
325             QLowEnergyHandle valueHandle,
326             const QByteArray &newValue,
327             QLowEnergyService::WriteMode mode);
328 
329     void writeDescriptorForPeripheral(
330             const QSharedPointer<QLowEnergyServicePrivate> &service,
331             const QLowEnergyHandle charHandle,
332             const QLowEnergyHandle descriptorHandle,
333             const QByteArray &newValue);
334     void writeDescriptorForCentral(
335             const QLowEnergyHandle charHandle,
336             const QLowEnergyHandle descriptorHandle,
337             const QByteArray &newValue);
338 
339     void restartRequestTimer();
340     void establishL2cpClientSocket();
341     void createServicesForCentralIfRequired();
342 
343 private slots:
344     void l2cpConnected();
345     void l2cpDisconnected();
346     void l2cpErrorChanged(QBluetoothSocket::SocketError);
347     void l2cpReadyRead();
348     void encryptionChangedEvent(const QBluetoothAddress&, bool);
349     void handleGattRequestTimeout();
350     void activeConnectionTerminationDone();
351 };
352 
353 Q_DECLARE_TYPEINFO(QLowEnergyControllerPrivateBluez::Attribute, Q_MOVABLE_TYPE);
354 
355 QT_END_NAMESPACE
356 
357 #endif //QLOWENERGYCONTROLLERBLUEZ_P_H
358