bluetooth: Implement EIR parsing for HCI_EVENT_EXTENDED_INQUIRY_EVENT

This parses only EIR_NAME_SHORT and EIR_NAME_COMPLETE, others are not
yet usefull, adds a way to fetch the cached friendly name and adds a
friendlyName field to RemoteDevice. Refactors DeviceListItem to work on
RemoteDevice as it's only being used for that.Also adds a check if the
cached name is complete or not. If not ask for the complete name.

Change-Id: I7e37fb9cf44cb5598ef348fdd4d781c5ae04e24e
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10489
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
vighnesh-sawant
2026-03-16 12:19:26 +00:00
committed by waddlesplash
parent ee10ca4b42
commit e7eb60f1a7
11 changed files with 116 additions and 26 deletions
+1 -1
View File
@@ -162,7 +162,7 @@ SYSTEM_SERVERS += [ FFilterByBuildFeatures
# Bluetooth stack + drivers # Bluetooth stack + drivers
SYSTEM_NETWORK_PROTOCOLS += SYSTEM_NETWORK_PROTOCOLS +=
# l2cap l2cap
; ;
SYSTEM_BT_STACK = SYSTEM_BT_STACK =
hci hci
+4 -1
View File
@@ -276,6 +276,7 @@ struct hci_ev_sychronous_connection_changed {
// TODO: Define remaining Bluetooth 2.1 events structures // TODO: Define remaining Bluetooth 2.1 events structures
#define HCI_EVENT_EXTENDED_INQUIRY_RESULT 0x2F #define HCI_EVENT_EXTENDED_INQUIRY_RESULT 0x2F
#define HCI_MAX_EIR_LENGTH 240
struct hci_ev_extended_inquiry_info { struct hci_ev_extended_inquiry_info {
bdaddr_t bdaddr; bdaddr_t bdaddr;
uint8 page_repetition_mode; uint8 page_repetition_mode;
@@ -283,8 +284,10 @@ struct hci_ev_extended_inquiry_info {
uint8 dev_class[3]; uint8 dev_class[3];
uint16 clock_offset; uint16 clock_offset;
int8 rssi; int8 rssi;
uint8 eir[240]; uint8 eir[HCI_MAX_EIR_LENGTH];
} __attribute__((packed)); } __attribute__((packed));
#define EIR_NAME_SHORT 0x08
#define EIR_NAME_COMPLETE 0x09
#define HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE 0x30 #define HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE 0x30
+3
View File
@@ -31,6 +31,7 @@ public:
bool IsTrustedDevice(); bool IsTrustedDevice();
BString GetFriendlyName(bool alwaysAsk); /* Throwing */ BString GetFriendlyName(bool alwaysAsk); /* Throwing */
BString GetFriendlyName(void); /* Throwing */ BString GetFriendlyName(void); /* Throwing */
BString GetCachedFriendlyName();
bdaddr_t GetBluetoothAddress(); bdaddr_t GetBluetoothAddress();
DeviceClass GetDeviceClass(); DeviceClass GetDeviceClass();
@@ -69,6 +70,8 @@ private:
uint8 fScanMode; uint8 fScanMode;
uint16 fClockOffset; uint16 fClockOffset;
int8 fRSSI; int8 fRSSI;
BString fFriendlyName;
bool fFriendlyNameIsComplete;
}; };
} }
+12
View File
@@ -88,6 +88,9 @@ DiscoveryListener::MessageReceived(BMessage* message)
uint8 scanMode = 0; uint8 scanMode = 0;
uint16 clockOffset = 0; uint16 clockOffset = 0;
int8 rssi = HCI_RSSI_INVALID; int8 rssi = HCI_RSSI_INVALID;
BString friendlyName;
bool friendlyNameIsComplete = false;
if (message->FindData("bdaddr", B_ANY_TYPE, i, (const void**)&bdaddr, &size) != B_OK if (message->FindData("bdaddr", B_ANY_TYPE, i, (const void**)&bdaddr, &size) != B_OK
|| message->FindData("dev_class", B_ANY_TYPE, i, (const void**)&devClass, &size) || message->FindData("dev_class", B_ANY_TYPE, i, (const void**)&devClass, &size)
@@ -102,6 +105,9 @@ DiscoveryListener::MessageReceived(BMessage* message)
message->FindUInt8("scan_mode", i, &scanMode); message->FindUInt8("scan_mode", i, &scanMode);
message->FindUInt16("clock_offset", i, &clockOffset); message->FindUInt16("clock_offset", i, &clockOffset);
message->FindInt8("rssi", i, &rssi); message->FindInt8("rssi", i, &rssi);
message->FindBool("friendly_name_is_complete", &friendlyNameIsComplete);
message->FindString("friendly_name", i, &friendlyName);
// Skip duplicated replies // Skip duplicated replies
bool duplicatedFound = false; bool duplicatedFound = false;
@@ -115,6 +121,10 @@ DiscoveryListener::MessageReceived(BMessage* message)
existingDevice->fScanMode = scanMode; existingDevice->fScanMode = scanMode;
existingDevice->fClockOffset = clockOffset; existingDevice->fClockOffset = clockOffset;
existingDevice->fRSSI = rssi; existingDevice->fRSSI = rssi;
if (!existingDevice->fFriendlyNameIsComplete && !friendlyName.IsEmpty()) {
existingDevice->fFriendlyNameIsComplete = friendlyNameIsComplete;
existingDevice->fFriendlyName = friendlyName;
}
duplicatedFound = true; duplicatedFound = true;
break; break;
} }
@@ -130,6 +140,8 @@ DiscoveryListener::MessageReceived(BMessage* message)
rd->fScanMode = scanMode; rd->fScanMode = scanMode;
rd->fClockOffset = clockOffset; rd->fClockOffset = clockOffset;
rd->fRSSI = rssi; rd->fRSSI = rssi;
rd->fFriendlyNameIsComplete = friendlyNameIsComplete;
rd->fFriendlyName = friendlyName;
DeviceDiscovered(rd, rd->GetDeviceClass()); DeviceDiscovered(rd, rd->GetDeviceClass());
} }
} }
+16 -4
View File
@@ -50,9 +50,8 @@ RemoteDevice::GetFriendlyName(bool alwaysAsk)
{ {
CALLED(); CALLED();
if (!alwaysAsk) { if (!alwaysAsk) {
// Check if the name is already retrieved if (!fFriendlyName.IsEmpty() && fFriendlyNameIsComplete)
// TODO: Check if It is known from a KnownDevicesList return fFriendlyName;
return BString(B_TRANSLATE("Not implemented"));
} }
if (fDiscovererLocalDevice == NULL) if (fDiscovererLocalDevice == NULL)
@@ -90,6 +89,8 @@ RemoteDevice::GetFriendlyName(bool alwaysAsk)
if ((reply.FindInt8("status", &status) == B_OK) && (status == BT_OK)) { if ((reply.FindInt8("status", &status) == B_OK) && (status == BT_OK)) {
if ((reply.FindString("friendlyname", &name) == B_OK )) { if ((reply.FindString("friendlyname", &name) == B_OK )) {
fFriendlyName = name;
fFriendlyNameIsComplete = true;
return name; return name;
} else { } else {
return BString(""); // should not happen return BString(""); // should not happen
@@ -97,6 +98,9 @@ RemoteDevice::GetFriendlyName(bool alwaysAsk)
} else { } else {
// seems we got a negative event // seems we got a negative event
if (!fFriendlyName.IsEmpty())
return fFriendlyName;
return BString(B_TRANSLATE("#CommandFailed#Not Valid name")); return BString(B_TRANSLATE("#CommandFailed#Not Valid name"));
} }
} }
@@ -109,7 +113,15 @@ BString
RemoteDevice::GetFriendlyName() RemoteDevice::GetFriendlyName()
{ {
CALLED(); CALLED();
return GetFriendlyName(true); return GetFriendlyName(false);
}
BString
RemoteDevice::GetCachedFriendlyName()
{
CALLED();
return fFriendlyName;
} }
+10 -5
View File
@@ -16,19 +16,24 @@
namespace Bluetooth { namespace Bluetooth {
DeviceListItem::DeviceListItem(BluetoothDevice* bDevice)
DeviceListItem::DeviceListItem(RemoteDevice* bDevice)
: :
BListItem(), BListItem(),
fDevice(bDevice), fDevice(bDevice)
fName("unknown")
{ {
fAddress = bDevice->GetBluetoothAddress(); fAddress = bDevice->GetBluetoothAddress();
fClass = bDevice->GetDeviceClass(); fClass = bDevice->GetDeviceClass();
// we always use the cached name here as we dont want to fire a query in the middle of an
// INQUIRY
fName = bDevice->GetCachedFriendlyName();
if (fName.IsEmpty())
fName = "unknown";
} }
void void
DeviceListItem::SetDevice(BluetoothDevice* bDevice) DeviceListItem::SetDevice(RemoteDevice* bDevice)
{ {
fAddress = bDevice->GetBluetoothAddress(); fAddress = bDevice->GetBluetoothAddress();
fClass = bDevice->GetDeviceClass(); fClass = bDevice->GetDeviceClass();
@@ -146,7 +151,7 @@ DeviceListItem::Compare(const void *firstArg, const void *secondArg)
} }
BluetoothDevice* RemoteDevice*
DeviceListItem::Device() const DeviceListItem::Device() const
{ {
return fDevice; return fDevice;
+5 -6
View File
@@ -8,15 +8,14 @@
#include <ListItem.h> #include <ListItem.h>
#include <String.h> #include <String.h>
#include <bluetooth/bluetooth.h> #include "bluetooth/RemoteDevice.h"
#include <bluetooth/DeviceClass.h>
namespace Bluetooth { namespace Bluetooth {
class DeviceListItem : public BListItem class DeviceListItem : public BListItem
{ {
public: public:
DeviceListItem(BluetoothDevice* bDevice); DeviceListItem(RemoteDevice* bDevice);
~DeviceListItem(); ~DeviceListItem();
@@ -24,11 +23,11 @@ class DeviceListItem : public BListItem
void Update(BView* owner, const BFont* font); void Update(BView* owner, const BFont* font);
static int Compare(const void* firstArg, const void* secondArg); static int Compare(const void* firstArg, const void* secondArg);
void SetDevice(BluetoothDevice* bDevice); void SetDevice(RemoteDevice* bDevice);
BluetoothDevice* Device() const; RemoteDevice* Device() const;
private: private:
BluetoothDevice* fDevice; RemoteDevice* fDevice;
bdaddr_t fAddress; bdaddr_t fAddress;
DeviceClass fClass; DeviceClass fClass;
BString fName; BString fName;
+1 -2
View File
@@ -283,8 +283,7 @@ InquiryPanel::MessageReceived(BMessage* message)
// Really erally expensive operation should be done in a separate thread // Really erally expensive operation should be done in a separate thread
// once Haiku gets a BarberPole in API replacing the progress bar // once Haiku gets a BarberPole in API replacing the progress bar
((DeviceListItem*)fRemoteList->ItemAt(retrievalIndex)) ((DeviceListItem*)fRemoteList->ItemAt(retrievalIndex))
->SetDevice((BluetoothDevice*) fDiscoveryAgent ->SetDevice(fDiscoveryAgent->RetrieveDevices(0).ItemAt(retrievalIndex));
->RetrieveDevices(0).ItemAt(retrievalIndex));
fRemoteList->InvalidateItem(retrievalIndex); fRemoteList->InvalidateItem(retrievalIndex);
retrievalIndex++; retrievalIndex++;
@@ -57,13 +57,14 @@ RemoteDevicesView::RemoteDevicesView(const char* name, uint32 flags)
disconnectButton = new BButton("disconnect", B_TRANSLATE("Disconnect"), disconnectButton = new BButton("disconnect", B_TRANSLATE("Disconnect"),
new BMessage(kMsgDisconnectDevice)); new BMessage(kMsgDisconnectDevice));
/* /*
blockButton = new BButton("block", B_TRANSLATE("As blocked"), blockButton = new BButton("block", B_TRANSLATE("As blocked"),
new BMessage(kMsgBlockDevice)); new BMessage(kMsgBlockDevice));
availButton = new BButton("check", B_TRANSLATE("Refresh" B_UTF8_ELLIPSIS), //TODO:Here use GetFriendlyName(true)
new BMessage(kMsgRefreshDevices)); availButton = new BButton("check", B_TRANSLATE("Refresh" B_UTF8_ELLIPSIS),
*/ new BMessage(kMsgRefreshDevices));
*/
// Set up device list // Set up device list
fDeviceList = new BListView("DeviceList", B_SINGLE_SELECTION_LIST); fDeviceList = new BListView("DeviceList", B_SINGLE_SELECTION_LIST);
+56 -1
View File
@@ -890,7 +890,8 @@ LocalDeviceImpl::ExtendedInquiryResult(uint8* numberOfResponses, BMessage* reque
reply.AddUInt16("clock_offset", info->clock_offset); reply.AddUInt16("clock_offset", info->clock_offset);
reply.AddInt8("rssi", info->rssi); reply.AddInt8("rssi", info->rssi);
// need to implement eir parsing ParseEIR(info->eir, reply);
printf("%s: Sending reply...\n", __func__); printf("%s: Sending reply...\n", __func__);
status_t status = request->SendReply(&reply); status_t status = request->SendReply(&reply);
if (status < B_OK) if (status < B_OK)
@@ -898,6 +899,60 @@ LocalDeviceImpl::ExtendedInquiryResult(uint8* numberOfResponses, BMessage* reque
} }
void
LocalDeviceImpl::ParseEIR(const uint8* eir, BMessage& reply)
{
if (eir == NULL)
return;
int offset = 0;
BString completeName;
BString shortName;
while (offset < HCI_MAX_EIR_LENGTH) {
uint8 length = eir[offset];
// break either when finished reading buffer or when next data value is zero
if (length == 0 || offset + length >= HCI_MAX_EIR_LENGTH)
break;
uint8 type = eir[offset + 1];
const uint8* data = &eir[offset + 2];
uint8 dataLen = length - 1;
// TODO:Implement other EIR datatypes
switch (type) {
case EIR_NAME_SHORT:
if (shortName.Length() == 0) {
shortName.SetTo((const char*)data, dataLen);
TRACE_BT("LocalDeviceImpl: Parsed EIR Short Name: '%s'\n", shortName.String());
}
break;
case EIR_NAME_COMPLETE:
if (completeName.Length() == 0) {
completeName.SetTo((const char*)data, dataLen);
TRACE_BT("LocalDeviceImpl: Parsed EIR Complete Name: '%s'\n",
completeName.String());
}
break;
default:
TRACE_BT("LocalDeviceImpl: Ignored EIR Type: 0x%02X (Length: %d)\n", type, dataLen);
break;
}
offset += length + 1;
}
if (completeName.Length() > 0) {
reply.AddString("friendly_name", completeName.String());
reply.AddBool("friendly_name_is_complete", true);
} else if (shortName.Length() > 0) {
reply.AddString("friendly_name", shortName.String());
reply.AddBool("friendly_name_is_complete", false);
}
}
void void
LocalDeviceImpl::InquiryComplete(uint8* status, BMessage* request) LocalDeviceImpl::InquiryComplete(uint8* status, BMessage* request)
{ {
+1
View File
@@ -50,6 +50,7 @@ private:
void InquiryResult(uint8* numberOfResponses, BMessage* request); void InquiryResult(uint8* numberOfResponses, BMessage* request);
void InquiryResultWithRSSI(uint8* numberOfResponses, BMessage* request); void InquiryResultWithRSSI(uint8* numberOfResponses, BMessage* request);
void ExtendedInquiryResult(uint8* numberOfResponses, BMessage* request); void ExtendedInquiryResult(uint8* numberOfResponses, BMessage* request);
void ParseEIR(const uint8* eir, BMessage& reply);
void InquiryComplete(uint8* status, BMessage* request); void InquiryComplete(uint8* status, BMessage* request);
void RemoteNameRequestComplete(struct hci_ev_remote_name_request_complete_reply* void RemoteNameRequestComplete(struct hci_ev_remote_name_request_complete_reply*
remotename, BMessage* request); remotename, BMessage* request);