summaryrefslogtreecommitdiffstats
path: root/src/detection/bluetoothradio/bluetoothradio_windows.c
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/bluetoothradio/bluetoothradio_windows.c
Add the files
Diffstat (limited to 'src/detection/bluetoothradio/bluetoothradio_windows.c')
-rw-r--r--src/detection/bluetoothradio/bluetoothradio_windows.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/detection/bluetoothradio/bluetoothradio_windows.c b/src/detection/bluetoothradio/bluetoothradio_windows.c
new file mode 100644
index 0000000..f0b55d4
--- /dev/null
+++ b/src/detection/bluetoothradio/bluetoothradio_windows.c
@@ -0,0 +1,99 @@
+#include "bluetoothradio.h"
+#include "common/library.h"
+#include "common/io.h"
+#include "common/windows/unicode.h"
+
+#include <windows.h>
+#include <bluetoothapis.h>
+#include <winioctl.h>
+
+// #include <bthioctl.h>
+
+#define BTH_IOCTL_BASE 0
+#define BTH_CTL(id) CTL_CODE(FILE_DEVICE_BLUETOOTH, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_BTH_GET_LOCAL_INFO BTH_CTL(BTH_IOCTL_BASE + 0x00)
+#define LMP_LE_SUPPORTED(x) ((x >> 38) & 1)
+
+typedef struct _BTH_RADIO_INFO {
+ // Supported LMP features of the radio. Use LMP_XXX() to extract
+ // the desired bits.
+ ULONGLONG lmpSupportedFeatures;
+
+ // Manufacturer ID (possibly BTH_MFG_XXX)
+ USHORT mfg;
+
+ // LMP subversion
+ USHORT lmpSubversion;
+
+ // LMP version
+ UCHAR lmpVersion;
+} FF_A_PACKED BTH_RADIO_INFO;
+
+typedef struct _BTH_LOCAL_RADIO_INFO {
+ // Local BTH_ADDR, class of device, and radio name
+ BTH_DEVICE_INFO localInfo;
+
+ // Combo of LOCAL_RADIO_XXX values
+ ULONG flags;
+
+ // HCI revision, see core spec
+ USHORT hciRevision;
+
+ // HCI version, see core spec
+ UCHAR hciVersion;
+
+ // More information about the local radio (LMP, MFG)
+ BTH_RADIO_INFO radioInfo;
+} FF_A_PACKED BTH_LOCAL_RADIO_INFO;
+static_assert(sizeof(BTH_LOCAL_RADIO_INFO) == 292, "BTH_LOCAL_RADIO_INFO should be 292 bytes");
+
+#pragma GCC diagnostic ignored "-Wpointer-sign"
+
+const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */) {
+ // Actually bluetoothapis.dll, but it's missing on Windows 7
+ FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bluetoothapis.dll", 1)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstRadio)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindNextRadio)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindRadioClose)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothIsConnectable)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothIsDiscoverable)
+
+ HANDLE hRadio = NULL;
+ HBLUETOOTH_DEVICE_FIND hFind = ffBluetoothFindFirstRadio(&(BLUETOOTH_FIND_RADIO_PARAMS) {
+ .dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS) },
+ &hRadio);
+ if (!hFind) {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS) {
+ return "No Bluetooth radios found or service disabled";
+ } else {
+ return "BluetoothFindFirstRadio() failed";
+ }
+ }
+
+ do {
+ BTH_LOCAL_RADIO_INFO blri;
+ DWORD returned;
+ if (!DeviceIoControl(hRadio, IOCTL_BTH_GET_LOCAL_INFO, NULL, 0, &blri, sizeof(blri), &returned, NULL)) {
+ continue;
+ }
+
+ FFBluetoothRadioResult* device = FF_LIST_ADD(FFBluetoothRadioResult, *devices);
+ ffStrbufInitS(&device->name, blri.localInfo.name);
+
+ BLUETOOTH_ADDRESS_STRUCT addr = { .ullLong = blri.localInfo.address };
+ ffStrbufInitF(&device->address, "%02X:%02X:%02X:%02X:%02X:%02X", addr.rgBytes[5], addr.rgBytes[4], addr.rgBytes[3], addr.rgBytes[2], addr.rgBytes[1], addr.rgBytes[0]);
+
+ device->lmpVersion = blri.radioInfo.lmpVersion;
+ device->lmpSubversion = blri.radioInfo.lmpSubversion;
+ ffStrbufInitStatic(&device->vendor, ffBluetoothRadioGetVendor(blri.radioInfo.mfg));
+ device->enabled = true;
+ device->connectable = ffBluetoothIsConnectable(hRadio);
+ device->discoverable = ffBluetoothIsDiscoverable(hRadio);
+
+ NtClose(hRadio);
+ } while (ffBluetoothFindNextRadio(hFind, &hRadio));
+
+ ffBluetoothFindRadioClose(hFind);
+
+ return NULL;
+}