From 8650ab69889218ec857475da3dfd99624f714585 Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Tue, 9 Sep 2014 14:29:26 +0200 Subject: Add ability to set the security level of the l2cp connection Later this will be needed to read/write authorized and encrypted characteristic/descriptor values. Change-Id: Ibc70b65b51723d6e0668ee177f5dbd1df2ba047f Reviewed-by: Lars Knoll --- src/bluetooth/bluez/bluez_data_p.h | 13 ++++ src/bluetooth/qlowenergycontroller_bluez.cpp | 89 ++++++++++++++++++++++++++++ src/bluetooth/qlowenergycontroller_p.h | 3 + 3 files changed, 105 insertions(+) diff --git a/src/bluetooth/bluez/bluez_data_p.h b/src/bluetooth/bluez/bluez_data_p.h index 743f09dc..3e5b0245 100644 --- a/src/bluetooth/bluez/bluez_data_p.h +++ b/src/bluetooth/bluez/bluez_data_p.h @@ -54,6 +54,9 @@ #define SOL_L2CAP 6 #define SOL_RFCOMM 18 +#ifndef SOL_BLUETOOTH +#define SOL_BLUETOOTH 274 +#endif #define RFCOMM_LM 0x03 @@ -68,6 +71,16 @@ #define L2CAP_LM_TRUSTED 0x0008 #define L2CAP_LM_SECURE 0x0020 +#define BT_SECURITY 4 +struct bt_security { + uint8_t level; + uint8_t key_size; +}; +#define BT_SECURITY_SDP 0 +#define BT_SECURITY_LOW 1 +#define BT_SECURITY_MEDIUM 2 +#define BT_SECURITY_HIGH 3 + #define BDADDR_LE_PUBLIC 0x01 #define BDADDR_LE_RANDOM 0x02 diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp index 28f1bd5c..1659ec42 100644 --- a/src/bluetooth/qlowenergycontroller_bluez.cpp +++ b/src/bluetooth/qlowenergycontroller_bluez.cpp @@ -246,6 +246,7 @@ void QLowEnergyControllerPrivate::l2cpConnected() { Q_Q(QLowEnergyController); + securityLevel(); exchangeMTU(); setState(QLowEnergyController::ConnectedState); @@ -1148,6 +1149,94 @@ void QLowEnergyControllerPrivate::exchangeMTU() sendNextPendingRequest(); } +int QLowEnergyControllerPrivate::securityLevel() const +{ + qCDebug(QT_BT_BLUEZ) << "Getting security level"; + + int socket = l2cpSocket->socketDescriptor(); + if (socket < 0) { + qCWarning(QT_BT_BLUEZ) << "Invalid l2cp socket, aborting getting of sec level"; + return -1; + } + + struct bt_security secData; + socklen_t length = sizeof(secData); + memset(&secData, 0, length); + + if (getsockopt(socket, SOL_BLUETOOTH, BT_SECURITY, &secData, &length) == 0) { + qCDebug(QT_BT_BLUEZ) << "Current l2cp sec level:" << secData.level; + return secData.level; + } + + if (errno != ENOPROTOOPT) //older kernel, fall back to L2CAP_LM option + return -1; + + // cater for older kernels + int optval; + length = sizeof(optval); + if (getsockopt(socket, SOL_L2CAP, L2CAP_LM, &optval, &length) == 0) { + int level = BT_SECURITY_SDP; + if (optval & L2CAP_LM_AUTH) + level = BT_SECURITY_LOW; + if (optval & L2CAP_LM_ENCRYPT) + level = BT_SECURITY_MEDIUM; + if (optval & L2CAP_LM_SECURE) + level = BT_SECURITY_HIGH; + + qDebug() << "Current l2cp sec level (old):" << level; + return level; + } + + return -1; +} + +bool QLowEnergyControllerPrivate::setSecurityLevel(int level) +{ + qCDebug(QT_BT_BLUEZ) << "Setting security level:" << level; + + if (level > BT_SECURITY_HIGH || level < BT_SECURITY_LOW) + return false; + + int socket = l2cpSocket->socketDescriptor(); + if (socket < 0) { + qCWarning(QT_BT_BLUEZ) << "Invalid l2cp socket, aborting setting of sec level"; + return false; + } + + struct bt_security secData; + socklen_t length = sizeof(secData); + memset(&secData, 0, length); + secData.level = level; + + if (setsockopt(socket, SOL_BLUETOOTH, BT_SECURITY, &secData, length) == 0) { + qCDebug(QT_BT_BLUEZ) << "Setting new l2cp sec level:" << secData.level; + return true; + } + + if (errno != ENOPROTOOPT) //older kernel + return false; + + int optval = 0; + switch (level) { // fall through intendeds + case BT_SECURITY_HIGH: + optval |= L2CAP_LM_SECURE; + case BT_SECURITY_MEDIUM: + optval |= L2CAP_LM_ENCRYPT; + case BT_SECURITY_LOW: + optval |= L2CAP_LM_AUTH; + break; + default: + return false; + } + + if (setsockopt(socket, SOL_L2CAP, L2CAP_LM, &optval, sizeof(optval)) == 0) { + qDebug(QT_BT_BLUEZ) << "Old l2cp sec level:" << optval; + return true; + } + + return false; +} + void QLowEnergyControllerPrivate::discoverNextDescriptor( QSharedPointer serviceData, const QList pendingCharHandles, diff --git a/src/bluetooth/qlowenergycontroller_p.h b/src/bluetooth/qlowenergycontroller_p.h index fc88c605..219d2f0f 100644 --- a/src/bluetooth/qlowenergycontroller_p.h +++ b/src/bluetooth/qlowenergycontroller_p.h @@ -143,6 +143,8 @@ private: 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); @@ -157,6 +159,7 @@ private slots: #endif private: QLowEnergyController *q_ptr; + }; QT_END_NAMESPACE -- cgit v1.2.3