Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix LE devices not working on Ventura #446

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 105 additions & 6 deletions IntelBTPatcher/IntelBTPatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ static KernelPatcher::KextInfo IntelBTPatcher_IOUsbHostInfo {
KernelPatcher::KextInfo::Unloaded
};

void *CIntelBTPatcher::_hookPipeInstance = nullptr;
AsyncOwnerData *CIntelBTPatcher::_interruptPipeAsyncOwner = nullptr;
bool CIntelBTPatcher::_randomAddressInit = false;

bool CIntelBTPatcher::init()
Expand Down Expand Up @@ -128,6 +130,32 @@ void CIntelBTPatcher::processKext(KernelPatcher &patcher, size_t index, mach_vm_
SYSLOG(DRV_NAME, "failed to resolve %s, error = %d", hostDeviceRequest.symbol, patcher.getError());
patcher.clearError();
}

KernelPatcher::RouteRequest asyncIORequest {
"__ZN13IOUSBHostPipe2ioEP18IOMemoryDescriptorjP19IOUSBHostCompletionj",
newAsyncIO,
oldAsyncIO
};
patcher.routeMultiple(index, &asyncIORequest, 1, address, size);
if (patcher.getError() == KernelPatcher::Error::NoError) {
SYSLOG(DRV_NAME, "routed %s", asyncIORequest.symbol);
} else {
SYSLOG(DRV_NAME, "failed to resolve %s, error = %d", asyncIORequest.symbol, patcher.getError());
patcher.clearError();
}

KernelPatcher::RouteRequest initPipeRequest {
"__ZN13IOUSBHostPipe28initWithDescriptorsAndOwnersEPKN11StandardUSB18EndpointDescriptorEPKNS0_37SuperSpeedEndpointCompanionDescriptorEP22AppleUSBHostControllerP15IOUSBHostDeviceP18IOUSBHostInterfaceht",
newInitPipe,
oldInitPipe
};
patcher.routeMultiple(index, &initPipeRequest, 1, address, size);
if (patcher.getError() == KernelPatcher::Error::NoError) {
SYSLOG(DRV_NAME, "routed %s", initPipeRequest.symbol);
} else {
SYSLOG(DRV_NAME, "failed to resolve %s, error = %d", initPipeRequest.symbol, patcher.getError());
patcher.clearError();
}
}
}
}
Expand All @@ -153,10 +181,11 @@ StandardUSB::DeviceRequest randomAddressRequest;
const uint8_t randomAddressHci[9] = {0x05, 0x20, 0x06, 0x94, 0x50, 0x64, 0xD0, 0x78, 0x6B};
IOBufferMemoryDescriptor *writeHCIDescriptor = nullptr;

#define MAX_HCI_BUF_LEN 255
#define HCI_OP_RESET 0x0c03
#define HCI_OP_LE_SET_SCAN_PARAM 0x200B
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200C
#define MAX_HCI_BUF_LEN 255
#define HCI_OP_RESET 0x0c03
#define HCI_OP_LE_SET_SCAN_PARAM 0x200B
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200C
#define HCI_OP_LE_READ_REMOTE_FEATURES 0x2016

IOReturn CIntelBTPatcher::newHostDeviceRequest(void *that, IOService *provider, StandardUSB::DeviceRequest &request, void *data, IOMemoryDescriptor *descriptor, unsigned int &length, IOUSBHostCompletion *completion, unsigned int timeout)
{
Expand Down Expand Up @@ -185,12 +214,15 @@ IOReturn CIntelBTPatcher::newHostDeviceRequest(void *that, IOService *provider,
writeHCIDescriptor->complete();
const char *randAddressDump = _hexDumpHCIData((uint8_t *)randomAddressHci, 9);
if (randAddressDump) {
SYSLOG(DRV_NAME, "[PATCH] Sending Random Address HCI %lld %s", ret, randAddressDump);
SYSLOG(DRV_NAME, "[PATCH] Sending Random Address HCI %d %s", ret, randAddressDump);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix build warning

IOFree((void *)randAddressDump, 9 * 3 + 1);
}
_randomAddressInit = true;
SYSLOG(DRV_NAME, "[PATCH] Resend LE SCAN PARAM HCI %lld", ret);
SYSLOG(DRV_NAME, "[PATCH] Resend LE SCAN PARAM HCI %d", ret);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix build warning

}
} else if (hdr->opcode == HCI_OP_LE_READ_REMOTE_FEATURES) {
IOReturn ret = FunctionCast(newHostDeviceRequest, callbackIBTPatcher->oldHostDeviceRequest)(that, provider, request, nullptr, descriptor, length, nullptr, timeout);
SYSLOG(DRV_NAME, "[PATCH] Sending extra LE Read Remote Features command %d", ret);
}
} else {
hdr = (HciCommandHdr *)data;
Expand All @@ -213,3 +245,70 @@ IOReturn CIntelBTPatcher::newHostDeviceRequest(void *that, IOService *provider,
}
return FunctionCast(newHostDeviceRequest, callbackIBTPatcher->oldHostDeviceRequest)(that, provider, request, data, descriptor, length, completion, timeout);
}

#define HCI_EVT_LE_META 0x3E
#define HCI_EVT_LE_META_READ_REMOTE_FEATURES_COMPLETE 0x04

