aboutsummaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-10-25 10:23:14 +0200
committerSven Gothel <[email protected]>2023-10-25 10:23:14 +0200
commit94124031ffb1cbe93c29fcc02734d891669a55ab (patch)
treeb48c192a2b5c05c1de55ba4d3bcb30ac02fc57c0 /api
parent080814ec4641de5ddfb377e79cf421e66c216824 (diff)
LE Resolvable Address: Support IRK: SMPIdentityResolvingKey (IRK w/ added id_address), SMPKeyBin storage and host upload, w/ clearing all IRKs on startup
Diffstat (limited to 'api')
-rw-r--r--api/direct_bt/BTManager.hpp6
-rw-r--r--api/direct_bt/MgmtTypes.hpp156
-rw-r--r--api/direct_bt/SMPKeyBin.hpp29
-rw-r--r--api/direct_bt/SMPTypes.hpp4
4 files changed, 140 insertions, 55 deletions
diff --git a/api/direct_bt/BTManager.hpp b/api/direct_bt/BTManager.hpp
index 43ee4979..bfd4ab3a 100644
--- a/api/direct_bt/BTManager.hpp
+++ b/api/direct_bt/BTManager.hpp
@@ -500,10 +500,14 @@ namespace direct_bt {
*/
bool isValidLongTermKeyAddressAndType(const EUI48 &address, const BDAddressType &address_type) const noexcept;
- HCIStatusCode uploadLongTermKey(const uint16_t dev_id, const jau::darray<MgmtLongTermKeyInfo> &keys) noexcept;
+ HCIStatusCode uploadLongTermKey(const uint16_t dev_id, const jau::darray<MgmtLongTermKey> &keys) noexcept;
HCIStatusCode uploadLongTermKey(const BTRole adapterRole,
const uint16_t dev_id, const BDAddressAndType & addressAndType, const jau::darray<SMPLongTermKey>& ltks) noexcept;
+ HCIStatusCode uploadIdentityResolvingKey(const uint16_t dev_id, const jau::darray<MgmtIdentityResolvingKey> &keys) noexcept;
+ HCIStatusCode uploadIdentityResolvingKey(const uint16_t dev_id, const jau::darray<SMPIdentityResolvingKey>& irks) noexcept;
+ HCIStatusCode clearIdentityResolvingKeys(const uint16_t dev_id) noexcept;
+
HCIStatusCode uploadLinkKey(const uint16_t dev_id, const MgmtLinkKeyInfo &key) noexcept;
HCIStatusCode uploadLinkKey(const uint16_t dev_id, const BDAddressAndType & addressAndType, const SMPLinkKey& lk) noexcept;
diff --git a/api/direct_bt/MgmtTypes.hpp b/api/direct_bt/MgmtTypes.hpp
index 194e7cad..1745f934 100644
--- a/api/direct_bt/MgmtTypes.hpp
+++ b/api/direct_bt/MgmtTypes.hpp
@@ -140,7 +140,7 @@ namespace direct_bt {
std::string to_string(const MgmtLinkKeyType type) noexcept;
/**
- * Long Term Key Types compatible with Mgmt's MgmtLongTermKeyInfo
+ * Long Term Key Types compatible with Mgmt's MgmtLongTermKey
*/
enum class MgmtLTKType : uint8_t {
/** Unauthenticated long term key, implying legacy. */
@@ -160,7 +160,7 @@ namespace direct_bt {
MgmtLTKType to_MgmtLTKType(const SMPLongTermKey::Property ltk_prop_mask) noexcept;
/**
- * Signature Resolving Key Types compatible with Mgmt's MgmtSignatureResolvingKeyInfo
+ * Signature Resolving Key Types compatible with Mgmt's MgmtSignatureResolvingKey
*/
enum class MgmtCSRKType : uint8_t {
/** Unauthenticated local key */
@@ -183,7 +183,7 @@ namespace direct_bt {
* since the encryption values are interpreted as a byte stream.
* </p>
*/
- __pack( struct MgmtLongTermKeyInfo {
+ __pack( struct MgmtLongTermKey {
EUI48 address;
/** 0 reserved, 1 le public, 2 le static random address. Compatible with BDAddressType. */
BDAddressType address_type;
@@ -217,7 +217,7 @@ namespace direct_bt {
}
/**
- * Convert the given states to the MgmtLongTermKeyInfo compatoble role.
+ * Convert the given states to the MgmtLongTermKey compatoble role.
*/
static constexpr uint8_t to_role(const BTRole adapterRole, const bool is_responder) {
return ( ( BTRole::Slave == adapterRole && !is_responder ) ||
@@ -226,9 +226,9 @@ namespace direct_bt {
}
/**
- * Convert this instance into its platform agnostic SMPLongTermKeyInfo type.
+ * Convert this instance into its platform agnostic SMPLongTermKey type.
*/
- SMPLongTermKey toSMPLongTermKeyInfo(const BTRole adapterRole) const noexcept {
+ SMPLongTermKey toSMPLongTermKey(const BTRole adapterRole) const noexcept {
direct_bt::SMPLongTermKey res;
res.clear();
if( ( BTRole::Slave == adapterRole && !role ) ||
@@ -266,7 +266,7 @@ namespace direct_bt {
/**
* Used for MgmtLoadIdentityResolvingKeyCmd and MgmtEvtNewIdentityResolvingKey
*/
- __pack( struct MgmtIdentityResolvingKeyInfo {
+ __pack( struct MgmtIdentityResolvingKey {
EUI48 address;
BDAddressType address_type;
jau::uint128_t irk;
@@ -276,6 +276,16 @@ namespace direct_bt {
"], irk "+jau::bytesHexString(irk.data, 0, sizeof(irk), true /* lsbFirst */)+
"]";
}
+
+ SMPIdentityResolvingKey toSMPIdentityResolvingKey(const BTRole adapterRole) const noexcept {
+ direct_bt::SMPIdentityResolvingKey res;
+ res.clear();
+ if( BTRole::Master == adapterRole ) {
+ res.properties |= SMPIdentityResolvingKey::Property::RESPONDER;
+ }
+ res.irk = irk;
+ return res;
+ }
} );
/**
@@ -284,7 +294,7 @@ namespace direct_bt {
* One way for ATT Signed Write.
* </p>
*/
- __pack( struct MgmtSignatureResolvingKeyInfo {
+ __pack( struct MgmtSignatureResolvingKey {
EUI48 address;
BDAddressType address_type;
MgmtCSRKType key_type;
@@ -709,29 +719,83 @@ namespace direct_bt {
}
public:
- MgmtLoadLongTermKeyCmd(const uint16_t dev_id, const MgmtLongTermKeyInfo & key)
- : MgmtCommand(Opcode::LOAD_LONG_TERM_KEYS, dev_id, 2 + sizeof(MgmtLongTermKeyInfo))
+ MgmtLoadLongTermKeyCmd(const uint16_t dev_id, const MgmtLongTermKey & key)
+ : MgmtCommand(Opcode::LOAD_LONG_TERM_KEYS, dev_id, 2 + sizeof(MgmtLongTermKey))
+ {
+ pdu.put_uint16_nc(MGMT_HEADER_SIZE, 1);
+ memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtLongTermKey));
+ }
+
+ MgmtLoadLongTermKeyCmd(const uint16_t dev_id, const jau::darray<MgmtLongTermKey> &keys)
+ : MgmtCommand(Opcode::LOAD_LONG_TERM_KEYS, dev_id, 2 + keys.size() * sizeof(MgmtLongTermKey))
+ {
+ jau::nsize_t offset = MGMT_HEADER_SIZE;
+ pdu.put_uint16_nc(offset, keys.size()); offset+= 2;
+
+ for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtLongTermKey)) {
+ const MgmtLongTermKey& key = *it;
+ memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtLongTermKey));
+ }
+ }
+ uint16_t getKeyCount() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE); }
+
+ const MgmtLongTermKey& getLongTermKey(jau::nsize_t idx) const {
+ checkParamIdx(idx);
+ return *reinterpret_cast<const MgmtLongTermKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtLongTermKey)*idx) );
+ }
+ };
+
+ /**
+ * uint16_t key_count
+ * MgmtLongTermKey keys[key_count]
+ */
+ class MgmtIdentityResolveKeyCmd : public MgmtCommand
+ {
+ private:
+ void checkParamIdx(const jau::nsize_t idx) const {
+ const jau::nsize_t kc = getKeyCount();
+ if( idx >= kc ) {
+ throw jau::IndexOutOfBoundsException(idx, kc, E_FILE_LINE);
+ }
+ }
+
+ protected:
+ std::string valueString() const noexcept override {
+ const jau::nsize_t keyCount = getKeyCount();
+ std::string ps = "count "+std::to_string(keyCount)+": ";
+ for(jau::nsize_t i=0; i<keyCount; i++) {
+ if( 0 < i ) {
+ ps.append(", ");
+ }
+ ps.append( getLongTermKey(i).toString() );
+ }
+ return "param[size "+std::to_string(getParamSize())+", data["+ps+"]], tsz "+std::to_string(getTotalSize());
+ }
+
+ public:
+ MgmtIdentityResolveKeyCmd(const uint16_t dev_id, const MgmtLongTermKey & key)
+ : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + sizeof(MgmtLongTermKey))
{
pdu.put_uint16_nc(MGMT_HEADER_SIZE, 1);
- memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtLongTermKeyInfo));
+ memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtLongTermKey));
}
- MgmtLoadLongTermKeyCmd(const uint16_t dev_id, const jau::darray<MgmtLongTermKeyInfo> &keys)
- : MgmtCommand(Opcode::LOAD_LONG_TERM_KEYS, dev_id, 2 + keys.size() * sizeof(MgmtLongTermKeyInfo))
+ MgmtIdentityResolveKeyCmd(const uint16_t dev_id, const jau::darray<MgmtLongTermKey> &keys)
+ : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + keys.size() * sizeof(MgmtLongTermKey))
{
jau::nsize_t offset = MGMT_HEADER_SIZE;
pdu.put_uint16_nc(offset, keys.size()); offset+= 2;
- for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtLongTermKeyInfo)) {
- const MgmtLongTermKeyInfo& key = *it;
- memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtLongTermKeyInfo));
+ for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtLongTermKey)) {
+ const MgmtLongTermKey& key = *it;
+ memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtLongTermKey));
}
}
uint16_t getKeyCount() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE); }
- const MgmtLongTermKeyInfo& getLongTermKey(jau::nsize_t idx) const {
+ const MgmtLongTermKey& getLongTermKey(jau::nsize_t idx) const {
checkParamIdx(idx);
- return *reinterpret_cast<const MgmtLongTermKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtLongTermKeyInfo)*idx) );
+ return *reinterpret_cast<const MgmtLongTermKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtLongTermKey)*idx) );
}
};
@@ -799,29 +863,29 @@ namespace direct_bt {
}
public:
- MgmtLoadIdentityResolvingKeyCmd(const uint16_t dev_id, const MgmtIdentityResolvingKeyInfo & key)
- : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + sizeof(MgmtIdentityResolvingKeyInfo))
+ MgmtLoadIdentityResolvingKeyCmd(const uint16_t dev_id, const MgmtIdentityResolvingKey & key)
+ : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + sizeof(MgmtIdentityResolvingKey))
{
pdu.put_uint16_nc(MGMT_HEADER_SIZE, 1);
- memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtIdentityResolvingKeyInfo));
+ memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE+2), &key, sizeof(MgmtIdentityResolvingKey));
}
- MgmtLoadIdentityResolvingKeyCmd(const uint16_t dev_id, const jau::darray<MgmtIdentityResolvingKeyInfo> &keys)
- : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + keys.size() * sizeof(MgmtIdentityResolvingKeyInfo))
+ MgmtLoadIdentityResolvingKeyCmd(const uint16_t dev_id, const jau::darray<MgmtIdentityResolvingKey> &keys)
+ : MgmtCommand(Opcode::LOAD_IRKS, dev_id, 2 + keys.size() * sizeof(MgmtIdentityResolvingKey))
{
jau::nsize_t offset = MGMT_HEADER_SIZE;
pdu.put_uint16_nc(offset, keys.size()); offset+= 2;
- for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtIdentityResolvingKeyInfo)) {
- const MgmtIdentityResolvingKeyInfo& key = *it;
- memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtIdentityResolvingKeyInfo));
+ for(auto it = keys.begin(); it != keys.end(); ++it, offset+=sizeof(MgmtIdentityResolvingKey)) {
+ const MgmtIdentityResolvingKey& key = *it;
+ memcpy(pdu.get_wptr_nc(offset), &key, sizeof(MgmtIdentityResolvingKey));
}
}
uint16_t getKeyCount() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE); }
- const MgmtIdentityResolvingKeyInfo& getIdentityResolvingKey(jau::nsize_t idx) const {
+ const MgmtIdentityResolvingKey& getIdentityResolvingKey(jau::nsize_t idx) const {
checkParamIdx(idx);
- return *reinterpret_cast<const MgmtIdentityResolvingKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtIdentityResolvingKeyInfo)*idx) );
+ return *reinterpret_cast<const MgmtIdentityResolvingKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 2 + sizeof(MgmtIdentityResolvingKey)*idx) );
}
};
@@ -1711,7 +1775,7 @@ namespace direct_bt {
/**
* uint8_t store_hint,
- * MgmtLongTermKeyInfo key
+ * MgmtLongTermKey key
*/
class MgmtEvtNewLongTermKey : public MgmtEvent
{
@@ -1723,18 +1787,18 @@ namespace direct_bt {
public:
MgmtEvtNewLongTermKey(const uint8_t* buffer, const jau::nsize_t buffer_len)
- : MgmtEvent(buffer, buffer_len, 1+sizeof(MgmtLongTermKeyInfo))
+ : MgmtEvent(buffer, buffer_len, 1+sizeof(MgmtLongTermKey))
{
checkOpcode(getOpcode(), Opcode::NEW_LONG_TERM_KEY);
}
uint8_t getStoreHint() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE); }
- const MgmtLongTermKeyInfo& getLongTermKey() const {
- return *reinterpret_cast<const MgmtLongTermKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) );
+ const MgmtLongTermKey& getLongTermKey() const {
+ return *reinterpret_cast<const MgmtLongTermKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) );
}
- jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtLongTermKeyInfo); }
+ jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtLongTermKey); }
jau::nsize_t getDataSize() const noexcept override { return 0; }
const uint8_t* getData() const noexcept override { return nullptr; }
};
@@ -2192,7 +2256,7 @@ namespace direct_bt {
public:
MgmtEvtNewIdentityResolvingKey(const uint8_t* buffer, const jau::nsize_t buffer_len)
- : MgmtEvent(buffer, buffer_len, 1+6+sizeof(MgmtIdentityResolvingKeyInfo))
+ : MgmtEvent(buffer, buffer_len, 1+6+sizeof(MgmtIdentityResolvingKey))
{
checkOpcode(getOpcode(), Opcode::NEW_IRK);
}
@@ -2201,11 +2265,11 @@ namespace direct_bt {
const EUI48& getRandomAddress() const { return *reinterpret_cast<const EUI48 *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) ); }
- const MgmtIdentityResolvingKeyInfo& getIdentityResolvingKey() const {
- return *reinterpret_cast<const MgmtIdentityResolvingKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1 + 6) );
+ const MgmtIdentityResolvingKey& getIdentityResolvingKey() const {
+ return *reinterpret_cast<const MgmtIdentityResolvingKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1 + 6) );
}
- jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtIdentityResolvingKeyInfo); }
+ jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtIdentityResolvingKey); }
jau::nsize_t getDataSize() const noexcept override { return 0; }
const uint8_t* getData() const noexcept override { return nullptr; }
};
@@ -2213,7 +2277,7 @@ namespace direct_bt {
/**
* uint8_t store_hint,
* EUI48 random_address;
- * MgmtSignatureResolvingKeyInfo key
+ * MgmtSignatureResolvingKey key
*/
class MgmtEvtNewSignatureResolvingKey : public MgmtEvent
{
@@ -2225,18 +2289,18 @@ namespace direct_bt {
public:
MgmtEvtNewSignatureResolvingKey(const uint8_t* buffer, const jau::nsize_t buffer_len)
- : MgmtEvent(buffer, buffer_len, 1+sizeof(MgmtSignatureResolvingKeyInfo))
+ : MgmtEvent(buffer, buffer_len, 1+sizeof(MgmtSignatureResolvingKey))
{
checkOpcode(getOpcode(), Opcode::NEW_CSRK);
}
uint8_t getStoreHint() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE); }
- const MgmtSignatureResolvingKeyInfo& getSignatureResolvingKey() const {
- return *reinterpret_cast<const MgmtSignatureResolvingKeyInfo *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) );
+ const MgmtSignatureResolvingKey& getSignatureResolvingKey() const {
+ return *reinterpret_cast<const MgmtSignatureResolvingKey *>( pdu.get_ptr_nc(MGMT_HEADER_SIZE + 1) );
}
- jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtSignatureResolvingKeyInfo); }
+ jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1+sizeof(MgmtSignatureResolvingKey); }
jau::nsize_t getDataSize() const noexcept override { return 0; }
const uint8_t* getData() const noexcept override { return nullptr; }
};
@@ -2525,14 +2589,14 @@ namespace direct_bt {
const uint8_t* getData() const noexcept override { return nullptr; }
/**
- * Convert this instance into its platform agnostic SMPLongTermKeyInfo type,
+ * Convert this instance into its platform agnostic SMPLongTermKey type,
* invalid without LTK.
*
* LTK shall be completed via MgmtEvtHCILELTKReplyAckCmd.
*
* Local device’s role is BTRole::Slave, responder.
*/
- SMPLongTermKey toSMPLongTermKeyInfo(const bool isSC, const bool isAuth) const noexcept {
+ SMPLongTermKey toSMPLongTermKey(const bool isSC, const bool isAuth) const noexcept {
direct_bt::SMPLongTermKey res;
res.clear();
res.properties |= SMPLongTermKey::Property::RESPONDER;
@@ -2709,13 +2773,13 @@ namespace direct_bt {
const uint8_t* getData() const noexcept override { return nullptr; }
/**
- * Convert this instance into its platform agnostic SMPLongTermKeyInfo LTK.
+ * Convert this instance into its platform agnostic SMPLongTermKey LTK.
*
* Local device’s role is BTRole::Master, initiator.
*
* This LTK Encryption key is for the remote device having role BTRole::Slave (responder).
*/
- SMPLongTermKey toSMPLongTermKeyInfo(const bool isSC, const bool isAuth) const noexcept {
+ SMPLongTermKey toSMPLongTermKey(const bool isSC, const bool isAuth) const noexcept {
direct_bt::SMPLongTermKey res;
res.clear();
res.properties |= SMPLongTermKey::Property::RESPONDER;
diff --git a/api/direct_bt/SMPKeyBin.hpp b/api/direct_bt/SMPKeyBin.hpp
index 5b6859e6..acf7d476 100644
--- a/api/direct_bt/SMPKeyBin.hpp
+++ b/api/direct_bt/SMPKeyBin.hpp
@@ -78,31 +78,33 @@ class BTAdapter; // forward
*/
class SMPKeyBin {
public:
- constexpr static const uint16_t VERSION = (uint16_t)0b0101010101010101U + (uint16_t)5U; // bitpattern + version
+ constexpr static const uint16_t VERSION = (uint16_t)0b0101010101010101U + (uint16_t)6U; // bitpattern + version
private:
uint16_t version; // 2
uint16_t size; // 2
uint64_t ts_creation_sec; // 8
+ BTRole localRole; // 1
BDAddressAndType localAddress; // 7
BDAddressAndType remoteAddress; // 7
BTSecurityLevel sec_level; // 1
SMPIOCapability io_cap; // 1
SMPKeyType keys_init; // 1
- SMPKeyType keys_resp; // 1
+ SMPKeyType keys_resp; // 1 -> 31
SMPLongTermKey ltk_init; // 28 (optional)
- SMPIdentityResolvingKey irk_init; // 17 (optional)
+ SMPIdentityResolvingKey irk_init; // 23 (optional)
SMPSignatureResolvingKey csrk_init; // 17 (optional)
SMPLinkKey lk_init; // 19 (optional)
SMPLongTermKey ltk_resp; // 28 (optional)
- SMPIdentityResolvingKey irk_resp; // 17 (optional)
+ SMPIdentityResolvingKey irk_resp; // 23 (optional)
SMPSignatureResolvingKey csrk_resp; // 17 (optional)
SMPLinkKey lk_resp; // 19 (optional)
- // Min-Max: 30 - 190 bytes
+ constexpr static const int byte_size_max = 205;
+ constexpr static const int byte_size_min = 31;
bool verbose;
@@ -111,6 +113,7 @@ class SMPKeyBin {
s += sizeof(version);
s += sizeof(size);
s += sizeof(ts_creation_sec);
+ s += sizeof(localRole);
s += sizeof(localAddress.address);
s += sizeof(localAddress.type);
s += sizeof(remoteAddress.address);
@@ -234,11 +237,12 @@ class SMPKeyBin {
static std::vector<SMPKeyBin> readAll(const std::string& dname, const bool verbose_);
static std::vector<SMPKeyBin> readAllForLocalAdapter(const BDAddressAndType& localAddress, const std::string& dname, const bool verbose_);
- SMPKeyBin(BDAddressAndType localAddress_,
+ SMPKeyBin(BTRole localRole_, BDAddressAndType localAddress_,
BDAddressAndType remoteAddress_,
const BTSecurityLevel sec_level_, const SMPIOCapability io_cap_)
: version(VERSION), size(0),
ts_creation_sec( jau::getWallClockSeconds() ),
+ localRole(localRole_),
localAddress(std::move(localAddress_)), remoteAddress(std::move(remoteAddress_)),
sec_level(sec_level_), io_cap(io_cap_),
keys_init(SMPKeyType::NONE), keys_resp(SMPKeyType::NONE),
@@ -250,6 +254,7 @@ class SMPKeyBin {
SMPKeyBin()
: version(VERSION), size(0),
ts_creation_sec(0),
+ localRole(BTRole::None),
localAddress(), remoteAddress(),
sec_level(BTSecurityLevel::UNSET), io_cap(SMPIOCapability::UNSET),
keys_init(SMPKeyType::NONE), keys_resp(SMPKeyType::NONE),
@@ -267,6 +272,9 @@ class SMPKeyBin {
/** Returns the creation timestamp in seconds since Unix epoch */
constexpr uint64_t getCreationTime() const noexcept { return ts_creation_sec; }
+ /** Return the local adapter BTRole. */
+ constexpr BTRole getLocalRole() const noexcept { return localRole; }
+
/** Return the local adapter address. */
constexpr const BDAddressAndType& getLocalAddrAndType() const noexcept { return localAddress; }
@@ -354,13 +362,20 @@ class SMPKeyBin {
*
*/
constexpr bool isValid() const noexcept {
+ // local_is_responder == true: responder's IRK info (LL slave), else the initiator's (LL master)
+ const bool local_is_responder = BTRole::Slave == localRole;
+ const BDAddressAndType& responderAddress = local_is_responder ? localAddress : remoteAddress;
+ const BDAddressAndType& initiatorAddress = local_is_responder ? remoteAddress : localAddress;
+
return isVersionValid() && isSizeValid() &&
BTSecurityLevel::UNSET != sec_level &&
SMPIOCapability::UNSET != io_cap &&
( !hasLTKInit() || ltk_init.isValid() ) &&
( !hasLTKResp() || ltk_resp.isValid() ) &&
( !hasLKInit() || lk_init.isValid() ) &&
- ( !hasLKResp() || lk_resp.isValid() );
+ ( !hasLKResp() || lk_resp.isValid() ) &&
+ ( !hasIRKInit() || irk_init.id_address == initiatorAddress.address ) &&
+ ( !hasIRKResp() || irk_resp.id_address == responderAddress.address );
}
std::string toString() const noexcept;
diff --git a/api/direct_bt/SMPTypes.hpp b/api/direct_bt/SMPTypes.hpp
index 7e75d415..b628a554 100644
--- a/api/direct_bt/SMPTypes.hpp
+++ b/api/direct_bt/SMPTypes.hpp
@@ -613,6 +613,8 @@ namespace direct_bt {
Property properties;
/** Identity Resolving Key (IRK) */
jau::uint128_t irk;
+ /** Identity Address for the IRK */
+ EUI48 id_address;
bool isResponder() const noexcept;
@@ -628,7 +630,7 @@ namespace direct_bt {
std::string toString() const noexcept { // hex-fmt aligned with btmon
return "IRK[props "+getPropertyString(properties)+
- ", irk "+jau::bytesHexString(irk.data, 0, sizeof(irk), true /* lsbFirst */)+
+ ", id "+id_address.toString()+", irk "+jau::bytesHexString(irk.data, 0, sizeof(irk), true /* lsbFirst */)+
"]";
}
} );