diff options
-rw-r--r-- | api/direct_bt/DBTManager.hpp | 4 | ||||
-rw-r--r-- | api/direct_bt/MgmtTypes.hpp | 906 | ||||
-rw-r--r-- | api/direct_bt/SMPHandler.hpp | 2 | ||||
-rw-r--r-- | src/direct_bt/DBTAdapter.cpp | 9 | ||||
-rw-r--r-- | src/direct_bt/DBTManager.cpp | 136 | ||||
-rw-r--r-- | src/direct_bt/MgmtTypes.cpp | 111 | ||||
-rw-r--r-- | src/direct_bt/SMPHandler.cpp | 7 |
7 files changed, 715 insertions, 460 deletions
diff --git a/api/direct_bt/DBTManager.hpp b/api/direct_bt/DBTManager.hpp index 73026b9a..3c07f93b 100644 --- a/api/direct_bt/DBTManager.hpp +++ b/api/direct_bt/DBTManager.hpp @@ -257,6 +257,7 @@ namespace direct_bt { void processAdapterAdded(std::shared_ptr<MgmtEvent> e) noexcept; void processAdapterRemoved(std::shared_ptr<MgmtEvent> e) noexcept; bool mgmtEvNewSettingsCB(std::shared_ptr<MgmtEvent> e) noexcept; + bool mgmtEvControllerErrorCB(std::shared_ptr<MgmtEvent> e) noexcept; bool mgmtEvClassOfDeviceChangedCB(std::shared_ptr<MgmtEvent> e) noexcept; bool mgmtEvDeviceDiscoveringCB(std::shared_ptr<MgmtEvent> e) noexcept; bool mgmtEvDeviceFoundCB(std::shared_ptr<MgmtEvent> e) noexcept; @@ -376,7 +377,8 @@ namespace direct_bt { */ int getDefaultAdapterDevID() const noexcept; - bool setMode(const uint16_t dev_id, const MgmtOpcode opc, const uint8_t mode) noexcept; + bool setMode(const uint16_t dev_id, const MgmtCommand::Opcode opc, const uint8_t mode, AdapterSetting& current_settings) noexcept; + MgmtStatus setDiscoverable(const uint16_t dev_id, const uint8_t state, const uint16_t timeout, AdapterSetting& current_settings) noexcept; /** Start discovery on given adapter dev_id with a ScanType matching the given BTMode. Returns set ScanType. */ ScanType startDiscovery(const uint16_t dev_id, const BTMode btMode) noexcept; diff --git a/api/direct_bt/MgmtTypes.hpp b/api/direct_bt/MgmtTypes.hpp index b387881c..af38b9ce 100644 --- a/api/direct_bt/MgmtTypes.hpp +++ b/api/direct_bt/MgmtTypes.hpp @@ -95,95 +95,148 @@ namespace direct_bt { ALREADY_PAIRED = 0x13, PERMISSION_DENIED = 0x14 }; - std::string getMgmtStatusString(const MgmtStatus opc) noexcept; - enum class MgmtOpcode : uint16_t { - READ_VERSION = 0x0001, - READ_COMMANDS = 0x0002, - READ_INDEX_LIST = 0x0003, - READ_INFO = 0x0004, - SET_POWERED = 0x0005, // uint8_t bool - SET_DISCOVERABLE = 0x0006, // uint8_t bool [+ uint16_t timeout] - SET_CONNECTABLE = 0x0007, // uint8_t bool - SET_FAST_CONNECTABLE = 0x0008, // uint8_t bool - SET_BONDABLE = 0x0009, // uint8_t bool - SET_LINK_SECURITY = 0x000A, - SET_SSP = 0x000B, - SET_HS = 0x000C, - SET_LE = 0x000D, // uint8_t bool - SET_DEV_CLASS = 0x000E, // uint8_t major, uint8_t minor - SET_LOCAL_NAME = 0x000F, // uint8_t name[MAX_NAME_LENGTH], uint8_t short_name[MAX_SHORT_NAME_LENGTH]; - ADD_UUID = 0x0010, - REMOVE_UUID = 0x0011, - LOAD_LINK_KEYS = 0x0012, - LOAD_LONG_TERM_KEYS = 0x0013, - DISCONNECT = 0x0014, - GET_CONNECTIONS = 0x0015, - PIN_CODE_REPLY = 0x0016, - PIN_CODE_NEG_REPLY = 0x0017, - SET_IO_CAPABILITY = 0x0018, - PAIR_DEVICE = 0x0019, - CANCEL_PAIR_DEVICE = 0x001A, - UNPAIR_DEVICE = 0x001B, - USER_CONFIRM_REPLY = 0x001C, - USER_CONFIRM_NEG_REPLY = 0x001D, - USER_PASSKEY_REPLY = 0x001E, - USER_PASSKEY_NEG_REPLY = 0x001F, - READ_LOCAL_OOB_DATA = 0x0020, - ADD_REMOTE_OOB_DATA = 0x0021, - REMOVE_REMOTE_OOB_DATA = 0x0022, - START_DISCOVERY = 0x0023, - STOP_DISCOVERY = 0x0024, - CONFIRM_NAME = 0x0025, - BLOCK_DEVICE = 0x0026, - UNBLOCK_DEVICE = 0x0027, - SET_DEVICE_ID = 0x0028, - SET_ADVERTISING = 0x0029, - SET_BREDR = 0x002A, - SET_STATIC_ADDRESS = 0x002B, - SET_SCAN_PARAMS = 0x002C, - SET_SECURE_CONN = 0x002D, - SET_DEBUG_KEYS = 0x002E, - SET_PRIVACY = 0x002F, - LOAD_IRKS = 0x0030, - GET_CONN_INFO = 0x0031, - GET_CLOCK_INFO = 0x0032, - ADD_DEVICE_WHITELIST = 0x0033, - REMOVE_DEVICE_WHITELIST = 0x0034, - LOAD_CONN_PARAM = 0x0035, - READ_UNCONF_INDEX_LIST = 0x0036, - READ_CONFIG_INFO = 0x0037, - SET_EXTERNAL_CONFIG = 0x0038, - SET_PUBLIC_ADDRESS = 0x0039, - START_SERVICE_DISCOVERY = 0x003A, - READ_LOCAL_OOB_EXT_DATA = 0x003B, - READ_EXT_INDEX_LIST = 0x003C, - READ_ADV_FEATURES = 0x003D, - ADD_ADVERTISING = 0x003E, - REMOVE_ADVERTISING = 0x003F, - GET_ADV_SIZE_INFO = 0x0040, - START_LIMITED_DISCOVERY = 0x0041, - READ_EXT_INFO = 0x0042, - SET_APPEARANCE = 0x0043, - GET_PHY_CONFIGURATION = 0x0044, - SET_PHY_CONFIGURATION = 0x0045, - SET_BLOCKED_KEYS = 0x0046 - }; - - std::string getMgmtOpcodeString(const MgmtOpcode op) noexcept; - enum MgmtOption : uint32_t { EXTERNAL_CONFIG = 0x00000001, PUBLIC_ADDRESS = 0x00000002 }; - class MgmtCommand + class MgmtMsg { protected: POctets pdu; + uint64_t ts_creation; + + virtual std::string baseString() const noexcept { + return "opcode "+jau::uint16HexString(getIntOpcode())+", devID "+jau::uint16HexString(getDevID()); + } + + virtual std::string valueString() const noexcept = 0; + + public: + MgmtMsg(const uint16_t opc, const uint16_t dev_id, const uint16_t param_size) + : pdu(MGMT_HEADER_SIZE+param_size), ts_creation(jau::getCurrentMilliseconds()) + { + pdu.put_uint16_nc(0, opc); + pdu.put_uint16_nc(2, dev_id); + pdu.put_uint16_nc(4, param_size); + } + + MgmtMsg(const uint8_t* buffer, const jau::nsize_t buffer_len) + : pdu(buffer, buffer_len), ts_creation(jau::getCurrentMilliseconds()) + {} + + virtual ~MgmtMsg() {} + + uint64_t getTimestamp() const noexcept { return ts_creation; } + + jau::nsize_t getTotalSize() const noexcept { return pdu.getSize(); } + + /** Return the underlying octets read only */ + TROOctets & getPDU() noexcept { return pdu; } + + uint16_t getIntOpcode() const noexcept { return pdu.get_uint16_nc(0); } + uint16_t getDevID() const noexcept { return pdu.get_uint16_nc(2); } + + virtual std::string toString() const noexcept = 0; + }; + + class MgmtCommand : public MgmtMsg + { + public: + enum class Opcode : uint16_t { + READ_VERSION = 0x0001, + READ_COMMANDS = 0x0002, + READ_INDEX_LIST = 0x0003, + READ_INFO = 0x0004, + SET_POWERED = 0x0005, // uint8_t bool + SET_DISCOVERABLE = 0x0006, // uint8_t bool [+ uint16_t timeout] + SET_CONNECTABLE = 0x0007, // uint8_t bool + SET_FAST_CONNECTABLE = 0x0008, // uint8_t bool + SET_BONDABLE = 0x0009, // uint8_t bool + SET_LINK_SECURITY = 0x000A, + SET_SSP = 0x000B, + SET_HS = 0x000C, + SET_LE = 0x000D, // uint8_t bool + SET_DEV_CLASS = 0x000E, // uint8_t major, uint8_t minor + SET_LOCAL_NAME = 0x000F, // uint8_t name[MAX_NAME_LENGTH], uint8_t short_name[MAX_SHORT_NAME_LENGTH]; + ADD_UUID = 0x0010, + REMOVE_UUID = 0x0011, + LOAD_LINK_KEYS = 0x0012, + LOAD_LONG_TERM_KEYS = 0x0013, + DISCONNECT = 0x0014, + GET_CONNECTIONS = 0x0015, + PIN_CODE_REPLY = 0x0016, + PIN_CODE_NEG_REPLY = 0x0017, + SET_IO_CAPABILITY = 0x0018, + PAIR_DEVICE = 0x0019, + CANCEL_PAIR_DEVICE = 0x001A, + UNPAIR_DEVICE = 0x001B, + USER_CONFIRM_REPLY = 0x001C, + USER_CONFIRM_NEG_REPLY = 0x001D, + USER_PASSKEY_REPLY = 0x001E, + USER_PASSKEY_NEG_REPLY = 0x001F, + READ_LOCAL_OOB_DATA = 0x0020, + ADD_REMOTE_OOB_DATA = 0x0021, + REMOVE_REMOTE_OOB_DATA = 0x0022, + START_DISCOVERY = 0x0023, // MgmtUint8Cmd + STOP_DISCOVERY = 0x0024, // MgmtUint8Cmd + CONFIRM_NAME = 0x0025, + BLOCK_DEVICE = 0x0026, + UNBLOCK_DEVICE = 0x0027, + SET_DEVICE_ID = 0x0028, + SET_ADVERTISING = 0x0029, + SET_BREDR = 0x002A, + SET_STATIC_ADDRESS = 0x002B, + SET_SCAN_PARAMS = 0x002C, + SET_SECURE_CONN = 0x002D, // uint8_t 0x00 disabled, 0x01 enables mixed, 0x02 enables only mode; Core Spec >= 4.1 + SET_DEBUG_KEYS = 0x002E, // uint8_t 0x00 disabled, 0x01 transient, 0x02 persistent + SET_PRIVACY = 0x002F, + LOAD_IRKS = 0x0030, + GET_CONN_INFO = 0x0031, + GET_CLOCK_INFO = 0x0032, + ADD_DEVICE_WHITELIST = 0x0033, + REMOVE_DEVICE_WHITELIST = 0x0034, + LOAD_CONN_PARAM = 0x0035, + READ_UNCONF_INDEX_LIST = 0x0036, + READ_CONFIG_INFO = 0x0037, + SET_EXTERNAL_CONFIG = 0x0038, + SET_PUBLIC_ADDRESS = 0x0039, + START_SERVICE_DISCOVERY = 0x003A, + READ_LOCAL_OOB_EXT_DATA = 0x003B, + READ_EXT_INDEX_LIST = 0x003C, + READ_ADV_FEATURES = 0x003D, + ADD_ADVERTISING = 0x003E, + REMOVE_ADVERTISING = 0x003F, + GET_ADV_SIZE_INFO = 0x0040, + START_LIMITED_DISCOVERY = 0x0041, + READ_EXT_INFO = 0x0042, + SET_APPEARANCE = 0x0043, + GET_PHY_CONFIGURATION = 0x0044, // linux >= 4.19 + SET_PHY_CONFIGURATION = 0x0045, // linux >= 4.19 + SET_BLOCKED_KEYS = 0x0046, // linux >= 5.6 + SET_WIDEBAND_SPEECH = 0x0047, // linux >= 5.7 + READ_SECURITY_INFO = 0x0048, // linux >= 5.8 + READ_EXP_FEATURES_INFO = 0x0049, // linux >= 5.8 + SET_EXP_FEATURE = 0x004a, // linux >= 5.8 + READ_DEF_SYSTEM_CONFIG = 0x004b, // linux >= 5.9 + SET_DEF_SYSTEM_CONFIG = 0x004c, + READ_DEF_RUNTIME_CONFIG = 0x004d, + SET_DEF_RUNTIME_CONFIG = 0x004e, + GET_DEVICE_FLAGS = 0x004f, + SET_DEVICE_FLAGS = 0x0050, + READ_ADV_MONITOR_FEATURES = 0x0051, + ADD_ADV_PATTERNS_MONITOR = 0x0052, + REMOVE_ADV_MONITOR = 0x0053 // linux >= 5.9 + }; + static constexpr uint16_t number(const Opcode rhs) noexcept { + return static_cast<uint16_t>(rhs); + } + static std::string getOpcodeString(const Opcode op) noexcept; - inline static void checkOpcode(const MgmtOpcode has, const MgmtOpcode min, const MgmtOpcode max) + protected: + inline static void checkOpcode(const Opcode has, const Opcode min, const Opcode max) { if( has < min || has > max ) { throw MgmtOpcodeException("Has opcode "+jau::uint16HexString(static_cast<uint16_t>(has))+ @@ -191,11 +244,19 @@ namespace direct_bt { ".."+jau::uint16HexString(static_cast<uint16_t>(max))+"]", E_FILE_LINE); } } + static void checkOpcode(const Opcode has, const Opcode exp) + { + if( has != exp ) { + throw MgmtOpcodeException("Has evcode "+jau::uint16HexString(static_cast<uint16_t>(has))+ + ", not matching "+jau::uint16HexString(static_cast<uint16_t>(exp)), E_FILE_LINE); + } + } - virtual std::string baseString() const noexcept { - return "opcode="+jau::uint16HexString(static_cast<uint16_t>(getOpcode()))+" "+getOpcodeString()+", devID "+jau::uint16HexString(getDevID()); + virtual std::string baseString() const noexcept override { + return "opcode "+getOpcodeString()+", devID "+jau::uint16HexString(getDevID()); } - virtual std::string valueString() const noexcept { + + virtual std::string valueString() const noexcept override { const jau::nsize_t psz = getParamSize(); const std::string ps = psz > 0 ? jau::bytesHexString(getParam(), 0, psz, true /* lsbFirst */, true /* leading0X */) : ""; return "param[size "+std::to_string(getParamSize())+", data "+ps+"], tsz "+std::to_string(getTotalSize()); @@ -203,50 +264,90 @@ namespace direct_bt { public: - MgmtCommand(const MgmtOpcode opc, const uint16_t dev_id, const uint16_t param_size=0) - : pdu(MGMT_HEADER_SIZE+param_size) + MgmtCommand(const Opcode opc, const uint16_t dev_id, const uint16_t param_size=0) + : MgmtMsg(number(opc), dev_id, param_size) { - checkOpcode(opc, MgmtOpcode::READ_VERSION, MgmtOpcode::SET_BLOCKED_KEYS); - - pdu.put_uint16_nc(0, static_cast<uint16_t>(opc)); - pdu.put_uint16_nc(2, dev_id); - pdu.put_uint16_nc(4, param_size); + checkOpcode(opc, Opcode::READ_VERSION, Opcode::SET_BLOCKED_KEYS); } - MgmtCommand(const MgmtOpcode opc, const uint16_t dev_id, const uint16_t param_size, const uint8_t* param) + + MgmtCommand(const Opcode opc, const uint16_t dev_id, const uint16_t param_size, const uint8_t* param) : MgmtCommand(opc, dev_id, param_size) { if( param_size > 0 ) { memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE), param, param_size); } } - virtual ~MgmtCommand() noexcept {} + virtual ~MgmtCommand() noexcept override {} - jau::nsize_t getTotalSize() const noexcept { return pdu.getSize(); } - - /** Return the underlying octets read only */ - TROOctets & getPDU() noexcept { return pdu; } + Opcode getOpcode() const noexcept { return static_cast<Opcode>( pdu.get_uint16_nc(0) ); } + std::string getOpcodeString() const noexcept { return getOpcodeString(getOpcode()); } - MgmtOpcode getOpcode() const noexcept { return static_cast<MgmtOpcode>( pdu.get_uint16_nc(0) ); } - std::string getOpcodeString() const noexcept { return getMgmtOpcodeString(getOpcode()); } - uint16_t getDevID() const noexcept { return pdu.get_uint16_nc(2); } uint16_t getParamSize() const noexcept { return pdu.get_uint16_nc(4); } const uint8_t* getParam() const noexcept { return pdu.get_ptr_nc(MGMT_HEADER_SIZE); } - std::string toString() const noexcept { - return "MgmtReq["+baseString()+", "+valueString()+"]"; + std::string toString() const noexcept override { + return "MgmtCmd["+baseString()+", "+valueString()+"]"; } }; class MgmtUint8Cmd : public MgmtCommand { public: - MgmtUint8Cmd(const MgmtOpcode opc, const uint16_t dev_id, const uint8_t data) + MgmtUint8Cmd(const Opcode opc, const uint16_t dev_id, const uint8_t data) : MgmtCommand(opc, dev_id, 1) { pdu.put_uint8_nc(MGMT_HEADER_SIZE, data); } }; + /** + * uint8_t discoverable + * uint16_t timeout + */ + class MgmtSetDiscoverableCmd : public MgmtCommand + { + protected: + std::string valueString() const noexcept override { + const std::string ps = "state '"+jau::uint8HexString(getDiscoverable())+"', timeout "+std::to_string(getTimeout())+"s"; + return "param[size "+std::to_string(getParamSize())+", data["+ps+"]], tsz "+std::to_string(getTotalSize()); + } + + public: + MgmtSetDiscoverableCmd(const uint16_t dev_id, const uint8_t discoverable, uint16_t timeout_sec) + : MgmtCommand(Opcode::SET_DISCOVERABLE, dev_id, 1+2) + { + pdu.put_uint8_nc(MGMT_HEADER_SIZE, discoverable); + pdu.put_uint16_nc(MGMT_HEADER_SIZE+1, timeout_sec); + } + uint8_t getDiscoverable() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE); } + uint16_t getTimeout() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE+1); } + }; + + /** + * uint8_t name[MGMT_MAX_NAME_LENGTH]; + * uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH]; + */ + class MgmtSetLocalNameCmd : public MgmtCommand + { + protected: + std::string valueString() const noexcept override { + const std::string ps = "name '"+getName()+"', shortName '"+getShortName()+"'"; + return "param[size "+std::to_string(getParamSize())+", data["+ps+"]], tsz "+std::to_string(getTotalSize()); + } + + public: + MgmtSetLocalNameCmd(const uint16_t dev_id, const std::string & name, const std::string & short_name) + : MgmtCommand(Opcode::SET_LOCAL_NAME, dev_id, MgmtConstU16::MGMT_MAX_NAME_LENGTH + MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH) + { + pdu.put_string_nc(MGMT_HEADER_SIZE, name, MgmtConstU16::MGMT_MAX_NAME_LENGTH, true); + pdu.put_string_nc(MGMT_HEADER_SIZE+MgmtConstU16::MGMT_MAX_NAME_LENGTH, short_name, MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH, true); + } + const std::string getName() const noexcept { return pdu.get_string_nc(MGMT_HEADER_SIZE); } + const std::string getShortName() const noexcept { return pdu.get_string_nc(MGMT_HEADER_SIZE + MgmtConstU16::MGMT_MAX_NAME_LENGTH); } + }; + + // FIXME LOAD_LINK_KEYS = 0x0012, + // FIXME LOAD_LONG_TERM_KEYS = 0x0013, /** * mgmt_addr_info { EUI48, uint8_t type }, @@ -261,15 +362,17 @@ namespace direct_bt { public: MgmtDisconnectCmd(const uint16_t dev_id, const EUI48 &address, const BDAddressType addressType) - : MgmtCommand(MgmtOpcode::DISCONNECT, dev_id, 6+1) + : MgmtCommand(Opcode::DISCONNECT, dev_id, 6+1) { pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(addressType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(addressType)); } const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info }; + // FIXME LOAD_IRKS = 0x0030, + /** * mgmt_addr_info { EUI48, uint8_t type }, */ @@ -283,10 +386,10 @@ namespace direct_bt { public: MgmtGetConnectionInfoCmd(const uint16_t dev_id, const EUI48 &address, const BDAddressType addressType) - : MgmtCommand(MgmtOpcode::GET_CONN_INFO, dev_id, 6+1) + : MgmtCommand(Opcode::GET_CONN_INFO, dev_id, 6+1) { pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(addressType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(addressType)); } const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info @@ -309,10 +412,10 @@ namespace direct_bt { public: MgmtPinCodeReplyCmd(const uint16_t dev_id, const EUI48 &address, const BDAddressType addressType, const uint8_t pin_len, const TROOctets &pin_code) - : MgmtCommand(MgmtOpcode::PIN_CODE_REPLY, dev_id, 6+1+1+16) + : MgmtCommand(Opcode::PIN_CODE_REPLY, dev_id, 6+1+1+16) { pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(addressType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(addressType)); pdu.put_uint8_nc(MGMT_HEADER_SIZE+7, pin_len); pdu.put_octets_nc(MGMT_HEADER_SIZE+8, pin_code); } @@ -335,15 +438,27 @@ namespace direct_bt { public: MgmtPinCodeNegativeReplyCmd(const uint16_t dev_id, const EUI48 &address, const BDAddressType addressType) - : MgmtCommand(MgmtOpcode::PIN_CODE_NEG_REPLY, dev_id, 6+1) + : MgmtCommand(Opcode::PIN_CODE_NEG_REPLY, dev_id, 6+1) { pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(addressType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(addressType)); } const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info }; + // FIXME SET_IO_CAPABILITY = 0x0018, + // FIXME PAIR_DEVICE = 0x0019, + // FIXME CANCEL_PAIR_DEVICE = 0x001A, + // FIXME UNPAIR_DEVICE = 0x001B, + // FIXME USER_CONFIRM_REPLY = 0x001C, + // FIXME USER_CONFIRM_NEG_REPLY = 0x001D, + // FIXME USER_PASSKEY_REPLY = 0x001E, + // FIXME USER_PASSKEY_NEG_REPLY = 0x001F, + // TODO READ_LOCAL_OOB_DATA = 0x0020, + // TODO ADD_REMOTE_OOB_DATA = 0x0021, + // TODO REMOVE_REMOTE_OOB_DATA = 0x0022, + /** * mgmt_addr_info { EUI48, uint8_t type }, * uint8_t action @@ -359,11 +474,11 @@ namespace direct_bt { public: MgmtAddDeviceToWhitelistCmd(const uint16_t dev_id, const EUI48 &address, const BDAddressType addressType, const HCIWhitelistConnectType ctype) - : MgmtCommand(MgmtOpcode::ADD_DEVICE_WHITELIST, dev_id, 6+1+1) + : MgmtCommand(Opcode::ADD_DEVICE_WHITELIST, dev_id, 6+1+1) { pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(addressType)); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6+1, number(ctype)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(addressType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6+1, direct_bt::number(ctype)); } const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info @@ -383,38 +498,15 @@ namespace direct_bt { public: MgmtRemoveDeviceFromWhitelistCmd(const uint16_t dev_id, const EUI48 &address, const BDAddressType addressType) - : MgmtCommand(MgmtOpcode::REMOVE_DEVICE_WHITELIST, dev_id, 6+1) + : MgmtCommand(Opcode::REMOVE_DEVICE_WHITELIST, dev_id, 6+1) { pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(addressType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(addressType)); } const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info }; - /** - * uint8_t name[MGMT_MAX_NAME_LENGTH]; - * uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH]; - */ - class MgmtSetLocalNameCmd : public MgmtCommand - { - protected: - std::string valueString() const noexcept override { - const std::string ps = "name '"+getName()+"', shortName '"+getShortName()+"'"; - return "param[size "+std::to_string(getParamSize())+", data["+ps+"]], tsz "+std::to_string(getTotalSize()); - } - - public: - MgmtSetLocalNameCmd(const uint16_t dev_id, const std::string & name, const std::string & short_name) - : MgmtCommand(MgmtOpcode::SET_LOCAL_NAME, dev_id, MgmtConstU16::MGMT_MAX_NAME_LENGTH + MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH) - { - pdu.put_string_nc(MGMT_HEADER_SIZE, name, MgmtConstU16::MGMT_MAX_NAME_LENGTH, true); - pdu.put_string_nc(MGMT_HEADER_SIZE+MgmtConstU16::MGMT_MAX_NAME_LENGTH, short_name, MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH, true); - } - const std::string getName() const noexcept { return pdu.get_string_nc(MGMT_HEADER_SIZE); } - const std::string getShortName() const noexcept { return pdu.get_string_nc(MGMT_HEADER_SIZE + MgmtConstU16::MGMT_MAX_NAME_LENGTH); } - }; - struct MgmtConnParam { EUI48 address; uint8_t address_type; @@ -465,7 +557,7 @@ namespace direct_bt { public: MgmtLoadConnParamCmd(const uint16_t dev_id, const MgmtConnParam & connParam) - : MgmtCommand(MgmtOpcode::LOAD_CONN_PARAM, dev_id, 2 + 15) + : MgmtCommand(Opcode::LOAD_CONN_PARAM, dev_id, 2 + 15) { jau::nsize_t offset = MGMT_HEADER_SIZE; pdu.put_uint16_nc(offset, 1); offset+= 2; @@ -479,7 +571,7 @@ namespace direct_bt { } MgmtLoadConnParamCmd(const uint16_t dev_id, std::vector<std::shared_ptr<MgmtConnParam>> connParams) - : MgmtCommand(MgmtOpcode::LOAD_CONN_PARAM, dev_id, 2 + connParams.size() * 15) + : MgmtCommand(Opcode::LOAD_CONN_PARAM, dev_id, 2 + connParams.size() * 15) { jau::nsize_t offset = MGMT_HEADER_SIZE; pdu.put_uint16_nc(offset, connParams.size()); offset+= 2; @@ -510,7 +602,7 @@ namespace direct_bt { * uint16_t dev-id, * uint16_t param_size */ - class MgmtEvent + class MgmtEvent : public MgmtMsg { public: enum class Opcode : uint16_t { @@ -552,21 +644,23 @@ namespace direct_bt { ADVERTISING_ADDED = 0x0023, ADVERTISING_REMOVED = 0x0024, EXT_INFO_CHANGED = 0x0025, - PHY_CONFIGURATION_CHANGED = 0x0026, - MGMT_EVENT_TYPE_COUNT = 0x0026 + PHY_CONFIGURATION_CHANGED = 0x0026, // linux >= 4.19 + EXP_FEATURE_CHANGED = 0x0027, // linux >= 5.8 + DEVICE_FLAGS_CHANGED = 0x002a, + ADV_MONITOR_ADDED = 0x002b, + ADV_MONITOR_REMOVED = 0x002c, + MGMT_EVENT_TYPE_COUNT = 0x002c }; - + static constexpr uint16_t number(const Opcode rhs) noexcept { + return static_cast<uint16_t>(rhs); + } static std::string getOpcodeString(const Opcode opc) noexcept; protected: - /** actual received mgmt event */ - POctets pdu; - uint64_t ts_creation; - - static void checkOpcode(const Opcode has, const Opcode min, const Opcode max) + inline static void checkOpcode(const Opcode has, const Opcode min, const Opcode max) { if( has < min || has > max ) { - throw MgmtOpcodeException("Has evcode "+jau::uint16HexString(static_cast<uint16_t>(has))+ + throw MgmtOpcodeException("Has opcode "+jau::uint16HexString(static_cast<uint16_t>(has))+ ", not within range ["+jau::uint16HexString(static_cast<uint16_t>(min))+ ".."+jau::uint16HexString(static_cast<uint16_t>(max))+"]", E_FILE_LINE); } @@ -574,16 +668,15 @@ namespace direct_bt { static void checkOpcode(const Opcode has, const Opcode exp) { if( has != exp ) { - throw MgmtOpcodeException("Has evcode "+jau::uint16HexString(static_cast<uint16_t>(has))+ + throw MgmtOpcodeException("Has opcode "+jau::uint16HexString(static_cast<uint16_t>(has))+ ", not matching "+jau::uint16HexString(static_cast<uint16_t>(exp)), E_FILE_LINE); } } - virtual std::string baseString() const { - return "opcode="+jau::uint16HexString(static_cast<uint16_t>(getOpcode()))+ - " "+getOpcodeString()+", devID "+jau::uint16HexString(getDevID(), true); + virtual std::string baseString() const noexcept override { + return "opcode "+getOpcodeString()+", devID "+jau::uint16HexString(getDevID(), true); } - virtual std::string valueString() const { + virtual std::string valueString() const noexcept override { const jau::nsize_t d_sz = getDataSize(); const std::string d_str = d_sz > 0 ? jau::bytesHexString(getData(), 0, d_sz, true /* lsbFirst */, true /* leading0X */) : ""; return "data[size "+std::to_string(d_sz)+", data "+d_str+"], tsz "+std::to_string(getTotalSize()); @@ -601,7 +694,7 @@ namespace direct_bt { /** Persistent memory, w/ ownership ..*/ MgmtEvent(const uint8_t* buffer, const jau::nsize_t buffer_len, const jau::nsize_t exp_param_size) - : pdu(buffer, buffer_len), ts_creation(jau::getCurrentMilliseconds()) + : MgmtMsg(buffer, buffer_len) { const jau::nsize_t paramSize = getParamSize(); pdu.check_range(0, MGMT_HEADER_SIZE+paramSize); @@ -612,7 +705,7 @@ namespace direct_bt { } MgmtEvent(const Opcode opc, const uint16_t dev_id, const uint16_t param_size=0) - : pdu(MGMT_HEADER_SIZE+param_size), ts_creation(jau::getCurrentMilliseconds()) + : MgmtMsg(number(opc), dev_id, param_size) { // checkOpcode(opc, READ_VERSION, SET_BLOCKED_KEYS); @@ -627,11 +720,10 @@ namespace direct_bt { memcpy(pdu.get_wptr_nc(MGMT_HEADER_SIZE), param, param_size); } } - virtual ~MgmtEvent() noexcept {} + virtual ~MgmtEvent() noexcept override {} jau::nsize_t getTotalSize() const noexcept { return pdu.getSize(); } - uint64_t getTimestamp() const noexcept { return ts_creation; } Opcode getOpcode() const noexcept { return static_cast<Opcode>( pdu.get_uint16_nc(0) ); } std::string getOpcodeString() const noexcept { return getOpcodeString(getOpcode()); } uint16_t getDevID() const noexcept { return pdu.get_uint16_nc(2); } @@ -645,17 +737,44 @@ namespace direct_bt { return req.getDevID() == getDevID(); } - std::string toString() const { + std::string toString() const noexcept override { return "MgmtEvt["+baseString()+", "+valueString()+"]"; } }; + /** + * mgmt_addr_info { EUI48, uint8_t type }, + */ + class MgmtEvtAdressInfoMeta : public MgmtEvent + { + protected: + std::string baseString() const noexcept override { + return MgmtEvent::baseString()+", address="+getAddress().toString()+ + ", addressType "+getBDAddressTypeString(getAddressType()); + } + + public: + MgmtEvtAdressInfoMeta(const Opcode opc, const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvent(buffer, buffer_len, 7) + { + checkOpcode(getOpcode(), opc); + } + + virtual ~MgmtEvtAdressInfoMeta() noexcept override {} + + const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info + BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info + + jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+7; } + jau::nsize_t getDataSize() const noexcept override { return getParamSize()-7; } + const uint8_t* getData() const noexcept override { return getDataSize()>0 ? pdu.get_ptr_nc(getDataOffset()) : nullptr; } + }; + class MgmtEvtCmdComplete : public MgmtEvent { protected: - std::string baseString() const override { - return MgmtEvent::baseString()+", req-opcode="+jau::uint16HexString(static_cast<uint16_t>(getReqOpcode()))+ - " "+getMgmtOpcodeString(getReqOpcode())+ + std::string baseString() const noexcept override { + return MgmtEvent::baseString()+", cmd "+MgmtCommand::getOpcodeString(getCmdOpcode())+ ", status "+jau::uint8HexString(static_cast<uint8_t>(getStatus()), true)+" "+getMgmtStatusString(getStatus()); } @@ -667,8 +786,8 @@ namespace direct_bt { public: - static MgmtOpcode getReqOpcode(const uint8_t *data) { - return static_cast<MgmtOpcode>( jau::get_uint16(data, MGMT_HEADER_SIZE, true /* littleEndian */) ); + static MgmtCommand::Opcode getCmdOpcode(const uint8_t *data) { + return static_cast<MgmtCommand::Opcode>( jau::get_uint16(data, MGMT_HEADER_SIZE, true /* littleEndian */) ); } MgmtEvtCmdComplete(const uint8_t* buffer, const jau::nsize_t buffer_len) @@ -679,7 +798,7 @@ namespace direct_bt { virtual ~MgmtEvtCmdComplete() noexcept override {} - MgmtOpcode getReqOpcode() const noexcept { return static_cast<MgmtOpcode>( pdu.get_uint16_nc(MGMT_HEADER_SIZE) ); } + MgmtCommand::Opcode getCmdOpcode() const noexcept { return static_cast<MgmtCommand::Opcode>( pdu.get_uint16_nc(MGMT_HEADER_SIZE) ); } MgmtStatus getStatus() const noexcept { return static_cast<MgmtStatus>( pdu.get_uint8_nc(MGMT_HEADER_SIZE+2) ); } jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+3; } @@ -687,19 +806,24 @@ namespace direct_bt { const uint8_t* getData() const noexcept override { return getDataSize()>0 ? pdu.get_ptr_nc(getDataOffset()) : nullptr; } bool validate(const MgmtCommand &req) const noexcept override { - return MgmtEvent::validate(req) && req.getOpcode() == getReqOpcode(); + return MgmtEvent::validate(req) && req.getOpcode() == getCmdOpcode(); } /** + * Returns AdapterSetting if getCmdOpcode() expects a single 4-octet AdapterSetting and hence getDataSize() == 4. + */ + AdapterSetting getCurrentSettings() const noexcept; + + /** * Convert this instance into ConnectionInfo - * if getReqOpcode() == GET_CONN_INFO, getStatus() == SUCCESS and size allows, + * if getCmdOpcode() == GET_CONN_INFO, getStatus() == SUCCESS and size allows, * otherwise returns nullptr. */ std::shared_ptr<ConnectionInfo> toConnectionInfo() const noexcept; /** * Convert this instance into ConnectionInfo - * if getReqOpcode() == SET_LOCAL_NAME, getStatus() == SUCCESS and size allows, + * if getCmdOpcode() == SET_LOCAL_NAME, getStatus() == SUCCESS and size allows, * otherwise returns nullptr. */ std::shared_ptr<NameAndShortName> toNameAndShortName() const noexcept; @@ -710,9 +834,8 @@ namespace direct_bt { public: protected: - std::string baseString() const override { - return MgmtEvent::baseString()+", req-opcode="+jau::uint16HexString(static_cast<uint16_t>(getReqOpcode()))+ - " "+getMgmtOpcodeString(getReqOpcode())+ + std::string baseString() const noexcept override { + return MgmtEvent::baseString()+", cmd "+MgmtCommand::getOpcodeString(getCmdOpcode())+ ", status "+jau::uint8HexString(static_cast<uint8_t>(getStatus()))+" "+getMgmtStatusString(getStatus()); } @@ -722,7 +845,7 @@ namespace direct_bt { { checkOpcode(getOpcode(), Opcode::CMD_STATUS); } - MgmtOpcode getReqOpcode() const noexcept { return static_cast<MgmtOpcode>( pdu.get_uint16_nc(MGMT_HEADER_SIZE) ); } + MgmtCommand::Opcode getCmdOpcode() const noexcept { return static_cast<MgmtCommand::Opcode>( pdu.get_uint16_nc(MGMT_HEADER_SIZE) ); } MgmtStatus getStatus() const noexcept { return static_cast<MgmtStatus>( pdu.get_uint8_nc(MGMT_HEADER_SIZE+2) ); } jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+3; } @@ -730,38 +853,28 @@ namespace direct_bt { const uint8_t* getData() const noexcept override { return nullptr; } bool validate(const MgmtCommand &req) const noexcept override { - return MgmtEvent::validate(req) && req.getOpcode() == getReqOpcode(); + return MgmtEvent::validate(req) && req.getOpcode() == getCmdOpcode(); } }; - class MgmtEvtDiscovering : public MgmtEvent + class MgmtEvtControllerError : public MgmtEvent { public: protected: - std::string baseString() const override { - return MgmtEvent::baseString()+", scan-type "+getScanTypeString(getScanType())+ - ", enabled "+std::to_string(getEnabled()); + std::string baseString() const noexcept override { + return MgmtEvent::baseString()+", error-code "+jau::uint8HexString(static_cast<uint8_t>(getErrorCode())); } public: - MgmtEvtDiscovering(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, 2) - { - checkOpcode(getOpcode(), Opcode::DISCOVERING); - } - - MgmtEvtDiscovering(const uint16_t dev_id, const ScanType scanType, const bool enabled) - : MgmtEvent(Opcode::DISCOVERING, dev_id, 1+1) + MgmtEvtControllerError(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvent(buffer, buffer_len, 1) { - pdu.put_uint8_nc(MGMT_HEADER_SIZE, number(scanType)); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+1, enabled); + checkOpcode(getOpcode(), Opcode::CONTROLLER_ERROR); } + uint8_t getErrorCode() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE); } - ScanType getScanType() const noexcept { return static_cast<ScanType>( pdu.get_uint8_nc(MGMT_HEADER_SIZE) ); } - bool getEnabled() const noexcept { return 0 != pdu.get_uint8_nc(MGMT_HEADER_SIZE+1); } - - jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+2; } + jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+1; } jau::nsize_t getDataSize() const noexcept override { return 0; } const uint8_t* getData() const noexcept override { return nullptr; } }; @@ -774,7 +887,7 @@ namespace direct_bt { public: protected: - std::string baseString() const override { + std::string baseString() const noexcept override { return MgmtEvent::baseString()+", settings="+getAdapterSettingMaskString(getSettings()); } @@ -792,103 +905,41 @@ namespace direct_bt { }; /** - * mgmt_addr_info { EUI48, uint8_t type }, - * int8_t store_hint, - * uint16_t min_interval; - * uint16_t max_interval; - * uint16_t latency, - * uint16_t timeout, + * uint8_t name[MGMT_MAX_NAME_LENGTH]; + * uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH]; */ - class MgmtEvtNewConnectionParam : public MgmtEvent + class MgmtEvtLocalNameChanged : public MgmtEvent { - public: - protected: - std::string baseString() const override { - return MgmtEvent::baseString()+", address="+getAddress().toString()+ - ", addressType "+getBDAddressTypeString(getAddressType())+ - ", store-hint "+std::to_string(getStoreHint())+ - ", interval["+std::to_string(getMinInterval())+".."+std::to_string(getMaxInterval())+ - "], latency "+std::to_string(getLatency())+", timeout "+std::to_string(getTimeout()); + std::string valueString() const noexcept override { + return "name '"+getName()+"', shortName '"+getShortName()+"'"; } public: - MgmtEvtNewConnectionParam(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, 16) - { - checkOpcode(getOpcode(), Opcode::NEW_CONN_PARAM); - } - const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info - BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info - - int8_t getStoreHint() const noexcept { return pdu.get_int8_nc(MGMT_HEADER_SIZE+7); } - uint16_t getMinInterval() const noexcept { return pdu.get_uint32_nc(MGMT_HEADER_SIZE+8); } - uint16_t getMaxInterval() const noexcept { return pdu.get_uint32_nc(MGMT_HEADER_SIZE+10); } - uint16_t getLatency() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE+12); } - uint16_t getTimeout() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE+14); } - - jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+16; } - jau::nsize_t getDataSize() const noexcept override { return getParamSize()-16; } - const uint8_t* getData() const noexcept override { return getDataSize()>0 ? pdu.get_ptr_nc(getDataOffset()) : nullptr; } - }; - - /** - * mgmt_addr_info { EUI48, uint8_t type }, - * int8_t rssi, - * uint32_t flags, - * uint16_t eir_len; - * uint8_t *eir - */ - class MgmtEvtDeviceFound : public MgmtEvent - { - private: - std::shared_ptr<EInfoReport> eireport; - - protected: - std::string baseString() const override { - if( nullptr != eireport ) { - return MgmtEvent::baseString()+", "+eireport->toString(false /* includeServices */); - } else { - return MgmtEvent::baseString()+", address="+getAddress().toString()+ - ", addressType "+getBDAddressTypeString(getAddressType())+ - ", rssi "+std::to_string(getRSSI())+", flags="+jau::uint32HexString(getFlags(), true)+ - ", eir-size "+std::to_string(getEIRSize()); - } - } + static jau::nsize_t namesDataSize() noexcept { return MgmtConstU16::MGMT_MAX_NAME_LENGTH + MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH; } + static jau::nsize_t getRequiredTotalSize() noexcept { return MGMT_HEADER_SIZE + namesDataSize(); } - public: - MgmtEvtDeviceFound(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, 14) + MgmtEvtLocalNameChanged(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvent(buffer, buffer_len, namesDataSize()) { - checkOpcode(getOpcode(), Opcode::DEVICE_FOUND); - eireport = nullptr; + checkOpcode(getOpcode(), Opcode::LOCAL_NAME_CHANGED); } - MgmtEvtDeviceFound(const uint16_t dev_id, std::shared_ptr<EInfoReport> eir) - : MgmtEvent(Opcode::DEVICE_FOUND, dev_id, 6+1+1+4+2+0) + MgmtEvtLocalNameChanged(const uint16_t dev_id, const std::string & name, const std::string & short_name) + : MgmtEvent(Opcode::LOCAL_NAME_CHANGED, dev_id, MgmtConstU16::MGMT_MAX_NAME_LENGTH + MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH) { - pdu.put_eui48_nc(MGMT_HEADER_SIZE, eir->getAddress()); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(eir->getAddressType())); - pdu.put_int8_nc(MGMT_HEADER_SIZE+6+1, eir->getRSSI()); - pdu.put_uint32_nc(MGMT_HEADER_SIZE+6+1+1, eir->getFlags()); // EIR flags only 8bit, Mgmt uses 32bit? - pdu.put_uint16_nc(MGMT_HEADER_SIZE+6+1+1+4, 0); // eir_len - eireport = eir; + pdu.put_string_nc(MGMT_HEADER_SIZE, name, MgmtConstU16::MGMT_MAX_NAME_LENGTH, true); + pdu.put_string_nc(MGMT_HEADER_SIZE+MgmtConstU16::MGMT_MAX_NAME_LENGTH, short_name, MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH, true); } - /** Returns the EInfoReport, assuming creation occurred via HCIHandler. Otherwise nullptr. */ - std::shared_ptr<EInfoReport> getEIR() const noexcept { return eireport; } - - const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info - BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info - - int8_t getRSSI() const noexcept { return pdu.get_int8_nc(MGMT_HEADER_SIZE+7); } - uint32_t getFlags() const noexcept { return pdu.get_uint32_nc(MGMT_HEADER_SIZE+8); } - uint16_t getEIRSize() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE+12); } + const std::string getName() const noexcept { return pdu.get_string_nc(MGMT_HEADER_SIZE); } + const std::string getShortName() const noexcept { return pdu.get_string_nc(MGMT_HEADER_SIZE + MgmtConstU16::MGMT_MAX_NAME_LENGTH); } - jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+14; } - jau::nsize_t getDataSize() const noexcept override { return getParamSize()-14; } - const uint8_t* getData() const noexcept override { return getDataSize()>0 ? pdu.get_ptr_nc(getDataOffset()) : nullptr; } + std::shared_ptr<NameAndShortName> toNameAndShortName() const noexcept; }; + // FIXME NEW_LINK_KEY + // FIXME NEW_LONG_TERM_KEY + /** * mgmt_addr_info { EUI48, uint8_t type }, * uint32_t flags, @@ -901,7 +952,7 @@ namespace direct_bt { uint16_t hci_conn_handle; protected: - std::string baseString() const override { + std::string baseString() const noexcept override { return MgmtEvent::baseString()+", address="+getAddress().toString()+ ", addressType "+getBDAddressTypeString(getAddressType())+ ", flags="+jau::uint32HexString(getFlags(), true)+ @@ -919,7 +970,7 @@ namespace direct_bt { : MgmtEvent(Opcode::DEVICE_CONNECTED, dev_id, 6+1+4+2), hci_conn_handle(hci_conn_handle_) { pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(addressType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(addressType)); pdu.put_uint32_nc(MGMT_HEADER_SIZE+6+1, 0); // flags pdu.put_uint16_nc(MGMT_HEADER_SIZE+6+1+4, 0); // eir-len } @@ -940,49 +991,6 @@ namespace direct_bt { /** * mgmt_addr_info { EUI48, uint8_t type }, - * uint8_t status - */ - class MgmtEvtDeviceConnectFailed : public MgmtEvent - { - private: - const HCIStatusCode hciStatus; - - protected: - std::string baseString() const override { - return MgmtEvent::baseString()+", address="+getAddress().toString()+ - ", addressType "+getBDAddressTypeString(getAddressType())+ - ", status[mgmt["+jau::uint8HexString(static_cast<uint8_t>(getStatus()))+" ("+getMgmtStatusString(getStatus())+")]"+ - ", hci["+jau::uint8HexString(static_cast<uint8_t>(hciStatus))+" ("+getHCIStatusCodeString(hciStatus)+")]]"; - } - - public: - MgmtEvtDeviceConnectFailed(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, 8), hciStatus(HCIStatusCode::UNKNOWN) - { - checkOpcode(getOpcode(), Opcode::CONNECT_FAILED); - } - MgmtEvtDeviceConnectFailed(const uint16_t dev_id, const EUI48 &address, const BDAddressType addressType, const HCIStatusCode status) - : MgmtEvent(Opcode::CONNECT_FAILED, dev_id, 6+1+1), hciStatus(status) - { - pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(addressType)); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6+1, static_cast<uint8_t>(MgmtStatus::CONNECT_FAILED)); - } - const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info - BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info - - MgmtStatus getStatus() const noexcept { return static_cast<MgmtStatus>( pdu.get_uint8_nc(MGMT_HEADER_SIZE+7) ); } - - /** Return the root reason in non reduced HCIStatusCode space, if available. Otherwise this value will be HCIStatusCode::UNKNOWN. */ - HCIStatusCode getHCIStatus() const noexcept { return hciStatus; } - - jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+8; } - jau::nsize_t getDataSize() const noexcept override { return getParamSize()-8; } - const uint8_t* getData() const noexcept override { return getDataSize()>0 ? pdu.get_ptr_nc(getDataOffset()) : nullptr; } - }; - - /** - * mgmt_addr_info { EUI48, uint8_t type }, * uint8_t reason */ class MgmtEvtDeviceDisconnected : public MgmtEvent @@ -1016,7 +1024,7 @@ namespace direct_bt { const uint16_t hci_conn_handle; protected: - std::string baseString() const override { + std::string baseString() const noexcept override { const DisconnectReason reason1 = getReason(); const HCIStatusCode reason2 = getHCIReason(); return MgmtEvent::baseString()+", address="+getAddress().toString()+ @@ -1038,7 +1046,7 @@ namespace direct_bt { { DisconnectReason disconnectReason = getDisconnectReason(hciReason_); pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); - pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, number(addressType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(addressType)); pdu.put_uint8_nc(MGMT_HEADER_SIZE+6+1, static_cast<uint8_t>(disconnectReason)); } @@ -1065,29 +1073,41 @@ namespace direct_bt { /** * mgmt_addr_info { EUI48, uint8_t type }, - * uint8_t secure + * uint8_t status */ - class MgmtEvtPinCodeRequest : public MgmtEvent + class MgmtEvtDeviceConnectFailed : public MgmtEvent { - public: + private: + const HCIStatusCode hciStatus; protected: - std::string baseString() const override { + std::string baseString() const noexcept override { return MgmtEvent::baseString()+", address="+getAddress().toString()+ ", addressType "+getBDAddressTypeString(getAddressType())+ - ", secure "+std::to_string(getSecure()); + ", status[mgmt["+jau::uint8HexString(static_cast<uint8_t>(getStatus()))+" ("+getMgmtStatusString(getStatus())+")]"+ + ", hci["+jau::uint8HexString(static_cast<uint8_t>(hciStatus))+" ("+getHCIStatusCodeString(hciStatus)+")]]"; } public: - MgmtEvtPinCodeRequest(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, 8) + MgmtEvtDeviceConnectFailed(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvent(buffer, buffer_len, 8), hciStatus(HCIStatusCode::UNKNOWN) { - checkOpcode(getOpcode(), Opcode::PIN_CODE_REQUEST); + checkOpcode(getOpcode(), Opcode::CONNECT_FAILED); + } + MgmtEvtDeviceConnectFailed(const uint16_t dev_id, const EUI48 &address, const BDAddressType addressType, const HCIStatusCode status) + : MgmtEvent(Opcode::CONNECT_FAILED, dev_id, 6+1+1), hciStatus(status) + { + pdu.put_eui48_nc(MGMT_HEADER_SIZE, address); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(addressType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6+1, static_cast<uint8_t>(MgmtStatus::CONNECT_FAILED)); } const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info - uint8_t getSecure() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE+7); } + MgmtStatus getStatus() const noexcept { return static_cast<MgmtStatus>( pdu.get_uint8_nc(MGMT_HEADER_SIZE+7) ); } + + /** Return the root reason in non reduced HCIStatusCode space, if available. Otherwise this value will be HCIStatusCode::UNKNOWN. */ + HCIStatusCode getHCIStatus() const noexcept { return hciStatus; } jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+8; } jau::nsize_t getDataSize() const noexcept override { return getParamSize()-8; } @@ -1096,155 +1116,275 @@ namespace direct_bt { /** * mgmt_addr_info { EUI48, uint8_t type }, - * uint8_t action + * uint8_t secure */ - class MgmtEvtDeviceWhitelistAdded : public MgmtEvent + class MgmtEvtPinCodeRequest : public MgmtEvent { public: protected: - std::string baseString() const override { + std::string baseString() const noexcept override { return MgmtEvent::baseString()+", address="+getAddress().toString()+ ", addressType "+getBDAddressTypeString(getAddressType())+ - ", action "+std::to_string(getAction()); + ", secure "+std::to_string(getSecure()); } public: - MgmtEvtDeviceWhitelistAdded(const uint8_t* buffer, const jau::nsize_t buffer_len) + MgmtEvtPinCodeRequest(const uint8_t* buffer, const jau::nsize_t buffer_len) : MgmtEvent(buffer, buffer_len, 8) { - checkOpcode(getOpcode(), Opcode::DEVICE_WHITELIST_ADDED); + checkOpcode(getOpcode(), Opcode::PIN_CODE_REQUEST); } const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info - uint8_t getAction() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE+7); } + uint8_t getSecure() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE+7); } jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+8; } jau::nsize_t getDataSize() const noexcept override { return getParamSize()-8; } const uint8_t* getData() const noexcept override { return getDataSize()>0 ? pdu.get_ptr_nc(getDataOffset()) : nullptr; } }; + // FIXME USER_CONFIRM_REQUEST = 0x000F, + /** * mgmt_addr_info { EUI48, uint8_t type }, */ - class MgmtEvtAdressInfoMeta : public MgmtEvent + class MgmtEvtUserPasskeyRequest: public MgmtEvtAdressInfoMeta { + public: + MgmtEvtUserPasskeyRequest(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvtAdressInfoMeta(Opcode::USER_PASSKEY_REQUEST, buffer, buffer_len) + { } + }; + + // FIXME AUTH_FAILED = 0x0011, + + /** + * mgmt_addr_info { EUI48, uint8_t type }, + * int8_t rssi, + * uint32_t flags, + * uint16_t eir_len; + * uint8_t *eir + */ + class MgmtEvtDeviceFound : public MgmtEvent + { + private: + std::shared_ptr<EInfoReport> eireport; + protected: - std::string baseString() const override { - return MgmtEvent::baseString()+", address="+getAddress().toString()+ - ", addressType "+getBDAddressTypeString(getAddressType()); + std::string baseString() const noexcept override { + if( nullptr != eireport ) { + return MgmtEvent::baseString()+", "+eireport->toString(false /* includeServices */); + } else { + return MgmtEvent::baseString()+", address="+getAddress().toString()+ + ", addressType "+getBDAddressTypeString(getAddressType())+ + ", rssi "+std::to_string(getRSSI())+", flags="+jau::uint32HexString(getFlags(), true)+ + ", eir-size "+std::to_string(getEIRSize()); + } } public: - MgmtEvtAdressInfoMeta(const Opcode opc, const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, 7) + MgmtEvtDeviceFound(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvent(buffer, buffer_len, 14) { - checkOpcode(getOpcode(), opc); + checkOpcode(getOpcode(), Opcode::DEVICE_FOUND); + eireport = nullptr; + } + MgmtEvtDeviceFound(const uint16_t dev_id, std::shared_ptr<EInfoReport> eir) + : MgmtEvent(Opcode::DEVICE_FOUND, dev_id, 6+1+1+4+2+0) + { + pdu.put_eui48_nc(MGMT_HEADER_SIZE, eir->getAddress()); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+6, direct_bt::number(eir->getAddressType())); + pdu.put_int8_nc(MGMT_HEADER_SIZE+6+1, eir->getRSSI()); + pdu.put_uint32_nc(MGMT_HEADER_SIZE+6+1+1, eir->getFlags()); // EIR flags only 8bit, Mgmt uses 32bit? + pdu.put_uint16_nc(MGMT_HEADER_SIZE+6+1+1+4, 0); // eir_len + eireport = eir; } - virtual ~MgmtEvtAdressInfoMeta() noexcept override {} + /** Returns the EInfoReport, assuming creation occurred via HCIHandler. Otherwise nullptr. */ + std::shared_ptr<EInfoReport> getEIR() const noexcept { return eireport; } const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info - jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+7; } - jau::nsize_t getDataSize() const noexcept override { return getParamSize()-7; } + int8_t getRSSI() const noexcept { return pdu.get_int8_nc(MGMT_HEADER_SIZE+7); } + uint32_t getFlags() const noexcept { return pdu.get_uint32_nc(MGMT_HEADER_SIZE+8); } + uint16_t getEIRSize() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE+12); } + + jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+14; } + jau::nsize_t getDataSize() const noexcept override { return getParamSize()-14; } const uint8_t* getData() const noexcept override { return getDataSize()>0 ? pdu.get_ptr_nc(getDataOffset()) : nullptr; } }; + class MgmtEvtDiscovering : public MgmtEvent + { + public: + + protected: + std::string baseString() const noexcept override { + return MgmtEvent::baseString()+", scan-type "+getScanTypeString(getScanType())+ + ", enabled "+std::to_string(getEnabled()); + } + + public: + MgmtEvtDiscovering(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvent(buffer, buffer_len, 2) + { + checkOpcode(getOpcode(), Opcode::DISCOVERING); + } + + MgmtEvtDiscovering(const uint16_t dev_id, const ScanType scanType, const bool enabled) + : MgmtEvent(Opcode::DISCOVERING, dev_id, 1+1) + { + pdu.put_uint8_nc(MGMT_HEADER_SIZE, direct_bt::number(scanType)); + pdu.put_uint8_nc(MGMT_HEADER_SIZE+1, enabled); + } + + ScanType getScanType() const noexcept { return static_cast<ScanType>( pdu.get_uint8_nc(MGMT_HEADER_SIZE) ); } + bool getEnabled() const noexcept { return 0 != pdu.get_uint8_nc(MGMT_HEADER_SIZE+1); } + + jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+2; } + jau::nsize_t getDataSize() const noexcept override { return 0; } + const uint8_t* getData() const noexcept override { return nullptr; } + }; + /** * mgmt_addr_info { EUI48, uint8_t type }, */ - class MgmtEvtDeviceWhitelistRemoved : public MgmtEvtAdressInfoMeta + class MgmtEvtDeviceBlocked : public MgmtEvtAdressInfoMeta { public: - MgmtEvtDeviceWhitelistRemoved(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvtAdressInfoMeta(Opcode::DEVICE_WHITELIST_REMOVED, buffer, buffer_len) + MgmtEvtDeviceBlocked(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvtAdressInfoMeta(Opcode::DEVICE_BLOCKED, buffer, buffer_len) { } }; /** * mgmt_addr_info { EUI48, uint8_t type }, */ - class MgmtEvtDeviceUnpaired : public MgmtEvtAdressInfoMeta + class MgmtEvtDeviceUnblocked : public MgmtEvtAdressInfoMeta { public: - MgmtEvtDeviceUnpaired(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvtAdressInfoMeta(Opcode::DEVICE_UNPAIRED, buffer, buffer_len) + MgmtEvtDeviceUnblocked(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvtAdressInfoMeta(Opcode::DEVICE_UNBLOCKED, buffer, buffer_len) { } }; /** * mgmt_addr_info { EUI48, uint8_t type }, */ - class MgmtEvtDeviceBlocked : public MgmtEvtAdressInfoMeta + class MgmtEvtDeviceUnpaired : public MgmtEvtAdressInfoMeta { public: - MgmtEvtDeviceBlocked(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvtAdressInfoMeta(Opcode::DEVICE_BLOCKED, buffer, buffer_len) + MgmtEvtDeviceUnpaired(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvtAdressInfoMeta(Opcode::DEVICE_UNPAIRED, buffer, buffer_len) { } }; + // FIXME PASSKEY_NOTIFY = 0x0017, + // FIXME NEW_IRK = 0x0018, + // FIXME NEW_CSRK = 0x0019, + /** * mgmt_addr_info { EUI48, uint8_t type }, + * uint8_t action */ - class MgmtEvtDeviceUnblocked : public MgmtEvtAdressInfoMeta + class MgmtEvtDeviceWhitelistAdded : public MgmtEvent { public: - MgmtEvtDeviceUnblocked(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvtAdressInfoMeta(Opcode::DEVICE_UNBLOCKED, buffer, buffer_len) - { } + + protected: + std::string baseString() const noexcept override { + return MgmtEvent::baseString()+", address="+getAddress().toString()+ + ", addressType "+getBDAddressTypeString(getAddressType())+ + ", action "+std::to_string(getAction()); + } + + public: + MgmtEvtDeviceWhitelistAdded(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvent(buffer, buffer_len, 8) + { + checkOpcode(getOpcode(), Opcode::DEVICE_WHITELIST_ADDED); + } + const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info + BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info + + uint8_t getAction() const noexcept { return pdu.get_uint8_nc(MGMT_HEADER_SIZE+7); } + + jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+8; } + jau::nsize_t getDataSize() const noexcept override { return getParamSize()-8; } + const uint8_t* getData() const noexcept override { return getDataSize()>0 ? pdu.get_ptr_nc(getDataOffset()) : nullptr; } }; /** * mgmt_addr_info { EUI48, uint8_t type }, */ - class MgmtEvtUserPasskeyRequest: public MgmtEvtAdressInfoMeta + class MgmtEvtDeviceWhitelistRemoved : public MgmtEvtAdressInfoMeta { public: - MgmtEvtUserPasskeyRequest(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvtAdressInfoMeta(Opcode::USER_PASSKEY_REQUEST, buffer, buffer_len) + MgmtEvtDeviceWhitelistRemoved(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvtAdressInfoMeta(Opcode::DEVICE_WHITELIST_REMOVED, buffer, buffer_len) { } }; /** - * uint8_t name[MGMT_MAX_NAME_LENGTH]; - * uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH]; + * mgmt_addr_info { EUI48, uint8_t type }, + * int8_t store_hint, + * uint16_t min_interval; + * uint16_t max_interval; + * uint16_t latency, + * uint16_t timeout, */ - class MgmtEvtLocalNameChanged : public MgmtEvent + class MgmtEvtNewConnectionParam : public MgmtEvent { + public: + protected: - std::string valueString() const override { - return "name '"+getName()+"', shortName '"+getShortName()+"'"; + std::string baseString() const noexcept override { + return MgmtEvent::baseString()+", address="+getAddress().toString()+ + ", addressType "+getBDAddressTypeString(getAddressType())+ + ", store-hint "+std::to_string(getStoreHint())+ + ", interval["+std::to_string(getMinInterval())+".."+std::to_string(getMaxInterval())+ + "], latency "+std::to_string(getLatency())+", timeout "+std::to_string(getTimeout()); } public: - static jau::nsize_t namesDataSize() noexcept { return MgmtConstU16::MGMT_MAX_NAME_LENGTH + MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH; } - static jau::nsize_t getRequiredTotalSize() noexcept { return MGMT_HEADER_SIZE + namesDataSize(); } - - MgmtEvtLocalNameChanged(const uint8_t* buffer, const jau::nsize_t buffer_len) - : MgmtEvent(buffer, buffer_len, namesDataSize()) - { - checkOpcode(getOpcode(), Opcode::LOCAL_NAME_CHANGED); - } - MgmtEvtLocalNameChanged(const uint16_t dev_id, const std::string & name, const std::string & short_name) - : MgmtEvent(Opcode::LOCAL_NAME_CHANGED, dev_id, MgmtConstU16::MGMT_MAX_NAME_LENGTH + MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH) + MgmtEvtNewConnectionParam(const uint8_t* buffer, const jau::nsize_t buffer_len) + : MgmtEvent(buffer, buffer_len, 16) { - pdu.put_string_nc(MGMT_HEADER_SIZE, name, MgmtConstU16::MGMT_MAX_NAME_LENGTH, true); - pdu.put_string_nc(MGMT_HEADER_SIZE+MgmtConstU16::MGMT_MAX_NAME_LENGTH, short_name, MgmtConstU16::MGMT_MAX_SHORT_NAME_LENGTH, true); + checkOpcode(getOpcode(), Opcode::NEW_CONN_PARAM); } + const EUI48 getAddress() const noexcept { return EUI48(pdu.get_ptr_nc(MGMT_HEADER_SIZE)); } // mgmt_addr_info + BDAddressType getAddressType() const noexcept { return static_cast<BDAddressType>(pdu.get_uint8_nc(MGMT_HEADER_SIZE+6)); } // mgmt_addr_info - const std::string getName() const noexcept { return pdu.get_string_nc(MGMT_HEADER_SIZE); } - const std::string getShortName() const noexcept { return pdu.get_string_nc(MGMT_HEADER_SIZE + MgmtConstU16::MGMT_MAX_NAME_LENGTH); } + int8_t getStoreHint() const noexcept { return pdu.get_int8_nc(MGMT_HEADER_SIZE+7); } + uint16_t getMinInterval() const noexcept { return pdu.get_uint32_nc(MGMT_HEADER_SIZE+8); } + uint16_t getMaxInterval() const noexcept { return pdu.get_uint32_nc(MGMT_HEADER_SIZE+10); } + uint16_t getLatency() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE+12); } + uint16_t getTimeout() const noexcept { return pdu.get_uint16_nc(MGMT_HEADER_SIZE+14); } - std::shared_ptr<NameAndShortName> toNameAndShortName() const noexcept; + jau::nsize_t getDataOffset() const noexcept override { return MGMT_HEADER_SIZE+16; } + jau::nsize_t getDataSize() const noexcept override { return getParamSize()-16; } + const uint8_t* getData() const noexcept override { return getDataSize()>0 ? pdu.get_ptr_nc(getDataOffset()) : nullptr; } }; + // TODO UNCONF_INDEX_ADDED = 0x001D, + // TODO UNCONF_INDEX_REMOVED = 0x001E, + // TODO NEW_CONFIG_OPTIONS = 0x001F, + // TODO EXT_INDEX_ADDED = 0x0020, + // TODO EXT_INDEX_REMOVED = 0x0021, + // TODO LOCAL_OOB_DATA_UPDATED = 0x0022, + // TODO ADVERTISING_ADDED = 0x0023, + // TODO ADVERTISING_REMOVED = 0x0024, + // TODO EXT_INFO_CHANGED = 0x0025, + // TODO PHY_CONFIGURATION_CHANGED = 0x0026, + // TODO MGMT_EVENT_TYPE_COUNT = 0x0026 + class MgmtEvtAdapterInfo : public MgmtEvtCmdComplete { protected: - std::string valueString() const override { + std::string valueString() const noexcept override { return getAddress().toString()+", version "+std::to_string(getVersion())+ ", manuf "+std::to_string(getManufacturer())+ ", settings[sup "+getAdapterSettingMaskString(getSupportedSetting())+", cur "+getAdapterSettingMaskString(getCurrentSetting())+ diff --git a/api/direct_bt/SMPHandler.hpp b/api/direct_bt/SMPHandler.hpp index 814b2cd6..49c149e5 100644 --- a/api/direct_bt/SMPHandler.hpp +++ b/api/direct_bt/SMPHandler.hpp @@ -50,8 +50,10 @@ */ #ifdef __linux__ #define SMP_SUPPORTED_BY_OS 0 + #define USE_LINUX_BT_SECURITY 1 #else #define SMP_SUPPORTED_BY_OS 1 + #define USE_LINUX_BT_SECURITY 0 #endif /** diff --git a/src/direct_bt/DBTAdapter.cpp b/src/direct_bt/DBTAdapter.cpp index f72bd733..dc609653 100644 --- a/src/direct_bt/DBTAdapter.cpp +++ b/src/direct_bt/DBTAdapter.cpp @@ -322,15 +322,18 @@ std::shared_ptr<NameAndShortName> DBTAdapter::setLocalName(const std::string &na } bool DBTAdapter::setDiscoverable(bool value) noexcept { - return mgmt.setMode(dev_id, MgmtOpcode::SET_DISCOVERABLE, value ? 1 : 0); + AdapterSetting current_settings; + return MgmtStatus::SUCCESS == mgmt.setDiscoverable(dev_id, value ? 0x01 : 0x00, 10 /* timeout seconds */, current_settings); } bool DBTAdapter::setBondable(bool value) noexcept { - return mgmt.setMode(dev_id, MgmtOpcode::SET_BONDABLE, value ? 1 : 0); + AdapterSetting current_settings; + return mgmt.setMode(dev_id, MgmtCommand::Opcode::SET_BONDABLE, value ? 1 : 0, current_settings); } bool DBTAdapter::setPowered(bool value) noexcept { - return mgmt.setMode(dev_id, MgmtOpcode::SET_POWERED, value ? 1 : 0); + AdapterSetting current_settings; + return mgmt.setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, value ? 1 : 0, current_settings); } HCIStatusCode DBTAdapter::reset() noexcept { diff --git a/src/direct_bt/DBTManager.cpp b/src/direct_bt/DBTManager.cpp index 4b805b58..76c7aedb 100644 --- a/src/direct_bt/DBTManager.cpp +++ b/src/direct_bt/DBTManager.cpp @@ -46,6 +46,8 @@ #include "HCIComm.hpp" #include "DBTTypes.hpp" +#include "SMPHandler.hpp" + extern "C" { #include <inttypes.h> #include <unistd.h> @@ -232,22 +234,10 @@ std::shared_ptr<MgmtEvent> DBTManager::sendWithReply(MgmtCommand &req) noexcept return nullptr; } -void DBTManager::setAdapterMode(const uint16_t dev_id, const uint8_t ssp, const uint8_t bredr, const uint8_t le) noexcept { - bool res; - res = setMode(dev_id, MgmtOpcode::SET_SSP, ssp); - DBG_PRINT("setAdapterMode[%d]: SET_SSP(%d): result %d", dev_id, ssp, res); - - res = setMode(dev_id, MgmtOpcode::SET_BREDR, bredr); - DBG_PRINT("setAdapterMode[%d]: SET_BREDR(%d): result %d", dev_id, bredr, res); - - res = setMode(dev_id, MgmtOpcode::SET_LE, le); - DBG_PRINT("setAdapterMode[%d]: SET_LE(%d): result %d", dev_id, le, res); -} - std::shared_ptr<AdapterInfo> DBTManager::initAdapter(const uint16_t dev_id, const BTMode btMode) noexcept { std::shared_ptr<AdapterInfo> adapterInfo = nullptr; - bool powered; - MgmtCommand req0(MgmtOpcode::READ_INFO, dev_id); + AdapterSetting current_settings; + MgmtCommand req0(MgmtCommand::Opcode::READ_INFO, dev_id); { std::shared_ptr<MgmtEvent> res = sendWithReply(req0); if( nullptr == res ) { @@ -264,35 +254,50 @@ std::shared_ptr<AdapterInfo> DBTManager::initAdapter(const uint16_t dev_id, cons } } DBG_PRINT("initAdapter[%d, BTMode %s]: Start: %s", dev_id, getBTModeString(btMode).c_str(), adapterInfo->toString().c_str()); + current_settings = adapterInfo->getCurrentSettingMask(); switch ( btMode ) { case BTMode::DUAL: - setAdapterMode(dev_id, 1 /* ssp */, 1 /* bredr */, 1 /* le */); + setMode(dev_id, MgmtCommand::Opcode::SET_SSP, 1, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_BREDR, 1, current_settings); + setDiscoverable(dev_id, 0, 0, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_LE, 1, current_settings); +#if USE_LINUX_BT_SECURITY + setMode(dev_id, MgmtCommand::Opcode::SET_SECURE_CONN, 1, current_settings); +#endif break; case BTMode::BREDR: - setAdapterMode(dev_id, 1 /* ssp */, 1 /* bredr */, 0 /* le */); + setMode(dev_id, MgmtCommand::Opcode::SET_SSP, 1, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_BREDR, 1, current_settings); + setDiscoverable(dev_id, 0, 0, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_LE, 0, current_settings); break; case BTMode::NONE: [[fallthrough]]; // map NONE -> LE case BTMode::LE: - setAdapterMode(dev_id, 0 /* ssp */, 0 /* bredr */, 1 /* le */); + setMode(dev_id, MgmtCommand::Opcode::SET_SSP, 0, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_BREDR, 0, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_LE, 1, current_settings); +#if USE_LINUX_BT_SECURITY + setMode(dev_id, MgmtCommand::Opcode::SET_SECURE_CONN, 1, current_settings); +#endif break; } - setMode(dev_id, MgmtOpcode::SET_CONNECTABLE, 0); - setMode(dev_id, MgmtOpcode::SET_FAST_CONNECTABLE, 0); + setMode(dev_id, MgmtCommand::Opcode::SET_CONNECTABLE, 0, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_FAST_CONNECTABLE, 0, current_settings); removeDeviceFromWhitelist(dev_id, EUI48_ANY_DEVICE, BDAddressType::BDADDR_BREDR); // flush whitelist! - powered = setMode(dev_id, MgmtOpcode::SET_POWERED, 1); - DBG_PRINT("setAdapterMode[%d]: SET_POWERED(1): result %d", dev_id, powered); + setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, 1, current_settings); /** * Update AdapterSettings post settings */ - { + if( AdapterSetting::NONE != current_settings ) { + adapterInfo->setCurrentSettingMask(current_settings); + } else { adapterInfo = nullptr; // flush - std::shared_ptr<MgmtEvent> res = sendWithReply(req0); if( nullptr == res ) { goto fail; @@ -314,10 +319,12 @@ fail: } void DBTManager::shutdownAdapter(const uint16_t dev_id) noexcept { - setMode(dev_id, MgmtOpcode::SET_CONNECTABLE, 0); - setMode(dev_id, MgmtOpcode::SET_FAST_CONNECTABLE, 0); - setMode(dev_id, MgmtOpcode::SET_DISCOVERABLE, 0); - setMode(dev_id, MgmtOpcode::SET_POWERED, 0); + AdapterSetting current_settings; + setMode(dev_id, MgmtCommand::Opcode::SET_SECURE_CONN, 0, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_BONDABLE, 0, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_CONNECTABLE, 0, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_FAST_CONNECTABLE, 0, current_settings); + setMode(dev_id, MgmtCommand::Opcode::SET_POWERED, 0, current_settings); } DBTManager::DBTManager(const BTMode _defaultBTMode) noexcept @@ -362,7 +369,7 @@ DBTManager::DBTManager(const BTMode _defaultBTMode) noexcept // Mandatory { - MgmtCommand req0(MgmtOpcode::READ_VERSION, MgmtConstU16::MGMT_INDEX_NONE); + MgmtCommand req0(MgmtCommand::Opcode::READ_VERSION, MgmtConstU16::MGMT_INDEX_NONE); std::shared_ptr<MgmtEvent> res = sendWithReply(req0); if( nullptr == res ) { goto fail; @@ -382,7 +389,7 @@ DBTManager::DBTManager(const BTMode _defaultBTMode) noexcept } // Optional { - MgmtCommand req0(MgmtOpcode::READ_COMMANDS, MgmtConstU16::MGMT_INDEX_NONE); + MgmtCommand req0(MgmtCommand::Opcode::READ_COMMANDS, MgmtConstU16::MGMT_INDEX_NONE); std::shared_ptr<MgmtEvent> res = sendWithReply(req0); if( nullptr == res ) { goto next1; @@ -396,7 +403,7 @@ DBTManager::DBTManager(const BTMode _defaultBTMode) noexcept const int expDataSize = 4 + num_commands * 2 + num_events * 2; if( res->getDataSize() >= expDataSize ) { for(int i=0; i< num_commands; i++) { - const MgmtOpcode op = static_cast<MgmtOpcode>( get_uint16(data, 4+i*2, true /* littleEndian */) ); + const MgmtCommand::Opcode op = static_cast<MgmtCommand::Opcode>( get_uint16(data, 4+i*2, true /* littleEndian */) ); DBG_PRINT("kernel op %d: %s", i, getMgmtOpcodeString(op).c_str()); } } @@ -407,7 +414,7 @@ DBTManager::DBTManager(const BTMode _defaultBTMode) noexcept next1: // Mandatory { - MgmtCommand req0(MgmtOpcode::READ_INDEX_LIST, MgmtConstU16::MGMT_INDEX_NONE); + MgmtCommand req0(MgmtCommand::Opcode::READ_INDEX_LIST, MgmtConstU16::MGMT_INDEX_NONE); std::shared_ptr<MgmtEvent> res = sendWithReply(req0); if( nullptr == res ) { goto fail; @@ -444,6 +451,7 @@ next1: } addMgmtEventCallback(-1, MgmtEvent::Opcode::NEW_SETTINGS, jau::bindMemberFunc(this, &DBTManager::mgmtEvNewSettingsCB)); + addMgmtEventCallback(-1, MgmtEvent::Opcode::CONTROLLER_ERROR, jau::bindMemberFunc(this, &DBTManager::mgmtEvControllerErrorCB)); if( env.DEBUG_EVENT ) { addMgmtEventCallback(-1, MgmtEvent::Opcode::CLASS_OF_DEV_CHANGED, jau::bindMemberFunc(this, &DBTManager::mgmtEvClassOfDeviceChangedCB)); @@ -640,19 +648,55 @@ int DBTManager::getDefaultAdapterDevID() const noexcept { return ai->dev_id; } -bool DBTManager::setMode(const uint16_t dev_id, const MgmtOpcode opc, const uint8_t mode) noexcept { +bool DBTManager::setMode(const uint16_t dev_id, const MgmtCommand::Opcode opc, const uint8_t mode, AdapterSetting& current_settings) noexcept { MgmtUint8Cmd req(opc, dev_id, mode); - std::shared_ptr<MgmtEvent> res = sendWithReply(req); - if( nullptr != res ) { - if( res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) { - const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get()); - return MgmtStatus::SUCCESS == res1.getStatus(); - } else if( res->getOpcode() == MgmtEvent::Opcode::CMD_STATUS ) { - const MgmtEvtCmdStatus &res1 = *static_cast<const MgmtEvtCmdStatus *>(res.get()); - return MgmtStatus::SUCCESS == res1.getStatus(); + std::shared_ptr<MgmtEvent> reply = sendWithReply(req); + MgmtStatus res; + if( nullptr != reply ) { + if( reply->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) { + const MgmtEvtCmdComplete &reply1 = *static_cast<const MgmtEvtCmdComplete *>(reply.get()); + res = reply1.getStatus(); + if( MgmtStatus::SUCCESS == res ) { + current_settings = reply1.getCurrentSettings(); + } + } else if( reply->getOpcode() == MgmtEvent::Opcode::CMD_STATUS ) { + const MgmtEvtCmdStatus &reply1 = *static_cast<const MgmtEvtCmdStatus *>(reply.get()); + res = reply1.getStatus(); + } else { + res = MgmtStatus::UNKNOWN_COMMAND; } + } else { + res = MgmtStatus::TIMEOUT; } - return false; + DBG_PRINT("DBTManager::setMode[%d, %s]: %s, result %s %s", dev_id, + MgmtCommand::getOpcodeString(opc).c_str(), jau::uint8HexString(mode).c_str(), + getMgmtStatusString(res).c_str(), getAdapterSettingMaskString(current_settings).c_str()); + return MgmtStatus::SUCCESS == res; +} + +MgmtStatus DBTManager::setDiscoverable(const uint16_t dev_id, const uint8_t state, const uint16_t timeout_sec, AdapterSetting& current_settings) noexcept { + MgmtSetDiscoverableCmd req(dev_id, state, timeout_sec); + std::shared_ptr<MgmtEvent> reply = sendWithReply(req); + MgmtStatus res; + if( nullptr != reply ) { + if( reply->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) { + const MgmtEvtCmdComplete &reply1 = *static_cast<const MgmtEvtCmdComplete *>(reply.get()); + res = reply1.getStatus(); + if( MgmtStatus::SUCCESS == res ) { + current_settings = reply1.getCurrentSettings(); + } + } else if( reply->getOpcode() == MgmtEvent::Opcode::CMD_STATUS ) { + const MgmtEvtCmdStatus &reply1 = *static_cast<const MgmtEvtCmdStatus *>(reply.get()); + res = reply1.getStatus(); + } else { + res = MgmtStatus::UNKNOWN_COMMAND; + } + } else { + res = MgmtStatus::TIMEOUT; + } + DBG_PRINT("DBTManager::setDiscoverable[%d]: %s, result %s %s", dev_id, + req.toString().c_str(), getMgmtStatusString(res).c_str(), getAdapterSettingMaskString(current_settings).c_str()); + return res; } ScanType DBTManager::startDiscovery(const uint16_t dev_id, const BTMode btMode) noexcept { @@ -660,7 +704,7 @@ ScanType DBTManager::startDiscovery(const uint16_t dev_id, const BTMode btMode) } ScanType DBTManager::startDiscovery(const uint16_t dev_id, const ScanType scanType) noexcept { - MgmtUint8Cmd req(MgmtOpcode::START_DISCOVERY, dev_id, number(scanType)); + MgmtUint8Cmd req(MgmtCommand::Opcode::START_DISCOVERY, dev_id, number(scanType)); std::shared_ptr<MgmtEvent> res = sendWithReply(req); ScanType type = ScanType::NONE; if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) { @@ -677,7 +721,7 @@ ScanType DBTManager::startDiscovery(const uint16_t dev_id, const ScanType scanTy return type; } bool DBTManager::stopDiscovery(const uint16_t dev_id, const ScanType type) noexcept { - MgmtUint8Cmd req(MgmtOpcode::STOP_DISCOVERY, dev_id, number(type)); + MgmtUint8Cmd req(MgmtCommand::Opcode::STOP_DISCOVERY, dev_id, number(type)); std::shared_ptr<MgmtEvent> res = sendWithReply(req); if( nullptr != res && res->getOpcode() == MgmtEvent::Opcode::CMD_COMPLETE ) { const MgmtEvtCmdComplete &res1 = *static_cast<const MgmtEvtCmdComplete *>(res.get()); @@ -949,6 +993,12 @@ bool DBTManager::mgmtEvNewSettingsCB(std::shared_ptr<MgmtEvent> e) noexcept { return true; } +bool DBTManager::mgmtEvControllerErrorCB(std::shared_ptr<MgmtEvent> e) noexcept { + DBG_PRINT("DBTManager:mgmt:ControllerError: %s", e->toString().c_str()); + (void)e; + return true; +} + bool DBTManager::mgmtEvClassOfDeviceChangedCB(std::shared_ptr<MgmtEvent> e) noexcept { DBG_PRINT("DBTManager:mgmt:ClassOfDeviceChanged: %s", e->toString().c_str()); (void)e; diff --git a/src/direct_bt/MgmtTypes.cpp b/src/direct_bt/MgmtTypes.cpp index 52bdf3b0..de6b1c08 100644 --- a/src/direct_bt/MgmtTypes.cpp +++ b/src/direct_bt/MgmtTypes.cpp @@ -163,11 +163,24 @@ std::string direct_bt::getMgmtStatusString(const MgmtStatus opc) noexcept { X(SET_APPEARANCE) \ X(GET_PHY_CONFIGURATION) \ X(SET_PHY_CONFIGURATION) \ - X(SET_BLOCKED_KEYS) - -#define MGMT_OPCODE_CASE_TO_STRING(V) case MgmtOpcode::V: return #V; - -std::string direct_bt::getMgmtOpcodeString(const MgmtOpcode op) noexcept { + X(SET_BLOCKED_KEYS) \ + X(SET_WIDEBAND_SPEECH) \ + X(READ_SECURITY_INFO) \ + X(READ_EXP_FEATURES_INFO) \ + X(SET_EXP_FEATURE) \ + X(READ_DEF_SYSTEM_CONFIG) \ + X(SET_DEF_SYSTEM_CONFIG) \ + X(READ_DEF_RUNTIME_CONFIG) \ + X(SET_DEF_RUNTIME_CONFIG) \ + X(GET_DEVICE_FLAGS) \ + X(SET_DEVICE_FLAGS) \ + X(READ_ADV_MONITOR_FEATURES) \ + X(ADD_ADV_PATTERNS_MONITOR) \ + X(REMOVE_ADV_MONITOR) + +#define MGMT_OPCODE_CASE_TO_STRING(V) case MgmtCommand::Opcode::V: return #V; + +std::string MgmtCommand::getOpcodeString(const Opcode op) noexcept { switch(op) { MGMT_OPCODE_ENUM(MGMT_OPCODE_CASE_TO_STRING) default: ; // fall through intended @@ -218,7 +231,11 @@ std::string direct_bt::getMgmtOpcodeString(const MgmtOpcode op) noexcept { X(ADVERTISING_ADDED) \ X(ADVERTISING_REMOVED) \ X(EXT_INFO_CHANGED) \ - X(PHY_CONFIGURATION_CHANGED) + X(PHY_CONFIGURATION_CHANGED) \ + X(EXP_FEATURE_CHANGED) \ + X(DEVICE_FLAGS_CHANGED) \ + X(ADV_MONITOR_ADDED) \ + X(ADV_MONITOR_REMOVED) #define MGMT_EV_OPCODE_CASE_TO_STRING(V) case MgmtEvent::Opcode::V: return #V; @@ -236,7 +253,7 @@ std::shared_ptr<MgmtEvent> MgmtEvent::getSpecialized(const uint8_t * buffer, jau switch( opc ) { case MgmtEvent::Opcode::CMD_COMPLETE: if( buffer_size >= MgmtEvtAdapterInfo::getRequiredTotalSize() && - MgmtOpcode::READ_INFO == MgmtEvtCmdComplete::getReqOpcode(buffer) ) { + MgmtCommand::Opcode::READ_INFO == MgmtEvtCmdComplete::getCmdOpcode(buffer) ) { res = new MgmtEvtAdapterInfo(buffer, buffer_size); } else { res = new MgmtEvtCmdComplete(buffer, buffer_size); @@ -244,35 +261,36 @@ std::shared_ptr<MgmtEvent> MgmtEvent::getSpecialized(const uint8_t * buffer, jau break; case MgmtEvent::Opcode::CMD_STATUS: res = new MgmtEvtCmdStatus(buffer, buffer_size); break; - case MgmtEvent::Opcode::DISCOVERING: - res = new MgmtEvtDiscovering(buffer, buffer_size); break; + case MgmtEvent::Opcode::CONTROLLER_ERROR: + res = new MgmtEvtControllerError(buffer, buffer_size); break; + case MgmtEvent::Opcode::INDEX_ADDED: + res = new MgmtEvent(buffer, buffer_size, 0); break; + case MgmtEvent::Opcode::INDEX_REMOVED: + res = new MgmtEvent(buffer, buffer_size, 0); break; case MgmtEvent::Opcode::NEW_SETTINGS: res = new MgmtEvtNewSettings(buffer, buffer_size); break; - case MgmtEvent::Opcode::NEW_CONN_PARAM: - res = new MgmtEvtNewConnectionParam(buffer, buffer_size); break; - case MgmtEvent::Opcode::DEVICE_FOUND: - res = new MgmtEvtDeviceFound(buffer, buffer_size); break; + case MgmtEvent::Opcode::LOCAL_NAME_CHANGED: + res = new MgmtEvtLocalNameChanged(buffer, buffer_size); break; case MgmtEvent::Opcode::DEVICE_CONNECTED: res = new MgmtEvtDeviceConnected(buffer, buffer_size); break; - case MgmtEvent::Opcode::CONNECT_FAILED: - res = new MgmtEvtDeviceConnectFailed(buffer, buffer_size); break; case MgmtEvent::Opcode::DEVICE_DISCONNECTED: res = new MgmtEvtDeviceDisconnected(buffer, buffer_size); break; + case MgmtEvent::Opcode::CONNECT_FAILED: + res = new MgmtEvtDeviceConnectFailed(buffer, buffer_size); break; case MgmtEvent::Opcode::PIN_CODE_REQUEST: res = new MgmtEvtPinCodeRequest(buffer, buffer_size); break; + case MgmtEvent::Opcode::DEVICE_FOUND: + res = new MgmtEvtDeviceFound(buffer, buffer_size); break; + case MgmtEvent::Opcode::DISCOVERING: + res = new MgmtEvtDiscovering(buffer, buffer_size); break; + case MgmtEvent::Opcode::DEVICE_UNPAIRED: + res = new MgmtEvtDeviceUnpaired(buffer, buffer_size); break; case MgmtEvent::Opcode::DEVICE_WHITELIST_ADDED: res = new MgmtEvtDeviceWhitelistAdded(buffer, buffer_size); break; case MgmtEvent::Opcode::DEVICE_WHITELIST_REMOVED: res = new MgmtEvtDeviceWhitelistRemoved(buffer, buffer_size); break; - case MgmtEvent::Opcode::DEVICE_UNPAIRED: - res = new MgmtEvtDeviceUnpaired(buffer, buffer_size); break; - case MgmtEvent::Opcode::LOCAL_NAME_CHANGED: - res = new MgmtEvtLocalNameChanged(buffer, buffer_size); - break; - case MgmtEvent::Opcode::INDEX_ADDED: - [[fallthrough]]; - case MgmtEvent::Opcode::INDEX_REMOVED: - [[fallthrough]]; + case MgmtEvent::Opcode::NEW_CONN_PARAM: + res = new MgmtEvtNewConnectionParam(buffer, buffer_size); break; default: res = new MgmtEvent(buffer, buffer_size, 0); break; } @@ -283,8 +301,49 @@ std::shared_ptr<MgmtEvent> MgmtEvent::getSpecialized(const uint8_t * buffer, jau // ************************************************* // ************************************************* +AdapterSetting MgmtEvtCmdComplete::getCurrentSettings() const noexcept { + if( 4 != getDataSize() ) { + return AdapterSetting::NONE; + } + MgmtCommand::Opcode cmd = getCmdOpcode(); + switch(cmd) { + case MgmtCommand::Opcode::SET_POWERED: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_DISCOVERABLE: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_CONNECTABLE: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_FAST_CONNECTABLE: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_BONDABLE: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_LINK_SECURITY: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_SSP: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_HS: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_LE: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_ADVERTISING: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_BREDR: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_STATIC_ADDRESS: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_SECURE_CONN: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_DEBUG_KEYS: + [[fallthrough]]; + case MgmtCommand::Opcode::SET_PRIVACY: + return static_cast<AdapterSetting>( pdu.get_uint32_nc(getDataOffset()) ); + default: + return AdapterSetting::NONE; + } +} + std::shared_ptr<ConnectionInfo> MgmtEvtCmdComplete::toConnectionInfo() const noexcept { - if( MgmtOpcode::GET_CONN_INFO != getReqOpcode() ) { + if( MgmtCommand::Opcode::GET_CONN_INFO != getCmdOpcode() ) { ERR_PRINT("Not a GET_CONN_INFO reply: %s", toString().c_str()); return nullptr; } @@ -308,7 +367,7 @@ std::shared_ptr<ConnectionInfo> MgmtEvtCmdComplete::toConnectionInfo() const noe } std::shared_ptr<NameAndShortName> MgmtEvtCmdComplete::toNameAndShortName() const noexcept { - if( MgmtOpcode::SET_LOCAL_NAME != getReqOpcode() ) { + if( MgmtCommand::Opcode::SET_LOCAL_NAME != getCmdOpcode() ) { ERR_PRINT("Not a SET_LOCAL_NAME reply: %s", toString().c_str()); return nullptr; } diff --git a/src/direct_bt/SMPHandler.cpp b/src/direct_bt/SMPHandler.cpp index 86dab20d..89158d5f 100644 --- a/src/direct_bt/SMPHandler.cpp +++ b/src/direct_bt/SMPHandler.cpp @@ -65,11 +65,10 @@ SMPEnv::SMPEnv() noexcept { } -#ifdef __linux__ - // Linux/BlueZ prohibits access to the existing SMP implementation via L2CAP (socket). - bool SMPHandler::IS_SUPPORTED_BY_OS = false; -#else +#if SMP_SUPPORTED_BY_OS bool SMPHandler::IS_SUPPORTED_BY_OS = true; +#else + bool SMPHandler::IS_SUPPORTED_BY_OS = false; #endif std::shared_ptr<DBTDevice> SMPHandler::getDeviceChecked() const { |