diff options
Diffstat (limited to 'src/bluetooth/bluez')
-rw-r--r-- | src/bluetooth/bluez/bluez5_helper.cpp | 34 | ||||
-rw-r--r-- | src/bluetooth/bluez/bluez5_helper_p.h | 34 | ||||
-rw-r--r-- | src/bluetooth/bluez/bluez_data_p.h | 127 | ||||
-rw-r--r-- | src/bluetooth/bluez/hcimanager.cpp | 323 | ||||
-rw-r--r-- | src/bluetooth/bluez/hcimanager_p.h | 52 | ||||
-rw-r--r-- | src/bluetooth/bluez/servicemap.cpp | 34 | ||||
-rw-r--r-- | src/bluetooth/bluez/servicemap_p.h | 34 |
7 files changed, 506 insertions, 132 deletions
diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp index 14e064e1..2d431367 100644 --- a/src/bluetooth/bluez/bluez5_helper.cpp +++ b/src/bluetooth/bluez/bluez5_helper.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/bluetooth/bluez/bluez5_helper_p.h b/src/bluetooth/bluez/bluez5_helper_p.h index 019fe635..a46810fc 100644 --- a/src/bluetooth/bluez/bluez5_helper_p.h +++ b/src/bluetooth/bluez/bluez5_helper_p.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/bluetooth/bluez/bluez_data_p.h b/src/bluetooth/bluez/bluez_data_p.h index 3722b80d..8c2dc43e 100644 --- a/src/bluetooth/bluez/bluez_data_p.h +++ b/src/bluetooth/bluez/bluez_data_p.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** @@ -52,6 +58,10 @@ QT_BEGIN_NAMESPACE +#define ATTRIBUTE_CHANNEL_ID 4 +#define SIGNALING_CHANNEL_ID 5 +#define SECURITY_CHANNEL_ID 6 + #define BTPROTO_L2CAP 0 #define BTPROTO_HCI 1 #define BTPROTO_RFCOMM 3 @@ -134,22 +144,6 @@ struct sockaddr_rc { // Bt Low Energy related -#define bt_get_unaligned(ptr) \ -({ \ - struct __attribute__((packed)) { \ - __typeof__(*(ptr)) __v; \ - } *__p = (__typeof__(__p)) (ptr); \ - __p->__v; \ -}) - -#define bt_put_unaligned(val, ptr) \ -do { \ - struct __attribute__((packed)) { \ - __typeof__(*(ptr)) __v; \ - } *__p = (__typeof__(__p)) (ptr); \ - __p->__v = (val); \ -} while (0) - #if __BYTE_ORDER == __LITTLE_ENDIAN static inline void btoh128(const quint128 *src, quint128 *dst) @@ -165,15 +159,7 @@ static inline void ntoh128(const quint128 *src, quint128 *dst) dst->data[15 - i] = src->data[i]; } -static inline quint16 bt_get_le16(const void *ptr) -{ - return bt_get_unaligned((const quint16 *) ptr); -} #elif __BYTE_ORDER == __BIG_ENDIAN -static inline quint16 bt_get_le16(const void *ptr) -{ - return qbswap(bt_get_unaligned((const quint16 *) ptr)); -} static inline void btoh128(const quint128 *src, quint128 *dst) { @@ -191,6 +177,25 @@ static inline void ntoh128(const quint128 *src, quint128 *dst) #error "Unknown byte order" #endif +template<typename T> inline T getBtData(const void *ptr) +{ + return qFromLittleEndian<T>(reinterpret_cast<const uchar *>(ptr)); +} + +static inline quint16 bt_get_le16(const void *ptr) +{ + return getBtData<quint16>(ptr); +} + +template<typename T> inline void putBtData(T src, void *dst) +{ + qToLittleEndian(src, reinterpret_cast<uchar *>(dst)); +} +template<> inline void putBtData(quint128 src, void *dst) +{ + btoh128(&src, reinterpret_cast<quint128 *>(dst)); +} + #define hton128(x, y) ntoh128(x, y) // HCI related @@ -203,12 +208,15 @@ static inline void ntoh128(const quint128 *src, quint128 *dst) #define HCI_FILTER 2 // HCI packet types +#define HCI_COMMAND_PKT 0x01 +#define HCI_ACL_PKT 0x02 #define HCI_EVENT_PKT 0x04 #define HCI_VENDOR_PKT 0xff #define HCI_FLT_TYPE_BITS 31 #define HCI_FLT_EVENT_BITS 63 + struct sockaddr_hci { sa_family_t hci_family; unsigned short hci_dev; @@ -333,6 +341,49 @@ typedef struct { } __attribute__ ((packed)) evt_encrypt_change; #define EVT_ENCRYPT_CHANGE_SIZE 4 +#define EVT_CMD_COMPLETE 0x0E +struct evt_cmd_complete { + quint8 ncmd; + quint16 opcode; +} __attribute__ ((packed)); + +struct AclData { + quint16 handle: 12; + quint16 pbFlag: 2; + quint16 bcFlag: 2; + quint16 dataLen; +}; + +struct L2CapHeader { + quint16 length; + quint16 channelId; +}; + +struct hci_command_hdr { + quint16 opcode; /* OCF & OGF */ + quint8 plen; +} __attribute__ ((packed)); + +enum OpCodeGroupField { + OgfLinkControl = 0x8, +}; + +enum OpCodeCommandField { + OcfLeSetAdvParams = 0x6, + OcfLeReadTxPowerLevel = 0x7, + OcfLeSetAdvData = 0x8, + OcfLeSetScanResponseData = 0x9, + OcfLeSetAdvEnable = 0xa, + OcfLeClearWhiteList = 0x10, + OcfLeAddToWhiteList = 0x11, + OcfLeConnectionUpdate = 0x13, +}; + +/* Command opcode pack/unpack */ +#define opCodePack(ogf, ocf) (quint16(((ocf) & 0x03ff)|((ogf) << 10))) +#define ogfFromOpCode(op) ((op) >> 10) +#define ocfFromOpCode(op) ((op) & 0x03ff) + QT_END_NAMESPACE #endif // BLUEZ_DATA_P_H diff --git a/src/bluetooth/bluez/hcimanager.cpp b/src/bluetooth/bluez/hcimanager.cpp index 16314f56..93bf941b 100644 --- a/src/bluetooth/bluez/hcimanager.cpp +++ b/src/bluetooth/bluez/hcimanager.cpp @@ -1,32 +1,38 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2013 Javier S. Pedro <maemo@javispedro.com> -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Javier S. Pedro <maemo@javispedro.com> +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtBluetooth module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** @@ -35,13 +41,16 @@ #include "hcimanager_p.h" #include "qbluetoothsocket_p.h" +#include "qlowenergyconnectionparameters.h" -#include <QtCore/QLoggingCategory> +#include <QtCore/qloggingcategory.h> +#include <cstring> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> +#include <sys/uio.h> #include <unistd.h> #define HCIGETCONNLIST _IOR('H', 212, int) @@ -174,6 +183,59 @@ bool HciManager::monitorEvent(HciManager::HciEvent event) return true; } +bool HciManager::monitorAclPackets() +{ + if (!isValid()) + return false; + + hci_filter filter; + socklen_t length = sizeof(hci_filter); + if (getsockopt(hciSocket, SOL_HCI, HCI_FILTER, &filter, &length) < 0) { + qCWarning(QT_BT_BLUEZ) << "Cannot retrieve HCI filter settings"; + return false; + } + + hci_filter_set_ptype(HCI_ACL_PKT, &filter); + hci_filter_all_events(&filter); + + if (setsockopt(hciSocket, SOL_HCI, HCI_FILTER, &filter, sizeof(hci_filter)) < 0) { + qCWarning(QT_BT_BLUEZ) << "Could not set HCI socket options:" << strerror(errno); + return false; + } + + return true; +} + +bool HciManager::sendCommand(OpCodeGroupField ogf, OpCodeCommandField ocf, const QByteArray ¶meters) +{ + qCDebug(QT_BT_BLUEZ) << "sending command; ogf:" << ogf << "ocf:" << ocf; + quint8 packetType = HCI_COMMAND_PKT; + hci_command_hdr command = { + opCodePack(ogf, ocf), + static_cast<uint8_t>(parameters.count()) + }; + static_assert(sizeof command == 3, "unexpected struct size"); + struct iovec iv[3]; + iv[0].iov_base = &packetType; + iv[0].iov_len = 1; + iv[1].iov_base = &command; + iv[1].iov_len = sizeof command; + int ivn = 2; + if (!parameters.isEmpty()) { + iv[2].iov_base = const_cast<char *>(parameters.constData()); // const_cast is safe, since iov_base will not get modified. + iv[2].iov_len = parameters.count(); + ++ivn; + } + while (writev(hciSocket, iv, ivn) < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + qCDebug(QT_BT_BLUEZ()) << "hci command failure:" << strerror(errno); + return false; + } + qCDebug(QT_BT_BLUEZ) << "command sent successfully"; + return true; +} + /* * Unsubscribe from all events */ @@ -226,13 +288,106 @@ QBluetoothAddress HciManager::addressForConnectionHandle(quint16 handle) const return QBluetoothAddress(); } +quint16 forceIntervalIntoRange(double connectionInterval) +{ + return qMin<double>(qMax<double>(7.5, connectionInterval), 4000) / 1.25; +} + +struct ConnectionUpdateData { + quint16 minInterval; + quint16 maxInterval; + quint16 slaveLatency; + quint16 timeout; +}; +ConnectionUpdateData connectionUpdateData(const QLowEnergyConnectionParameters ¶ms) +{ + ConnectionUpdateData data; + const quint16 minInterval = forceIntervalIntoRange(params.minimumInterval()); + const quint16 maxInterval = forceIntervalIntoRange(params.maximumInterval()); + data.minInterval = qToLittleEndian(minInterval); + data.maxInterval = qToLittleEndian(maxInterval); + const quint16 latency = qMax<quint16>(0, qMin<quint16>(params.latency(), 499)); + data.slaveLatency = qToLittleEndian(latency); + const quint16 timeout + = qMax<quint16>(100, qMin<quint16>(32000, params.supervisionTimeout())) / 10; + data.timeout = qToLittleEndian(timeout); + return data; +} + +bool HciManager::sendConnectionUpdateCommand(quint16 handle, + const QLowEnergyConnectionParameters ¶ms) +{ + struct CommandParams { + quint16 handle; + ConnectionUpdateData data; + quint16 minCeLength; + quint16 maxCeLength; + } commandParams; + commandParams.handle = qToLittleEndian(handle); + commandParams.data = connectionUpdateData(params); + commandParams.minCeLength = 0; + commandParams.maxCeLength = qToLittleEndian(quint16(0xffff)); + const QByteArray data = QByteArray::fromRawData(reinterpret_cast<char *>(&commandParams), + sizeof commandParams); + return sendCommand(OgfLinkControl, OcfLeConnectionUpdate, data); +} + +bool HciManager::sendConnectionParameterUpdateRequest(quint16 handle, + const QLowEnergyConnectionParameters ¶ms) +{ + ConnectionUpdateData connUpdateData = connectionUpdateData(params); + + // Vol 3, part A, 4 + struct SignalingPacket { + quint8 code; + quint8 identifier; + quint16 length; + } signalingPacket; + signalingPacket.code = 0x12; + signalingPacket.identifier = ++sigPacketIdentifier; + const quint16 sigPacketLen = sizeof connUpdateData; + signalingPacket.length = qToLittleEndian(sigPacketLen); + + L2CapHeader l2CapHeader; + const quint16 l2CapHeaderLen = sizeof signalingPacket + sigPacketLen; + l2CapHeader.length = qToLittleEndian(l2CapHeaderLen); + l2CapHeader.channelId = qToLittleEndian(quint16(SIGNALING_CHANNEL_ID)); + + // Vol 2, part E, 5.4.2 + AclData aclData; + aclData.handle = qToLittleEndian(handle); // Works because the next two values are zero. + aclData.pbFlag = 0; + aclData.bcFlag = 0; + aclData.dataLen = qToLittleEndian(quint16(sizeof l2CapHeader + l2CapHeaderLen)); + + struct iovec iv[5]; + quint8 packetType = HCI_ACL_PKT; + iv[0].iov_base = &packetType; + iv[0].iov_len = 1; + iv[1].iov_base = &aclData; + iv[1].iov_len = sizeof aclData; + iv[2].iov_base = &l2CapHeader; + iv[2].iov_len = sizeof l2CapHeader; + iv[3].iov_base = &signalingPacket; + iv[3].iov_len = sizeof signalingPacket; + iv[4].iov_base = &connUpdateData; + iv[4].iov_len = sizeof connUpdateData; + while (writev(hciSocket, iv, sizeof iv / sizeof *iv) < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + qCDebug(QT_BT_BLUEZ()) << "failure writing HCI ACL packet:" << strerror(errno); + return false; + } + qCDebug(QT_BT_BLUEZ) << "Connection Update Request packet sent successfully"; + return true; +} + /*! * Process all incoming HCI events. Function cannot process anything else but events. */ void HciManager::_q_readNotify() { - - unsigned char buffer[HCI_MAX_EVENT_SIZE]; + unsigned char buffer[qMax<int>(HCI_MAX_EVENT_SIZE, sizeof(AclData))]; int size; size = ::read(hciSocket, buffer, sizeof(buffer)); @@ -243,16 +398,29 @@ void HciManager::_q_readNotify() return; } - const unsigned char *data = buffer; + switch (buffer[0]) { + case HCI_EVENT_PKT: + handleHciEventPacket(buffer + 1, size - 1); + break; + case HCI_ACL_PKT: + handleHciAclPacket(buffer + 1, size - 1); + break; + default: + qCWarning(QT_BT_BLUEZ) << "Ignoring unexpected HCI packet type" << buffer[0]; + } +} - // Not interested in anything but valid HCI events - if ((size < HCI_EVENT_HDR_SIZE + 1) || buffer[0] != HCI_EVENT_PKT) +void HciManager::handleHciEventPacket(const quint8 *data, int size) +{ + if (size < HCI_EVENT_HDR_SIZE) { + qCWarning(QT_BT_BLUEZ) << "Unexpected HCI event packet size:" << size; return; + } - hci_event_hdr *header = (hci_event_hdr *)(&buffer[1]); + hci_event_hdr *header = (hci_event_hdr *) data; - size = size - HCI_EVENT_HDR_SIZE - 1; - data = data + HCI_EVENT_HDR_SIZE + 1; + size -= HCI_EVENT_HDR_SIZE; + data += HCI_EVENT_HDR_SIZE; if (header->plen != size) { qCWarning(QT_BT_BLUEZ) << "Invalid HCI event packet size"; @@ -275,10 +443,117 @@ void HciManager::_q_readNotify() emit encryptionChangedEvent(remoteDevice, event->status == 0); } break; + case EVT_CMD_COMPLETE: { + auto * const event = reinterpret_cast<const evt_cmd_complete *>(data); + static_assert(sizeof *event == 3, "unexpected struct size"); + + // There is always a status byte right after the generic structure. + Q_ASSERT(size > static_cast<int>(sizeof *event)); + const quint8 status = data[sizeof *event]; + const auto additionalData = QByteArray(reinterpret_cast<const char *>(data) + + sizeof *event + 1, size - sizeof *event - 1); + emit commandCompleted(event->opcode, status, additionalData); + } + break; + case LeMetaEvent: + handleLeMetaEvent(data); + break; default: break; } + } +void HciManager::handleHciAclPacket(const quint8 *data, int size) +{ + if (size < int(sizeof(AclData))) { + qCWarning(QT_BT_BLUEZ) << "Unexpected HCI ACL packet size"; + return; + } + + quint16 rawAclData[sizeof(AclData) / sizeof(quint16)]; + rawAclData[0] = bt_get_le16(data); + rawAclData[1] = bt_get_le16(data + sizeof(quint16)); + const AclData *aclData = reinterpret_cast<AclData *>(rawAclData); + data += sizeof *aclData; + size -= sizeof *aclData; + + // Consider only directed, complete messages. + if ((aclData->pbFlag != 0 && aclData->pbFlag != 2) || aclData->bcFlag != 0) + return; + + if (size < aclData->dataLen) { + qCWarning(QT_BT_BLUEZ) << "HCI ACL packet data size" << size + << "is smaller than specified size" << aclData->dataLen; + return; + } + +// qCDebug(QT_BT_BLUEZ) << "handle:" << aclData->handle << "PB:" << aclData->pbFlag +// << "BC:" << aclData->bcFlag << "data len:" << aclData->dataLen; + + if (size < int(sizeof(L2CapHeader))) { + qCWarning(QT_BT_BLUEZ) << "Unexpected HCI ACL packet size"; + return; + } + L2CapHeader l2CapHeader = *reinterpret_cast<const L2CapHeader*>(data); + l2CapHeader.channelId = qFromLittleEndian(l2CapHeader.channelId); + l2CapHeader.length = qFromLittleEndian(l2CapHeader.length); + data += sizeof l2CapHeader; + size -= sizeof l2CapHeader; + if (size < l2CapHeader.length) { + qCWarning(QT_BT_BLUEZ) << "L2Cap payload size" << size << "is smaller than specified size" + << l2CapHeader.length; + return; + } +// qCDebug(QT_BT_BLUEZ) << "l2cap channel id:" << l2CapHeader.channelId +// << "payload length:" << l2CapHeader.length; + if (l2CapHeader.channelId != SECURITY_CHANNEL_ID) + return; + if (*data != 0xa) // "Signing Information". Spec v4.2, Vol 3, Part H, 3.6.6 + return; + if (size != 17) { + qCWarning(QT_BT_BLUEZ) << "Unexpected key size" << size << "in Signing Information packet"; + return; + } + quint128 csrk; + memcpy(&csrk, data + 1, sizeof csrk); + const bool isRemoteKey = aclData->pbFlag == 2; + emit signatureResolvingKeyReceived(aclData->handle, isRemoteKey, csrk); +} + +void HciManager::handleLeMetaEvent(const quint8 *data) +{ + // Spec v4.2, Vol 2, part E, 7.7.65ff + switch (*data) { + case 0x1: { + const quint16 handle = bt_get_le16(data + 2); + emit connectionComplete(handle); + break; + } + case 0x3: { + // TODO: From little endian! + struct ConnectionUpdateData { + quint8 status; + quint16 handle; + quint16 interval; + quint16 latency; + quint16 timeout; + } __attribute((packed)); + const auto * const updateData + = reinterpret_cast<const ConnectionUpdateData *>(data + 1); + if (updateData->status == 0) { + QLowEnergyConnectionParameters params; + const double interval = qFromLittleEndian(updateData->interval) * 1.25; + params.setIntervalRange(interval, interval); + params.setLatency(qFromLittleEndian(updateData->latency)); + params.setSupervisionTimeout(qFromLittleEndian(updateData->timeout) * 10); + emit connectionUpdate(qFromLittleEndian(updateData->handle), params); + } + break; + } + default: + break; + } +} QT_END_NAMESPACE diff --git a/src/bluetooth/bluez/hcimanager_p.h b/src/bluetooth/bluez/hcimanager_p.h index 9dd2ceee..3bae92e5 100644 --- a/src/bluetooth/bluez/hcimanager_p.h +++ b/src/bluetooth/bluez/hcimanager_p.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** @@ -53,12 +59,16 @@ QT_BEGIN_NAMESPACE +class QLowEnergyConnectionParameters; + class HciManager : public QObject { Q_OBJECT public: enum HciEvent { EncryptChangeEvent = EVT_ENCRYPT_CHANGE, + CommandCompleteEvent = EVT_CMD_COMPLETE, + LeMetaEvent = 0x3e, }; explicit HciManager(const QBluetoothAddress &deviceAdapter, QObject *parent = 0); @@ -66,21 +76,35 @@ public: bool isValid() const; bool monitorEvent(HciManager::HciEvent event); + bool monitorAclPackets(); + bool sendCommand(OpCodeGroupField ogf, OpCodeCommandField ocf, const QByteArray ¶meters); + void stopEvents(); QBluetoothAddress addressForConnectionHandle(quint16 handle) const; + bool sendConnectionUpdateCommand(quint16 handle, const QLowEnergyConnectionParameters ¶ms); + bool sendConnectionParameterUpdateRequest(quint16 handle, + const QLowEnergyConnectionParameters ¶ms); signals: void encryptionChangedEvent(const QBluetoothAddress &address, bool wasSuccess); + void commandCompleted(quint16 opCode, quint8 status, const QByteArray &data); + void connectionComplete(quint16 handle); + void connectionUpdate(quint16 handle, const QLowEnergyConnectionParameters ¶meters); + void signatureResolvingKeyReceived(quint16 connHandle, bool remoteKey, const quint128 &csrk); private slots: void _q_readNotify(); private: int hciForAddress(const QBluetoothAddress &deviceAdapter); + void handleHciEventPacket(const quint8 *data, int size); + void handleHciAclPacket(const quint8 *data, int size); + void handleLeMetaEvent(const quint8 *data); int hciSocket; int hciDev; + quint8 sigPacketIdentifier = 0; QSocketNotifier *notifier; QSet<HciManager::HciEvent> runningEvents; }; diff --git a/src/bluetooth/bluez/servicemap.cpp b/src/bluetooth/bluez/servicemap.cpp index dcc8760a..46616cbe 100644 --- a/src/bluetooth/bluez/servicemap.cpp +++ b/src/bluetooth/bluez/servicemap.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** diff --git a/src/bluetooth/bluez/servicemap_p.h b/src/bluetooth/bluez/servicemap_p.h index 56f8d61e..572c2790 100644 --- a/src/bluetooth/bluez/servicemap_p.h +++ b/src/bluetooth/bluez/servicemap_p.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** 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$ ** |