diff options
Diffstat (limited to 'src/bluetooth/qlowenergycontroller_bluez_p.h')
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluez_p.h | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/src/bluetooth/qlowenergycontroller_bluez_p.h b/src/bluetooth/qlowenergycontroller_bluez_p.h new file mode 100644 index 00000000..66c048be --- /dev/null +++ b/src/bluetooth/qlowenergycontroller_bluez_p.h @@ -0,0 +1,357 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLOWENERGYCONTROLLERBLUEZ_P_H +#define QLOWENERGYCONTROLLERBLUEZ_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qglobal.h> +#include <QtCore/QQueue> +#include <QtCore/QVector> +#include <QtBluetooth/qbluetooth.h> +#include <QtBluetooth/qlowenergycharacteristic.h> +#include "qlowenergycontroller.h" +#include "qlowenergycontrollerbase_p.h" + +#include <QtBluetooth/QBluetoothSocket> +#include <functional> + +QT_BEGIN_NAMESPACE + +class QLowEnergyServiceData; +class QTimer; + +class HciManager; +class LeCmacCalculator; +class QSocketNotifier; +class RemoteDeviceManager; + +extern void registerQLowEnergyControllerMetaType(); + +class QLeAdvertiser; + +class QLowEnergyControllerPrivateBluez final: public QLowEnergyControllerPrivate +{ + Q_OBJECT +public: + QLowEnergyControllerPrivateBluez(); + ~QLowEnergyControllerPrivateBluez() override; + + void init() override; + + void connectToDevice() override; + void disconnectFromDevice() override; + + void discoverServices() override; + void discoverServiceDetails(const QBluetoothUuid &service) override; + + void startAdvertising(const QLowEnergyAdvertisingParameters ¶ms, + const QLowEnergyAdvertisingData &advertisingData, + const QLowEnergyAdvertisingData &scanResponseData) override; + void stopAdvertising() override; + + void requestConnectionUpdate(const QLowEnergyConnectionParameters ¶ms) override; + + // read data + void readCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service, + const QLowEnergyHandle charHandle) override; + void readDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service, + const QLowEnergyHandle charHandle, + const QLowEnergyHandle descriptorHandle) override; + + // write data + void writeCharacteristic(const QSharedPointer<QLowEnergyServicePrivate> service, + const QLowEnergyHandle charHandle, + const QByteArray &newValue, QLowEnergyService::WriteMode mode) override; + void writeDescriptor(const QSharedPointer<QLowEnergyServicePrivate> service, + const QLowEnergyHandle charHandle, + const QLowEnergyHandle descriptorHandle, + const QByteArray &newValue) override; + + void addToGenericAttributeList(const QLowEnergyServiceData &service, + QLowEnergyHandle startHandle) override; + + struct Attribute { + Attribute() : handle(0) {} + + QLowEnergyHandle handle; + QLowEnergyHandle groupEndHandle; + QLowEnergyCharacteristic::PropertyTypes properties; + QBluetooth::AttAccessConstraints readConstraints; + QBluetooth::AttAccessConstraints writeConstraints; + QBluetoothUuid type; + QByteArray value; + int minLength; + int maxLength; + }; + QVector<Attribute> localAttributes; + +private: + quint16 connectionHandle = 0; + QBluetoothSocket *l2cpSocket; + struct Request { + quint8 command; + QByteArray payload; + // TODO reference below is ugly but until we know all commands and their + // requirements this is WIP + QVariant reference; + QVariant reference2; + }; + QQueue<Request> openRequests; + + struct WriteRequest { + WriteRequest() {} + WriteRequest(quint16 h, quint16 o, const QByteArray &v) + : handle(h), valueOffset(o), value(v) {} + quint16 handle; + quint16 valueOffset; + QByteArray value; + }; + QVector<WriteRequest> openPrepareWriteRequests; + + // Invariant: !scheduledIndications.isEmpty => indicationInFlight == true + QVector<QLowEnergyHandle> scheduledIndications; + bool indicationInFlight = false; + + struct TempClientConfigurationData { + TempClientConfigurationData(QLowEnergyServicePrivate::DescData *dd = nullptr, + QLowEnergyHandle chHndl = 0, QLowEnergyHandle coHndl = 0) + : descData(dd), charValueHandle(chHndl), configHandle(coHndl) {} + + QLowEnergyServicePrivate::DescData *descData; + QLowEnergyHandle charValueHandle; + QLowEnergyHandle configHandle; + }; + + struct ClientConfigurationData { + ClientConfigurationData(QLowEnergyHandle chHndl = 0, QLowEnergyHandle coHndl = 0, + quint16 val = 0) + : charValueHandle(chHndl), configHandle(coHndl), configValue(val) {} + + QLowEnergyHandle charValueHandle; + QLowEnergyHandle configHandle; + quint16 configValue; + bool charValueWasUpdated = false; + }; + QHash<quint64, QVector<ClientConfigurationData>> clientConfigData; + + struct SigningData { + SigningData() = default; + SigningData(const quint128 &csrk, quint32 signCounter = quint32(-1)) + : key(csrk), counter(signCounter) {} + + quint128 key; + quint32 counter = quint32(-1); + }; + QHash<quint64, SigningData> signingData; + LeCmacCalculator *cmacCalculator = nullptr; + + bool requestPending; + quint16 mtuSize; + int securityLevelValue; + bool encryptionChangePending; + bool receivedMtuExchangeRequest = false; + + HciManager *hciManager; + QLeAdvertiser *advertiser; + QSocketNotifier *serverSocketNotifier; + QTimer *requestTimer = nullptr; + RemoteDeviceManager* device1Manager = nullptr; + + /* + Defines the maximum number of milliseconds the implementation will + wait for requests that require a response. + + This addresses the problem that some non-conformant BTLE devices + do not implement the request/response system properly. In such cases + the queue system would hang forever. + + Once timeout has been triggered we gracefully continue with the next request. + Depending on the type of the timed out ATT command we either ignore it + or artifically trigger an error response to ensure the API gives the + appropriate response. Potentially this can cause problems when the + response for the dropped requests arrives very late. That's why a big warning + is printed about the compromised state when a timeout is triggered. + */ + int gattRequestTimeout = 20000; + + void handleConnectionRequest(); + void closeServerSocket(); + + bool isBonded() const; + QVector<TempClientConfigurationData> gatherClientConfigData(); + void storeClientConfigurations(); + void restoreClientConfigurations(); + + enum SigningKeyType { LocalSigningKey, RemoteSigningKey }; + void loadSigningDataIfNecessary(SigningKeyType keyType); + void storeSignCounter(SigningKeyType keyType) const; + QString signingKeySettingsGroup(SigningKeyType keyType) const; + QString keySettingsFilePath() const; + + void sendPacket(const QByteArray &packet); + void sendNextPendingRequest(); + void processReply(const Request &request, const QByteArray &reply); + + void sendReadByGroupRequest(QLowEnergyHandle start, QLowEnergyHandle end, + quint16 type); + void sendReadByTypeRequest(QSharedPointer<QLowEnergyServicePrivate> serviceData, + QLowEnergyHandle nextHandle, quint16 attributeType); + void sendReadValueRequest(QLowEnergyHandle attributeHandle, bool isDescriptor); + void readServiceValues(const QBluetoothUuid &service, + bool readCharacteristics); + void readServiceValuesByOffset(uint handleData, quint16 offset, + bool isLastValue); + + void discoverServiceDescriptors(const QBluetoothUuid &serviceUuid); + void discoverNextDescriptor(QSharedPointer<QLowEnergyServicePrivate> serviceData, + const QList<QLowEnergyHandle> pendingCharHandles, + QLowEnergyHandle startingHandle); + void processUnsolicitedReply(const QByteArray &msg); + void exchangeMTU(); + bool setSecurityLevel(int level); + int securityLevel() const; + void sendExecuteWriteRequest(const QLowEnergyHandle attrHandle, + const QByteArray &newValue, + bool isCancelation); + void sendNextPrepareWriteRequest(const QLowEnergyHandle handle, + const QByteArray &newValue, quint16 offset); + bool increaseEncryptLevelfRequired(quint8 errorCode); + + void resetController(); + + void handleAdvertisingError(); + + bool checkPacketSize(const QByteArray &packet, int minSize, int maxSize = -1); + bool checkHandle(const QByteArray &packet, QLowEnergyHandle handle); + bool checkHandlePair(quint8 request, QLowEnergyHandle startingHandle, + QLowEnergyHandle endingHandle); + + void handleExchangeMtuRequest(const QByteArray &packet); + void handleFindInformationRequest(const QByteArray &packet); + void handleFindByTypeValueRequest(const QByteArray &packet); + void handleReadByTypeRequest(const QByteArray &packet); + void handleReadRequest(const QByteArray &packet); + void handleReadBlobRequest(const QByteArray &packet); + void handleReadMultipleRequest(const QByteArray &packet); + void handleReadByGroupTypeRequest(const QByteArray &packet); + void handleWriteRequestOrCommand(const QByteArray &packet); + void handlePrepareWriteRequest(const QByteArray &packet); + void handleExecuteWriteRequest(const QByteArray &packet); + + void sendErrorResponse(quint8 request, quint16 handle, quint8 code); + + using ElemWriter = std::function<void(const Attribute &, char *&)>; + void sendListResponse(const QByteArray &packetStart, int elemSize, + const QVector<Attribute> &attributes, const ElemWriter &elemWriter); + + void sendNotification(QLowEnergyHandle handle); + void sendIndication(QLowEnergyHandle handle); + void sendNotificationOrIndication(quint8 opCode, QLowEnergyHandle handle); + void sendNextIndication(); + + void ensureUniformAttributes(QVector<Attribute> &attributes, const std::function<int(const Attribute &)> &getSize); + void ensureUniformUuidSizes(QVector<Attribute> &attributes); + void ensureUniformValueSizes(QVector<Attribute> &attributes); + + using AttributePredicate = std::function<bool(const Attribute &)>; + QVector<Attribute> getAttributes(QLowEnergyHandle startHandle, QLowEnergyHandle endHandle, + const AttributePredicate &attributePredicate = [](const Attribute &) { return true; }); + + int checkPermissions(const Attribute &attr, QLowEnergyCharacteristic::PropertyType type); + int checkReadPermissions(const Attribute &attr); + int checkReadPermissions(QVector<Attribute> &attributes); + + bool verifyMac(const QByteArray &message, const quint128 &csrk, quint32 signCounter, + quint64 expectedMac); + + void updateLocalAttributeValue( + QLowEnergyHandle handle, + const QByteArray &value, + QLowEnergyCharacteristic &characteristic, + QLowEnergyDescriptor &descriptor); + + void writeCharacteristicForPeripheral( + QLowEnergyServicePrivate::CharData &charData, + const QByteArray &newValue); + void writeCharacteristicForCentral(const QSharedPointer<QLowEnergyServicePrivate> &service, + QLowEnergyHandle charHandle, + QLowEnergyHandle valueHandle, + const QByteArray &newValue, + QLowEnergyService::WriteMode mode); + + void writeDescriptorForPeripheral( + const QSharedPointer<QLowEnergyServicePrivate> &service, + const QLowEnergyHandle charHandle, + const QLowEnergyHandle descriptorHandle, + const QByteArray &newValue); + void writeDescriptorForCentral( + const QLowEnergyHandle charHandle, + const QLowEnergyHandle descriptorHandle, + const QByteArray &newValue); + + void restartRequestTimer(); + void establishL2cpClientSocket(); + void createServicesForCentralIfRequired(); + +private slots: + void l2cpConnected(); + void l2cpDisconnected(); + void l2cpErrorChanged(QBluetoothSocket::SocketError); + void l2cpReadyRead(); + void encryptionChangedEvent(const QBluetoothAddress&, bool); + void handleGattRequestTimeout(); + void activeConnectionTerminationDone(); +}; + +Q_DECLARE_TYPEINFO(QLowEnergyControllerPrivateBluez::Attribute, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + +#endif //QLOWENERGYCONTROLLERBLUEZ_P_H |