From 1905841f4008a58932368a7099e370e5758544c4 Mon Sep 17 00:00:00 2001 From: Javier Date: Sun, 5 Jun 2016 00:51:39 +0200 Subject: initial attempts to work with paired devices --- gatoaddress.cpp | 20 +++++++--- gatoaddress.h | 14 +++++-- gatoattclient.cpp | 11 +----- gatoattclient.h | 3 +- gatoperipheral.cpp | 41 ++++++++++++-------- gatoperipheral.h | 5 ++- gatosocket.cpp | 111 +++++++++++++++++++++++++++++++---------------------- gatosocket.h | 1 + rpm/libgato.spec | 2 +- rpm/libgato.yaml | 2 +- 10 files changed, 126 insertions(+), 84 deletions(-) diff --git a/gatoaddress.cpp b/gatoaddress.cpp index b99a977..6f1c583 100644 --- a/gatoaddress.cpp +++ b/gatoaddress.cpp @@ -31,34 +31,39 @@ struct GatoAddressPrivate : QSharedData bdaddr_t bd; quint64 u64; } addr; + GatoAddress::Type type; }; GatoAddress::GatoAddress() : d(new GatoAddressPrivate) { d->addr.u64 = 0; + d->type = TypeNull; } -GatoAddress::GatoAddress(quint64 addr) +GatoAddress::GatoAddress(quint64 addr, Type type) : d(new GatoAddressPrivate) { d->addr.u64 = addr; + d->type = type; } -GatoAddress::GatoAddress(quint8 addr[]) +GatoAddress::GatoAddress(quint8 addr[], Type type) : d(new GatoAddressPrivate) { d->addr.u64 = 0; for (int i = 0; i < 6; i++) { d->addr.bd.b[i] = addr[i]; } + d->type = type; } -GatoAddress::GatoAddress(const QString &addr) +GatoAddress::GatoAddress(const QString &addr, Type type) : d(new GatoAddressPrivate) { d->addr.u64 = 0; str2ba(addr.toLatin1().constData(), &d->addr.bd); + d->type = type; } GatoAddress::GatoAddress(const GatoAddress &o) @@ -83,6 +88,11 @@ bool GatoAddress::isNull() const return toUInt64() == 0; } +GatoAddress::Type GatoAddress::type() const +{ + return d->type; +} + quint64 GatoAddress::toUInt64() const { return d->addr.u64; @@ -104,10 +114,10 @@ QString GatoAddress::toString() const bool operator==(const GatoAddress &a, const GatoAddress &b) { - return a.toUInt64() == b.toUInt64(); + return a.toUInt64() == b.toUInt64() && a.type() == b.type(); } uint qHash(const GatoAddress &a) { - return qHash(a.toUInt64()); + return qHash(a.toUInt64() + a.type()); } diff --git a/gatoaddress.h b/gatoaddress.h index 9b551e7..b64fea9 100644 --- a/gatoaddress.h +++ b/gatoaddress.h @@ -10,16 +10,24 @@ class GatoAddressPrivate; class LIBGATO_EXPORT GatoAddress { public: + enum Type { + TypeNull, + TypeBREDR, + TypeLEPublic, + TypeLERandom + }; + GatoAddress(); - explicit GatoAddress(quint8 addr[]); - explicit GatoAddress(quint64 addr); - explicit GatoAddress(const QString &addr); + explicit GatoAddress(quint8 addr[], Type = TypeLEPublic); + explicit GatoAddress(quint64 addr, Type = TypeLEPublic); + explicit GatoAddress(const QString &addr, Type = TypeLEPublic); GatoAddress(const GatoAddress& o); ~GatoAddress(); GatoAddress& operator=(const GatoAddress& o); bool isNull() const; + Type type() const; void toUInt8Array(quint8 addr[]) const; quint64 toUInt64() const; diff --git a/gatoattclient.cpp b/gatoattclient.cpp index 00dd9d0..b8bdc17 100644 --- a/gatoattclient.cpp +++ b/gatoattclient.cpp @@ -75,8 +75,7 @@ static QByteArray remove_method_signature(const char *sig) } GatoAttClient::GatoAttClient(QObject *parent) : - QObject(parent), socket(new GatoSocket(this)), cur_mtu(ATT_DEFAULT_LE_MTU), next_id(1), - required_sec(GatoSocket::SecurityLow) + QObject(parent), socket(new GatoSocket(this)), cur_mtu(ATT_DEFAULT_LE_MTU), next_id(1) { connect(socket, SIGNAL(connected()), SLOT(handleSocketConnected())); connect(socket, SIGNAL(disconnected()), SLOT(handleSocketDisconnected())); @@ -92,9 +91,8 @@ GatoSocket::State GatoAttClient::state() const return socket->state(); } -bool GatoAttClient::connectTo(const GatoAddress &addr, GatoSocket::SecurityLevel sec_level) +bool GatoAttClient::connectTo(const GatoAddress &addr) { - required_sec = sec_level; return socket->connectTo(addr, ATT_CID); } @@ -110,7 +108,6 @@ GatoSocket::SecurityLevel GatoAttClient::securityLevel() const bool GatoAttClient::setSecurityLevel(GatoSocket::SecurityLevel level) { - required_sec = level; return socket->setSecurityLevel(level); } @@ -563,10 +560,6 @@ QList GatoAttClient::parseAttributeGroupData( void GatoAttClient::handleSocketConnected() { - if (socket->securityLevel() < required_sec) { - socket->setSecurityLevel(required_sec); - } - requestExchangeMTU(ATT_MAX_LE_MTU, this, SLOT(handleServerMTU(quint16))); emit connected(); } diff --git a/gatoattclient.h b/gatoattclient.h index 764abdd..0aafc6d 100644 --- a/gatoattclient.h +++ b/gatoattclient.h @@ -16,7 +16,7 @@ public: GatoSocket::State state() const; - bool connectTo(const GatoAddress& addr, GatoSocket::SecurityLevel sec_level); + bool connectTo(const GatoAddress& addr); void close(); GatoSocket::SecurityLevel securityLevel() const; @@ -99,7 +99,6 @@ private: quint16 cur_mtu; uint next_id; QQueue pending_requests; - GatoSocket::SecurityLevel required_sec; }; #endif // GATOATTCLIENT_H diff --git a/gatoperipheral.cpp b/gatoperipheral.cpp index d15bf99..a08f87a 100644 --- a/gatoperipheral.cpp +++ b/gatoperipheral.cpp @@ -186,20 +186,29 @@ bool GatoPeripheral::advertisesService(const GatoUUID &uuid) const return d->service_uuids.contains(uuid); } -void GatoPeripheral::connectPeripheral(PeripheralConnectOptions options) +bool GatoPeripheral::connectPeripheral(PeripheralConnectOptions options) { Q_D(GatoPeripheral); if (d->att->state() != GatoSocket::StateDisconnected) { qDebug() << "Already connecting"; - return; + return false; } - GatoSocket::SecurityLevel sec_level = GatoSocket::SecurityLow; + d->att->setSecurityLevel(GatoSocket::SecurityLow); if (options & PeripheralConnectOptionRequireEncryption) { - sec_level = GatoSocket::SecurityMedium; + if (!d->att->setSecurityLevel(GatoSocket::SecurityMedium)) { + qWarning() << "Could not set medium security level"; + return false; + } + } + if (options & PeripheralConnectOptionRequirePairing) { + if (!d->att->setSecurityLevel(GatoSocket::SecurityHigh)) { + qWarning() << "Could not set medium security level"; + return false; + } } - d->att->connectTo(d->addr, sec_level); + return d->att->connectTo(d->addr); } void GatoPeripheral::disconnectPeripheral() @@ -785,18 +794,17 @@ void GatoPeripheralPrivate::handleDescriptors(uint req, const QListdescriptorsDiscovered(characteristic); return; + } else if (last_handle == 0) { + qWarning() << "Invalid handle while enumerating characteristics"; + return; } // Fetch following attributes diff --git a/gatoperipheral.h b/gatoperipheral.h index 6b7ab5b..67c03a5 100644 --- a/gatoperipheral.h +++ b/gatoperipheral.h @@ -27,7 +27,8 @@ public: ~GatoPeripheral(); enum PeripheralConnectOption { - PeripheralConnectOptionRequireEncryption = 1 << 0 + PeripheralConnectOptionRequireEncryption = 1 << 0, + PeripheralConnectOptionRequirePairing = 2 << 0 }; Q_DECLARE_FLAGS(PeripheralConnectOptions, PeripheralConnectOption) @@ -54,7 +55,7 @@ public: bool advertisesService(const GatoUUID &uuid) const; public slots: - void connectPeripheral(PeripheralConnectOptions options = 0); + bool connectPeripheral(PeripheralConnectOptions options = 0); void disconnectPeripheral(); void discoverServices(); diff --git a/gatosocket.cpp b/gatosocket.cpp index da3721d..7860c9e 100644 --- a/gatosocket.cpp +++ b/gatosocket.cpp @@ -61,10 +61,10 @@ struct bt_le_params { uint16_t conn_timeout; }; -#endif +#endif /* BT_LE_PARAMS */ GatoSocket::GatoSocket(QObject *parent) - : QObject(parent), s(StateDisconnected), fd(-1) + : QObject(parent), s(StateDisconnected), fd(-1), desiredSec(SecurityLow) { } @@ -95,6 +95,8 @@ bool GatoSocket::connectTo(const GatoAddress &addr, unsigned short cid) s = StateConnecting; + setSecurityLevel(desiredSec); + readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); writeNotifier = new QSocketNotifier(fd, QSocketNotifier::Write, this); connect(readNotifier, SIGNAL(activated(int)), SLOT(readNotify())); @@ -106,7 +108,24 @@ bool GatoSocket::connectTo(const GatoAddress &addr, unsigned short cid) l2addr.l2_family = AF_BLUETOOTH; l2addr.l2_cid = htobs(cid); #ifdef BDADDR_LE_PUBLIC - l2addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; // TODO + switch (addr.type()) { + case GatoAddress::TypeBREDR: + l2addr.l2_bdaddr_type = BDADDR_BREDR; + break; + case GatoAddress::TypeLEPublic: + default: + l2addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; + break; + case GatoAddress::TypeLERandom: + l2addr.l2_bdaddr_type = BDADDR_LE_RANDOM; + break; + } +#else + // The kernel is probably too old to support this, + // but BLE might still work (e.g. Nokia N9). + if (addr.type() != GatoAddress::TypeLEPublic) { + qWarning() << "Kernel does not support random LE addresses!"; + } #endif addr.toUInt8Array(l2addr.l2_bdaddr.b); @@ -162,59 +181,59 @@ GatoSocket::SecurityLevel GatoSocket::securityLevel() const bt_security bt_sec; socklen_t len = sizeof(bt_sec); - if (s == StateDisconnected) { - qWarning() << "Socket not connected"; - return SecurityNone; - } - - if (::getsockopt(fd, SOL_BLUETOOTH, BT_SECURITY, &bt_sec, &len) == 0) { - switch (bt_sec.level) { - case BT_SECURITY_SDP: - return SecurityNone; - case BT_SECURITY_LOW: - return SecurityLow; - case BT_SECURITY_MEDIUM: - return SecurityMedium; - case BT_SECURITY_HIGH: - return SecurityHigh; + if (s != StateDisconnected) { + if (::getsockopt(fd, SOL_BLUETOOTH, BT_SECURITY, &bt_sec, &len) == 0) { + switch (bt_sec.level) { + case BT_SECURITY_SDP: + return SecurityNone; + case BT_SECURITY_LOW: + return SecurityLow; + case BT_SECURITY_MEDIUM: + return SecurityMedium; + case BT_SECURITY_HIGH: + return SecurityHigh; + } + } else { + qErrnoWarning("Could not read security level from L2 socket"); } + + return SecurityNone; } else { - qErrnoWarning("Could not read security level from L2 socket"); + return desiredSec; } - - return SecurityNone; } bool GatoSocket::setSecurityLevel(SecurityLevel level) { - bt_security bt_sec; - socklen_t len = sizeof(bt_sec); + desiredSec = level; - if (s == StateDisconnected) { - qWarning() << "Socket not connected"; - return false; - } - - memset(&bt_sec, 0, len); - - switch (level) { - case SecurityNone: - case SecurityLow: - bt_sec.level = BT_SECURITY_LOW; - break; - case SecurityMedium: - bt_sec.level = BT_SECURITY_MEDIUM; - break; - case SecurityHigh: - bt_sec.level = BT_SECURITY_HIGH; - break; - } + if (s != StateDisconnected) { + bt_security bt_sec; + socklen_t len = sizeof(bt_sec); + + memset(&bt_sec, 0, len); + + switch (level) { + case SecurityNone: + case SecurityLow: + bt_sec.level = BT_SECURITY_LOW; + break; + case SecurityMedium: + bt_sec.level = BT_SECURITY_MEDIUM; + break; + case SecurityHigh: + bt_sec.level = BT_SECURITY_HIGH; + break; + } - if (::setsockopt(fd, SOL_BLUETOOTH, BT_SECURITY, &bt_sec, len) == 0) { - return true; + if (::setsockopt(fd, SOL_BLUETOOTH, BT_SECURITY, &bt_sec, len) == 0) { + return true; + } else { + qErrnoWarning("Could not set security level in L2 socket"); + return false; + } } else { - qErrnoWarning("Could not set security level in L2 socket"); - return false; + return true; } } diff --git a/gatosocket.h b/gatosocket.h index 28fd788..b7634c7 100644 --- a/gatosocket.h +++ b/gatosocket.h @@ -69,6 +69,7 @@ private slots: private: State s; int fd; + SecurityLevel desiredSec; QSocketNotifier *readNotifier; QQueue readQueue; QSocketNotifier *writeNotifier; diff --git a/rpm/libgato.spec b/rpm/libgato.spec index 5b8584f..8b96fb8 100644 --- a/rpm/libgato.spec +++ b/rpm/libgato.spec @@ -13,7 +13,7 @@ Name: libgato %{!?qtc_make:%define qtc_make make} %{?qtc_builddir:%define _builddir %qtc_builddir} Summary: A GATT library to connect with Bluetooth Smart devices -Version: 0.1.7 +Version: 0.1.8 Release: 1 Group: Qt/Qt License: GPL2 diff --git a/rpm/libgato.yaml b/rpm/libgato.yaml index 3d1c092..b2b065e 100644 --- a/rpm/libgato.yaml +++ b/rpm/libgato.yaml @@ -1,6 +1,6 @@ Name: libgato Summary: A GATT library to connect with Bluetooth Smart devices -Version: 0.1.7 +Version: 0.1.8 Release: 1 Group: Qt/Qt URL: https://gitorious.org/gato/ -- cgit v1.2.3