summaryrefslogtreecommitdiffstats
path: root/src/detection/bluetoothradio/bluetoothradio_apple.m
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_apple.m
Add the files
Diffstat (limited to 'src/detection/bluetoothradio/bluetoothradio_apple.m')
-rw-r--r--src/detection/bluetoothradio/bluetoothradio_apple.m69
1 files changed, 69 insertions, 0 deletions
diff --git a/src/detection/bluetoothradio/bluetoothradio_apple.m b/src/detection/bluetoothradio/bluetoothradio_apple.m
new file mode 100644
index 0000000..c5154ab
--- /dev/null
+++ b/src/detection/bluetoothradio/bluetoothradio_apple.m
@@ -0,0 +1,69 @@
+#include "bluetoothradio.h"
+#include "common/processing.h"
+
+#import <IOBluetooth/IOBluetooth.h>
+
+// For some reason the official declaration of IOBluetoothHostController doesn't include property `controllers`
+@interface IOBluetoothHostController()
++ (id)controllers;
+@end
+
+const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
+{
+ NSArray<IOBluetoothHostController*>* ctrls = IOBluetoothHostController.controllers;
+ if(!ctrls)
+ return "IOBluetoothHostController.controllers returns nil";
+
+ FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
+ if (ffProcessAppendStdOut(&buffer, (char* const[]) {
+ "system_profiler",
+ "SPBluetoothDataType",
+ "-xml",
+ "-detailLevel",
+ "basic",
+ NULL
+ }) != NULL)
+ return "Starting `system_profiler SPBluetoothDataType -xml -detailLevel basic` failed";
+
+ NSArray* arr = [NSPropertyListSerialization propertyListWithData:[NSData dataWithBytes:buffer.chars length:buffer.length]
+ options:NSPropertyListImmutable
+ format:nil
+ error:nil];
+ if (!arr || !arr.count)
+ return "system_profiler SPBluetoothDataType returned an empty array";
+
+ for (IOBluetoothHostController* ctrl in ctrls)
+ {
+ FFBluetoothRadioResult* device = FF_LIST_ADD(FFBluetoothRadioResult, *devices);
+ ffStrbufInitS(&device->name, ctrl.nameAsString.UTF8String);
+ ffStrbufInitS(&device->address, ctrl.addressAsString.UTF8String);
+ ffStrbufInitStatic(&device->vendor, "Apple");
+ device->lmpVersion = INT_MIN;
+ device->lmpSubversion = INT_MIN;
+ device->enabled = ctrl.powerState == kBluetoothHCIPowerStateON;
+ device->discoverable = false;
+ device->connectable = true;
+
+ for (NSDictionary* itemDict in arr[0][@"_items"])
+ {
+ NSDictionary* props = itemDict[@"controller_properties"];
+ if (!props) continue;
+
+ if (![ctrl.addressAsString isEqualToString:props[@"controller_address"]]) continue;
+
+ NSString* services = props[@"controller_supportedServices"];
+ if ([services containsString:@" LEA "])
+ device->lmpVersion = -11;
+ else if ([services containsString:@" GATT "])
+ device->lmpVersion = -6;
+
+ device->discoverable = ![props[@"controller_discoverable"] isEqualToString:@"attrib_off"];
+ ffStrbufSetS(&device->vendor, ((NSString*) props[@"controller_vendorID"]).UTF8String);
+ ffStrbufSubstrAfterFirstC(&device->vendor, '(');
+ ffStrbufTrimRight(&device->vendor, ')');
+ break;
+ }
+ }
+
+ return NULL;
+}