feat(wifi): instantiate and attach native IO80211SkywalkInterface for airportd integration

### Breakthroughs & Rétro-ingénierie
- **Rétro-ingénierie ABI Skywalk Tahoe (`BootKernelExtensions.kc`)** :
  - Analyse désassemblée via Capstone de `IO80211Controller::attachInterface` (`0xffffff8002295fce`, slot 441) :
    - Le premier argument `rsi` doit être l'instance `IO80211SkywalkInterface`.
    - La fonction effectue `OSDynamicCast(IO80211SkywalkInterface, iface)`.
    - Vérification du rôle d'interface : `cmp dword ptr [rcx + 0x58], 1`. Si égal à 1 (Infra / Primary Wi-Fi), le pointeur est assigné à `ivars + 0x188` (`primaryInterface`).
  - Analyse de `IO80211SkywalkInterface::setInterfaceRole(unsigned int role)` (`0xffffff80022f60f0`) :
    - Écrit la valeur du rôle dans `ivars + 0x58` (`mov dword ptr [rax + 0x58], esi`), satisfaisant la condition de slot 441.
  - Analyse du cycle de vie de `IO80211SkywalkInterface` :
    - La classe ne possède aucun slot virtuel pur (`___cxa_pure_virtual` = 0).
    - Taille d'instance exacte : `0x128` (296 octets), ivars privées `0xf0` octets allouées par `initIvars()`.
    - L'initialisation via `init(controller, mac)` copie l'adresse MAC physique dans `ivars + 0xe4`.
    - `start(controller)` crée l'interface BSD (`en1`/`en2`), initialise `CCPipe` CoreCapture, lie le `getWorkQueue()` du contrôleur, invoque `controller->open(iface)` et instancie l'agent `IO80211MacAddressAgent`.

### Modifications apportées
- `QualcommWireless/include/IOKit/80211/IO80211SkywalkInterface.h` :
  - Déclaration de l'héritage `public IOSkywalkEthernetInterface`.
  - Déclaration des signatures de méthodes : `init(controller, mac)`, `setInterfaceRole(role)`, `start(controller)`, `stop(controller)`, `free()`.
- `QualcommWifi/QualcommWifi.hpp` :
  - Ajout du membre `IO80211SkywalkInterface *fSkywalkInterface`.
- `QualcommWifi/QualcommWifi.cpp` :
  - Déclaration des symboles externes exportés par `BootKernelExtensions.kc` (`_ZN23IO80211SkywalkInterfacenwEm`, `_ZN23IO80211SkywalkInterfaceC1EPK11OSMetaClass`, `_ZN23IO80211SkywalkInterface10gMetaClassE`).
  - Fonction helper `createSkywalkInterface()` allouant l'instance avec la metaclass native.
  - Dans `QualcommWifi::start()` :
    - Contrôle via boot-arg `qcom_skywalk=1`.
    - Instanciation de l'interface Skywalk via `createSkywalkInterface()`.
    - Initialisation avec MAC physique (`fMacAddress`) et assignation du rôle 1 (`setInterfaceRole(1)`).
    - Attachement IOKit (`attach(this)`), démarrage Skywalk (`start(this)`).
    - Enregistrement auprès du contrôleur (`attachInterface(fSkywalkInterface, nullptr)`).
    - Publication du service IOKit (`skywalk->registerService()`) pour notifier `airportd`.
  - Dans `QualcommWifi::stop()` : détachement propre (`detachInterface(fSkywalkInterface, false)`), `stop()`, `detach()` et libération.

### Validation
- Compilation réussie sans warning : `clang++ -target x86_64-apple-macos26.5`.
- Validation d'édition de liens et kext dependencies : `kmutil libraries -p build/Release/QualcommWifi.kext` à 100%.
- Déploiement automatique dans `/Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext`.
- Mise à jour de `/Volumes/EFI/EFI/OC/config.plist` avec `qcom_skywalk=1` (validé par `plutil -lint`).
This commit is contained in:
Erwan committed 2026-10-18 13:29:20 +02:00
1 parent d222156c8b
commit e4c7d59a5e
3 files changed
+74 -6

No files matched your search

