summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@digia.com>2014-09-09 14:29:26 +0200
committerAlex Blasche <alexander.blasche@digia.com>2014-09-16 08:59:01 +0200
commit8650ab69889218ec857475da3dfd99624f714585 (patch)
tree4fae8ce1f7933b0394c13061d4b7c75fd8e54b38
parent07f1b4c19880f79c6ee15c400ee830383529e59a (diff)
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 <lars.knoll@digia.com>
-rw-r--r--src/bluetooth/bluez/bluez_data_p.h13
-rw-r--r--src/bluetooth/qlowenergycontroller_bluez.cpp89
-rw-r--r--src/bluetooth/qlowenergycontroller_p.h3
3 files changed, 105 insertions, 0 deletions
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<QLowEnergyServicePrivate> serviceData,
const QList<QLowEnergyHandle> 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