diff --git a/IntelBTPatcher/IntelBTPatcher.cpp b/IntelBTPatcher/IntelBTPatcher.cpp index 6351761..6fd525d 100644 --- a/IntelBTPatcher/IntelBTPatcher.cpp +++ b/IntelBTPatcher/IntelBTPatcher.cpp @@ -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() @@ -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(); + } } } } @@ -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) { @@ -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); 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); } + } 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; @@ -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; +} diff --git a/IntelBTPatcher/IntelBTPatcher.hpp b/IntelBTPatcher/IntelBTPatcher.hpp index 0e5f7b3..fd37fe7 100644 --- a/IntelBTPatcher/IntelBTPatcher.hpp +++ b/IntelBTPatcher/IntelBTPatcher.hpp @@ -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", @@ -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; };