From 88c0dccd794ec064987ec2058bfcb4b9ee1aae6a Mon Sep 17 00:00:00 2001 From: nawrhehe Date: Thu, 15 Oct 2026 22:47:48 +0200 Subject: [PATCH] fix(bt): configure static LE random address to resolve status 718 scan crash --- QualcommWireless/QualcommWireless.cpp | 238 ++++++++++++++++---------- QualcommWireless/QualcommWireless.hpp | 1 + 2 files changed, 144 insertions(+), 95 deletions(-) diff --git a/QualcommWireless/QualcommWireless.cpp b/QualcommWireless/QualcommWireless.cpp index 1c1728a..a2f9b3b 100644 --- a/QualcommWireless/QualcommWireless.cpp +++ b/QualcommWireless/QualcommWireless.cpp @@ -165,6 +165,51 @@ bool QualcommWireless::sendHciReset(void) { return true; } +bool QualcommWireless::sendHciLeSetRandomAddress(void) { + // Bluetooth Core Specification 5.0+ (Vol 4, Part E, 7.8.5): + // Commande HCI_LE_Set_Random_Address (Opcode: 0x2005 = OGF 0x08, OCF 0x0005) + // Paramètre: 6 octets pour l'adresse aléatoire statique (les 2 bits de poids fort du MSB sont à 11b). + // Sur macOS Monterey à Sequoia, bluetoothd initie un scan LE passif avec own_address_type = 0x01 (Random) + // sans configurer d'adresse aléatoire. Le matériel Qualcomm WCN7850 rejette alors la commande + // HCI_LE_Set_Scan_Enable avec le statut 0x12 (Invalid Parameters), provoquant le crash en boucle + // de bluetoothd (OI_STATUS 718). + // Adresse statique générée : EC:F2:3C:7F:1B:48 (0xEC = 1110 1100b -> bits 7 et 6 à 1). + uint8_t cmd[9] = {0x05, 0x20, 0x06, 0x48, 0x1B, 0x7F, 0x3C, 0xF2, 0xEC}; + uint32_t transferred = 0; + + StandardUSB::DeviceRequest req; + req.bmRequestType = makeDeviceRequestbmRequestType(kRequestDirectionOut, + kRequestTypeClass, + kRequestRecipientInterface); + req.bRequest = 0; + req.wValue = 0; + req.wIndex = 0; + req.wLength = sizeof(cmd); + + IOReturn kr = fDevice->deviceRequest(this, req, cmd, transferred, 2000); + if (kr != kIOReturnSuccess) { + IOLog("QualcommWireless: Erreur envoi HCI LE Set Random Address (0x%08x)\n", kr); + return false; + } + + if (fIntrInPipe && fBulkBuffer) { + uint32_t bytesRead = 0; + kr = fIntrInPipe->io(fBulkBuffer, 256, bytesRead, 2000); + if (kr == kIOReturnSuccess && bytesRead > 0) { + uint8_t *evt = (uint8_t *)fBulkBuffer->getBytesNoCopy(); + if (evt[0] == 0x0E && bytesRead >= 6 && evt[5] == 0) { + IOLog("QualcommWireless: HCI LE Set Random Address acquitte avec succes (statut 0x00) !\n"); + return true; + } else { + IOLog("QualcommWireless: HCI LE Set Random Address reponse evt=0x%02x statut=0x%02x\n", + evt[0], (bytesRead > 5) ? evt[5] : 0xFF); + } + } + } + + return true; +} + bool QualcommWireless::start(IOService *provider) { if (!super::start(provider)) return false; @@ -203,108 +248,111 @@ bool QualcommWireless::start(IOService *provider) { bool needPatch = !(status & 0x80); bool needNvm = !(status & 0x40); - if (needPatch || needNvm) { - // Recherche de l'interface 0 (avec réessais si l'énumération est en cours) - for (int retry = 0; retry < 10 && !fInterface; retry++) { - OSIterator *iterator = fDevice->getChildIterator(gIOServicePlane); - if (iterator) { - OSObject *candidate; - while ((candidate = iterator->getNextObject())) { - IOUSBHostInterface *intf = OSDynamicCast(IOUSBHostInterface, candidate); - if (intf && intf->getInterfaceDescriptor() && intf->getInterfaceDescriptor()->bInterfaceNumber == 0) { - fInterface = intf; - fInterface->retain(); - break; - } + // Recherche de l'interface 0 (avec réessais si l'énumération est en cours) + for (int retry = 0; retry < 10 && !fInterface; retry++) { + OSIterator *iterator = fDevice->getChildIterator(gIOServicePlane); + if (iterator) { + OSObject *candidate; + while ((candidate = iterator->getNextObject())) { + IOUSBHostInterface *intf = OSDynamicCast(IOUSBHostInterface, candidate); + if (intf && intf->getInterfaceDescriptor() && intf->getInterfaceDescriptor()->bInterfaceNumber == 0) { + fInterface = intf; + fInterface->retain(); + break; } - OSSafeReleaseNULL(iterator); - } - if (!fInterface) { - IOSleep(30); } + OSSafeReleaseNULL(iterator); } - if (!fInterface) { - IOLog("QualcommWireless: Erreur - Interface 0 non trouvee.\n"); - fDevice->close(this); - OSSafeReleaseNULL(fDevice); - return false; + IOSleep(30); } - - if (!fInterface->open(this)) { - IOLog("QualcommWireless: Impossible d'ouvrir l'interface 0.\n"); - OSSafeReleaseNULL(fInterface); - fDevice->close(this); - OSSafeReleaseNULL(fDevice); - return false; - } - - // Recherche des pipes (Bulk OUT 0x02 et Interrupt IN 0x81) - const StandardUSB::ConfigurationDescriptor *configDescriptor = fInterface->getConfigurationDescriptor(); - const StandardUSB::InterfaceDescriptor *interfaceDescriptor = fInterface->getInterfaceDescriptor(); - const EndpointDescriptor *endpointDescriptor = nullptr; - - while ((endpointDescriptor = StandardUSB::getNextEndpointDescriptor(configDescriptor, interfaceDescriptor, endpointDescriptor))) { - uint8_t epDirection = StandardUSB::getEndpointDirection(endpointDescriptor); - uint8_t epType = StandardUSB::getEndpointType(endpointDescriptor); - uint8_t epAddress = StandardUSB::getEndpointAddress(endpointDescriptor); - - if (epDirection == kEndpointDirectionOut && epType == kEndpointTypeBulk) { - fBulkOutPipe = fInterface->copyPipe(epAddress); - } else if (epDirection == kEndpointDirectionIn && epType == kEndpointTypeInterrupt) { - fIntrInPipe = fInterface->copyPipe(epAddress); - } - } - - fBulkBuffer = fInterface->createIOBuffer(kIODirectionOut, QCA_DFU_PACKET_LEN); - - if (fBulkOutPipe && fBulkBuffer) { - if (needPatch) { - IOLog("QualcommWireless: Televersement du RAMPATCH WCN7850 (%u octets)...\n", rampatch_usb_00190200_bin_len); - if (downloadFirmware(rampatch_usb_00190200_bin, rampatch_usb_00190200_bin_len, 40)) { - IOLog("QualcommWireless: RAMPATCH televerse avec succes !\n"); - } else { - IOLog("QualcommWireless: Echec du televersement RAMPATCH !\n"); - } - } - - status = checkStatus(); - if (needNvm) { - IOLog("QualcommWireless: Televersement du NVM WCN7850 (%u octets)...\n", nvm_usb_00190200_bin_len); - if (downloadFirmware(nvm_usb_00190200_bin, nvm_usb_00190200_bin_len, 4)) { - IOLog("QualcommWireless: NVM televerse avec succes !\n"); - } else { - IOLog("QualcommWireless: Echec du televersement NVM !\n"); - } - IOSleep(100); - } - - sendHciReset(); - - // Délai de stabilisation post-reset (150 ms) pour permettre au processeur Bluetooth - // et aux tampons FIFO USB de re-calibrer leur état avant que bluetoothd n'initialise la pile. - IOSleep(150); - } else { - IOLog("QualcommWireless: Erreur initialisation pipes ou buffer.\n"); - } - - if (fIntrInPipe) { - fIntrInPipe->clearStall(false); - } - if (fBulkOutPipe) { - fBulkOutPipe->clearStall(false); - } - - OSSafeReleaseNULL(fBulkBuffer); - OSSafeReleaseNULL(fBulkOutPipe); - OSSafeReleaseNULL(fIntrInPipe); - - if (fInterface->isOpen(this)) { - fInterface->close(this); - } - OSSafeReleaseNULL(fInterface); } + if (!fInterface) { + IOLog("QualcommWireless: Erreur - Interface 0 non trouvee.\n"); + fDevice->close(this); + OSSafeReleaseNULL(fDevice); + return false; + } + + if (!fInterface->open(this)) { + IOLog("QualcommWireless: Impossible d'ouvrir l'interface 0.\n"); + OSSafeReleaseNULL(fInterface); + fDevice->close(this); + OSSafeReleaseNULL(fDevice); + return false; + } + + // Recherche des pipes (Bulk OUT 0x02 et Interrupt IN 0x81) + const StandardUSB::ConfigurationDescriptor *configDescriptor = fInterface->getConfigurationDescriptor(); + const StandardUSB::InterfaceDescriptor *interfaceDescriptor = fInterface->getInterfaceDescriptor(); + const EndpointDescriptor *endpointDescriptor = nullptr; + + while ((endpointDescriptor = StandardUSB::getNextEndpointDescriptor(configDescriptor, interfaceDescriptor, endpointDescriptor))) { + uint8_t epDirection = StandardUSB::getEndpointDirection(endpointDescriptor); + uint8_t epType = StandardUSB::getEndpointType(endpointDescriptor); + uint8_t epAddress = StandardUSB::getEndpointAddress(endpointDescriptor); + + if (epDirection == kEndpointDirectionOut && epType == kEndpointTypeBulk) { + fBulkOutPipe = fInterface->copyPipe(epAddress); + } else if (epDirection == kEndpointDirectionIn && epType == kEndpointTypeInterrupt) { + fIntrInPipe = fInterface->copyPipe(epAddress); + } + } + + fBulkBuffer = fInterface->createIOBuffer(kIODirectionOut, QCA_DFU_PACKET_LEN); + + if (fBulkOutPipe && fBulkBuffer) { + if (needPatch) { + IOLog("QualcommWireless: Televersement du RAMPATCH WCN7850 (%u octets)...\n", rampatch_usb_00190200_bin_len); + if (downloadFirmware(rampatch_usb_00190200_bin, rampatch_usb_00190200_bin_len, 40)) { + IOLog("QualcommWireless: RAMPATCH televerse avec succes !\n"); + } else { + IOLog("QualcommWireless: Echec du televersement RAMPATCH !\n"); + } + } + + status = checkStatus(); + if (needNvm) { + IOLog("QualcommWireless: Televersement du NVM WCN7850 (%u octets)...\n", nvm_usb_00190200_bin_len); + if (downloadFirmware(nvm_usb_00190200_bin, nvm_usb_00190200_bin_len, 4)) { + IOLog("QualcommWireless: NVM televerse avec succes !\n"); + } else { + IOLog("QualcommWireless: Echec du televersement NVM !\n"); + } + IOSleep(100); + } + + // Réinitialisation du contrôleur Bluetooth + sendHciReset(); + IOSleep(50); + + // Configuration d'une adresse aléatoire statique obligatoire pour le scan LE de macOS (évite erreur 718) + sendHciLeSetRandomAddress(); + + // Délai de stabilisation post-reset (150 ms) pour permettre au processeur Bluetooth + // et aux tampons FIFO USB de re-calibrer leur état avant que bluetoothd n'initialise la pile. + IOSleep(150); + } else { + IOLog("QualcommWireless: Erreur initialisation pipes ou buffer.\n"); + } + + if (fIntrInPipe) { + fIntrInPipe->clearStall(false); + } + if (fBulkOutPipe) { + fBulkOutPipe->clearStall(false); + } + + OSSafeReleaseNULL(fBulkBuffer); + OSSafeReleaseNULL(fBulkOutPipe); + OSSafeReleaseNULL(fIntrInPipe); + + if (fInterface->isOpen(this)) { + fInterface->close(this); + } + OSSafeReleaseNULL(fInterface); + uint8_t finalStatus = checkStatus(); IOLog("QualcommWireless: Statut FINAL: 0x%02x (Patch: %s, Syscfg: %s) -> Pret pour macOS !\n", finalStatus, (finalStatus & 0x80) ? "OUI" : "NON", (finalStatus & 0x40) ? "OUI" : "NON"); diff --git a/QualcommWireless/QualcommWireless.hpp b/QualcommWireless/QualcommWireless.hpp index 9bda298..9196ba4 100644 --- a/QualcommWireless/QualcommWireless.hpp +++ b/QualcommWireless/QualcommWireless.hpp @@ -39,6 +39,7 @@ private: bool queryTargetVersion(struct qca_version *verOut); bool downloadFirmware(const uint8_t *data, size_t size, size_t hdrSize); bool sendHciReset(void); + bool sendHciLeSetRandomAddress(void); public: virtual bool init(OSDictionary *dictionary = 0) override;