+67 -4
View File
@@ -128,6 +128,23 @@ static_assert(__builtin_offsetof(FakeLogStream, streamData) == 0x88, "streamData
static_assert(__builtin_offsetof(FakeLogStream, p1) == 0x90, "p1 must be at offset 0x90 for CCLogStream ABI");
static_assert(sizeof(FakeLogStream) == 0x98, "FakeLogStream size must match CCLogStream ABI (0x98)");
extern "C" {
void* _ZN23IO80211SkywalkInterfacenwEm(unsigned long size);
void _ZN23IO80211SkywalkInterfaceC1EPK11OSMetaClass(void *thisPtr, const void *meta);
void _ZN23IO80211SkywalkInterfacedlEPvm(void *ptr, unsigned long size);
extern const void * const _ZN23IO80211SkywalkInterface10gMetaClassE;
}
static IO80211SkywalkInterface* createSkywalkInterface(void) {
void *mem = _ZN23IO80211SkywalkInterfacenwEm(0x128);
if (!mem) {
IOLog("QualcommWifi: Erreur - operator new(IO80211SkywalkInterface) a echoue !\n");
return nullptr;
}
_ZN23IO80211SkywalkInterfaceC1EPK11OSMetaClass(mem, &_ZN23IO80211SkywalkInterface10gMetaClassE);
return (IO80211SkywalkInterface *)mem;
}
#define super IO80211Controller
OSDefineMetaClassAndStructors(QualcommWifi, IO80211Controller)
@@ -146,6 +163,7 @@ bool QualcommWifi::init(OSDictionary *dictionary) {
fWorkLoop = nullptr;
fWorkQueue = nullptr;
fNetif = nullptr;
fSkywalkInterface = nullptr;
// Adresse MAC par défaut (OUI Qualcomm 00:03:7F) en attendant la lecture BHI
fMacAddress.bytes[0] = 0x00;
fMacAddress.bytes[1] = 0x03;
@@ -173,6 +191,7 @@ bool QualcommWifi::init(OSDictionary *dictionary) {
void QualcommWifi::free(void) {
logNvramStage("free_enter");
OSSafeReleaseNULL(fSkywalkInterface);
OSSafeReleaseNULL(fFaultReporter);
OSSafeReleaseNULL(fLogger);
OSSafeReleaseNULL(fWorkLoop);
@@ -752,10 +771,47 @@ bool QualcommWifi::start(IOService *provider) {
setProperty("IO80211ScanCache", true);
setProperty("IO80211RadioState", (UInt64)1, 32);
// Note d'architecture Tahoe : un contrôleur IO80211Controller ne publie pas de médium Ethernet
// et ne doit pas appeler registerService() directement (anti-patron IOKit déclenchant airportd
// prématurément avant l'attachement d'une interface Skywalk).
// Contrôlé par boot-arg "qcom_register=1" pour isoler et tester le matching.
// Instanciation et attachement de l'interface réseau Skywalk native (IO80211SkywalkInterface)
// Contrôlé par boot-arg "qcom_skywalk=1" (activé par défaut)
int allow_skywalk = 1;
PE_parse_boot_argn("qcom_skywalk", &allow_skywalk, sizeof(allow_skywalk));
if (allow_skywalk) {
logNvramStage("skywalk_alloc");
fSkywalkInterface = createSkywalkInterface();
if (fSkywalkInterface) {
logNvramStage("skywalk_init");
if (fSkywalkInterface->init(this, (ether_addr *)&fMacAddress)) {
logNvramStage("skywalk_role");
fSkywalkInterface->setInterfaceRole(1); // 1 = kIO80211InterfaceRoleInfra (Primary Wi-Fi)
logNvramStage("skywalk_attach");
if (fSkywalkInterface->attach(this)) {
logNvramStage("skywalk_start");
if (fSkywalkInterface->start(this)) {
logNvramStage("skywalk_attach_ctrl");
attachInterface(fSkywalkInterface, nullptr); // slot 441 in IO80211Controller
logNvramStage("skywalk_register");
fSkywalkInterface->registerService();
IOLog("QualcommWifi: Interface Skywalk native (IO80211SkywalkInterface) attachée et enregistrée avec succès !\n");
} else {
logNvramStage("skywalk_start_err");
IOLog("QualcommWifi: Erreur - fSkywalkInterface->start(this) a échoué !\n");
fSkywalkInterface->detach(this);
OSSafeReleaseNULL(fSkywalkInterface);
}
} else {
logNvramStage("skywalk_attach_err");
IOLog("QualcommWifi: Erreur - fSkywalkInterface->attach(this) a échoué !\n");
OSSafeReleaseNULL(fSkywalkInterface);
}
} else {
logNvramStage("skywalk_init_err");
IOLog("QualcommWifi: Erreur - fSkywalkInterface->init(...) a échoué !\n");
OSSafeReleaseNULL(fSkywalkInterface);
}
}
}
int allow_register = 0;
PE_parse_boot_argn("qcom_register", &allow_register, sizeof(allow_register));
@@ -774,6 +830,13 @@ bool QualcommWifi::start(IOService *provider) {
void QualcommWifi::stop(IOService *provider) {
IOLog("QualcommWifi: Arret du pilote Wi-Fi natif, liberation MSI, DMA et BAR0.\n");
if (fSkywalkInterface) {
detachInterface(fSkywalkInterface, false); // slot 442 in IO80211Controller
fSkywalkInterface->stop(this);
fSkywalkInterface->detach(this);
OSSafeReleaseNULL(fSkywalkInterface);
}
IOWorkLoop *workLoop = getWorkLoop();
if (fInterruptSource) {
fInterruptSource->disable();
+1
View File
@@ -188,6 +188,7 @@ private:
IOWorkLoop *fWorkLoop;
IO80211WorkQueue *fWorkQueue;
IONetworkInterface *fNetif;
IO80211SkywalkInterface *fSkywalkInterface;
IOEthernetAddress fMacAddress;
// État réseau Wi-Fi
@@ -17,11 +17,15 @@
#error "Please define __IO80211_TARGET to the requested version"
#endif
class IO80211SkywalkInterface : IOSkywalkEthernetInterface {
class IO80211SkywalkInterface : public IOSkywalkEthernetInterface {
OSDeclareAbstractStructors(IO80211SkywalkInterface)
public:
virtual bool init(IOService *controller, ether_addr *mac);
virtual void setInterfaceRole(UInt32 role);
virtual bool start(IOService *controller) APPLE_KEXT_OVERRIDE;
virtual void stop(IOService *controller) APPLE_KEXT_OVERRIDE;
virtual void free() APPLE_KEXT_OVERRIDE;
};
#endif /* _IO80211SKYWALK_H */