summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/bluez
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/bluez')
-rw-r--r--src/bluetooth/bluez/bluez5_helper.cpp34
-rw-r--r--src/bluetooth/bluez/bluez5_helper_p.h34
-rw-r--r--src/bluetooth/bluez/bluez_data_p.h127
-rw-r--r--src/bluetooth/bluez/hcimanager.cpp323
-rw-r--r--src/bluetooth/bluez/hcimanager_p.h52
-rw-r--r--src/bluetooth/bluez/servicemap.cpp34
-rw-r--r--src/bluetooth/bluez/servicemap_p.h34
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 &parameters)
+{
+ 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 &params)
+{
+ 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 &params)
+{
+ 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 &params)
+{
+ 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 &parameters);
+
void stopEvents();
QBluetoothAddress addressForConnectionHandle(quint16 handle) const;
+ bool sendConnectionUpdateCommand(quint16 handle, const QLowEnergyConnectionParameters &params);
+ bool sendConnectionParameterUpdateRequest(quint16 handle,
+ const QLowEnergyConnectionParameters &params);
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 &parameters);
+ 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$
**