summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/bluez
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/bluez')
-rw-r--r--src/bluetooth/bluez/bluez_data_p.h24
-rw-r--r--src/bluetooth/bluez/hcimanager.cpp123
-rw-r--r--src/bluetooth/bluez/hcimanager_p.h4
3 files changed, 130 insertions, 21 deletions
diff --git a/src/bluetooth/bluez/bluez_data_p.h b/src/bluetooth/bluez/bluez_data_p.h
index e8d1ec62..8c2dc43e 100644
--- a/src/bluetooth/bluez/bluez_data_p.h
+++ b/src/bluetooth/bluez/bluez_data_p.h
@@ -58,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
@@ -173,9 +177,14 @@ 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 qFromLittleEndian<quint16>(reinterpret_cast<const uchar *>(ptr));
+ return getBtData<quint16>(ptr);
}
template<typename T> inline void putBtData(T src, void *dst)
@@ -200,6 +209,7 @@ template<> inline void putBtData(quint128 src, void *dst)
// HCI packet types
#define HCI_COMMAND_PKT 0x01
+#define HCI_ACL_PKT 0x02
#define HCI_EVENT_PKT 0x04
#define HCI_VENDOR_PKT 0xff
@@ -337,6 +347,18 @@ struct evt_cmd_complete {
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;
diff --git a/src/bluetooth/bluez/hcimanager.cpp b/src/bluetooth/bluez/hcimanager.cpp
index 123a16ab..35ce2184 100644
--- a/src/bluetooth/bluez/hcimanager.cpp
+++ b/src/bluetooth/bluez/hcimanager.cpp
@@ -183,6 +183,29 @@ 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;
@@ -325,28 +348,20 @@ bool HciManager::sendConnectionParameterUpdateRequest(quint16 handle,
const quint16 sigPacketLen = sizeof connUpdateData;
signalingPacket.length = qToLittleEndian(sigPacketLen);
- struct L2CapHeader {
- quint16 length;
- quint16 channelId;
- } l2CapHeader;
+ L2CapHeader l2CapHeader;
const quint16 l2CapHeaderLen = sizeof signalingPacket + sigPacketLen;
l2CapHeader.length = qToLittleEndian(l2CapHeaderLen);
- l2CapHeader.channelId = qToLittleEndian(quint16(5));
+ l2CapHeader.channelId = qToLittleEndian(quint16(SIGNALING_CHANNEL_ID));
// Vol 2, part E, 5.4.2
- struct AclData {
- quint16 handle: 12;
- quint16 pbFlag: 2;
- quint16 bcFlag: 2;
- quint16 dataLen;
- } aclData;
+ 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 = 2;
+ quint8 packetType = HCI_ACL_PKT;
iv[0].iov_base = &packetType;
iv[0].iov_len = 1;
iv[1].iov_base = &aclData;
@@ -372,8 +387,7 @@ bool HciManager::sendConnectionParameterUpdateRequest(quint16 handle,
*/
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));
@@ -384,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";
@@ -434,6 +461,62 @@ void HciManager::_q_readNotify()
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;
+ 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;
+
+ // Consider only directed, complete messages from controller to host (i.e. incoming packets).
+ if (aclData->pbFlag != 2 || aclData->bcFlag != 0)
+ return;
+
+ 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);
+ emit signatureResolvingKeyReceived(aclData->handle, csrk);
}
void HciManager::handleLeMetaEvent(const quint8 *data)
diff --git a/src/bluetooth/bluez/hcimanager_p.h b/src/bluetooth/bluez/hcimanager_p.h
index b2edb15b..eb899c79 100644
--- a/src/bluetooth/bluez/hcimanager_p.h
+++ b/src/bluetooth/bluez/hcimanager_p.h
@@ -76,6 +76,7 @@ public:
bool isValid() const;
bool monitorEvent(HciManager::HciEvent event);
+ bool monitorAclPackets();
bool sendCommand(OpCodeGroupField ogf, OpCodeCommandField ocf, const QByteArray &parameters);
void stopEvents();
@@ -90,12 +91,15 @@ signals:
void commandCompleted(quint16 opCode, quint8 status, const QByteArray &data);
void connectionComplete(quint16 handle);
void connectionUpdate(quint16 handle, const QLowEnergyConnectionParameters &parameters);
+ void signatureResolvingKeyReceived(quint16 connHandle, 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;