uint8_t fakePhyUpdateCompleteEvent[8] = {0x3E, 0x06, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x02};

static void asyncIOCompletion(void* owner, void* parameter, IOReturn status, uint32_t bytesTransferred)
{
AsyncOwnerData *asyncOwner = (AsyncOwnerData *)owner;
IOMemoryDescriptor* dataBuffer = asyncOwner->dataBuffer;
static bool skipExtraReadRemoteFeaturesComplete = true;

if (dataBuffer && bytesTransferred) {
void *buffer = IOMalloc(bytesTransferred);
dataBuffer->readBytes(0, buffer, bytesTransferred);
HciEventHdr *hdr = (HciEventHdr *)buffer;
if (hdr->evt == HCI_EVT_LE_META && hdr->data[0] == HCI_EVT_LE_META_READ_REMOTE_FEATURES_COMPLETE) {
if (skipExtraReadRemoteFeaturesComplete) {
skipExtraReadRemoteFeaturesComplete = false;
} else {
// Copy Connection Handle
fakePhyUpdateCompleteEvent[4] = hdr->data[2];
fakePhyUpdateCompleteEvent[5] = hdr->data[3];
dataBuffer->writeBytes(0, fakePhyUpdateCompleteEvent, 8);
skipExtraReadRemoteFeaturesComplete = true;
}
}
IOFree(buffer, bytesTransferred);
}
if (asyncOwner->action)
asyncOwner->action(asyncOwner->owner, parameter, status, bytesTransferred);
}

IOReturn CIntelBTPatcher::
newAsyncIO(void *that, IOMemoryDescriptor* dataBuffer, uint32_t bytesTransferred, IOUSBHostCompletion* completion, uint32_t completionTimeoutMs)
{
if (that == _hookPipeInstance && completion) {
_interruptPipeAsyncOwner->action = completion->action;
_interruptPipeAsyncOwner->owner = completion->owner;
_interruptPipeAsyncOwner->dataBuffer = dataBuffer;
completion->action = asyncIOCompletion;
completion->owner = _interruptPipeAsyncOwner;
}
return FunctionCast(newAsyncIO, callbackIBTPatcher->oldAsyncIO)(that, dataBuffer, bytesTransferred, completion, completionTimeoutMs);
}

#define VENDOR_USB_INTEL 0x8087

int CIntelBTPatcher::
newInitPipe(void *that, StandardUSB::EndpointDescriptor const *descriptor, StandardUSB::SuperSpeedEndpointCompanionDescriptor const *superDescriptor, AppleUSBHostController *controller, IOUSBHostDevice *device, IOUSBHostInterface *interface, unsigned char a7, unsigned short a8)
{
int ret = FunctionCast(newInitPipe, callbackIBTPatcher->oldInitPipe)(that, descriptor, superDescriptor, controller, device, interface, a7, a8);
if (device) {
const StandardUSB::DeviceDescriptor *deviceDescriptor = device->getDeviceDescriptor();
if (deviceDescriptor &&
deviceDescriptor->idVendor == VENDOR_USB_INTEL) {
uint8_t epType = StandardUSB::getEndpointType(descriptor);
if (epType == kIOUSBEndpointTypeInterrupt) {
CIntelBTPatcher::_hookPipeInstance = that;
if (!CIntelBTPatcher::_interruptPipeAsyncOwner)
CIntelBTPatcher::_interruptPipeAsyncOwner = new AsyncOwnerData;
CIntelBTPatcher::_randomAddressInit = false;
}
}
}
return ret;
}
15 changes: 7 additions & 8 deletions IntelBTPatcher/IntelBTPatcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,8 @@ typedef struct __attribute__((packed))
{
uint8_t evt;
uint8_t len;
} HciEventHdr;

typedef struct __attribute__((packed))
{
HciEventHdr evt;
uint8_t numCommands;
uint16_t opcode;
uint8_t data[];
} HciResponse;
} HciEventHdr;

const char *requestDirectionNames[] = {
"OUT",
Expand Down Expand Up @@ -82,12 +75,18 @@ class CIntelBTPatcher {
static IOReturn newFindQueueRequest(void *that, unsigned short arg1, void *addr, unsigned short arg2, bool arg3, void **hciRequestPtr);

static IOReturn newHostDeviceRequest(void *that, IOService *provider, StandardUSB::DeviceRequest &request, void *data, IOMemoryDescriptor *descriptor, unsigned int &length,IOUSBHostCompletion *completion, unsigned int timeout);
static IOReturn newAsyncIO(void *that, IOMemoryDescriptor* dataBuffer, uint32_t dataBufferLength, IOUSBHostCompletion* completion, uint32_t completionTimeoutMs);
static int newInitPipe(void *that, StandardUSB::EndpointDescriptor const *descriptor, StandardUSB::SuperSpeedEndpointCompanionDescriptor const *superDescriptor,AppleUSBHostController *controller, IOUSBHostDevice *device, IOUSBHostInterface *interface, unsigned char, unsigned short);


mach_vm_address_t oldFindQueueRequest {};
mach_vm_address_t oldHostDeviceRequest {};
mach_vm_address_t oldAsyncIO {};
mach_vm_address_t oldInitPipe {};

private:
static void *_hookPipeInstance;
static AsyncOwnerData *_interruptPipeAsyncOwner;
static bool _randomAddressInit;
};

Expand Down