1
0
mirror of https://github.com/OpenIntelWireless/itlwm.git synced 2025-06-03 06:05:18 +00:00
Files
itlwm/AirportItlwm/AirportItlwm.cpp

1072 lines
33 KiB
C++

/*
* Copyright (C) 2020 钟先耀
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "AirportItlwm.hpp"
#include <crypto/sha1.h>
#include <net80211/ieee80211_priv.h>
#include <net80211/ieee80211_var.h>
#define super IO80211Controller
OSDefineMetaClassAndStructors(AirportItlwm, IO80211Controller);
OSDefineMetaClassAndStructors(CTimeout, OSObject)
IO80211WorkLoop *_fWorkloop;
IOCommandGate *_fCommandGate;
bool AirportItlwm::init(OSDictionary *properties)
{
bool ret = super::init(properties);
awdlSyncEnable = true;
power_state = 0;
memset(geo_location_cc, 0, sizeof(geo_location_cc));
return ret;
}
#define PCI_MSI_FLAGS 2 /* Message Control */
#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
#define PCI_MSIX_FLAGS 2 /* Message Control */
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
#define PCI_MSIX_FLAGS_ENABLE 0x8000 /* MSI-X enable */
#define PCI_MSI_FLAGS_ENABLE 0x0001 /* MSI feature enabled */
static void pciMsiSetEnable(IOPCIDevice *device, UInt8 msiCap, int enable)
{
u16 control;
control = device->configRead16(msiCap + PCI_MSI_FLAGS);
control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable)
control |= PCI_MSI_FLAGS_ENABLE;
device->configWrite16(msiCap + PCI_MSI_FLAGS, control);
}
static void pciMsiXClearAndSet(IOPCIDevice *device, UInt8 msixCap, UInt16 clear, UInt16 set)
{
u16 ctrl;
ctrl = device->configRead16(msixCap + PCI_MSIX_FLAGS);
ctrl &= ~clear;
ctrl |= set;
device->configWrite16(msixCap + PCI_MSIX_FLAGS, ctrl);
}
static int kernel_version_map[] = {
[14] = __MAC_10_10,
[15] = __MAC_10_11,
[16] = __MAC_10_12,
[17] = __MAC_10_13,
[18] = __MAC_10_14,
[19] = __MAC_10_15,
[20] = __MAC_11_0,
[21] = __MAC_12_0,
[22] = __MAC_13_0,
[23] = __MAC_14_0,
[99] = 999999999
};
IOService* AirportItlwm::probe(IOService *provider, SInt32 *score)
{
bool isMatch = false;
if (__IO80211_TARGET != kernel_version_map[version_major]) {
XYLog("%s Please use the correct kext version corresponding to the OS!!!\n", __FUNCTION__);
return NULL;
}
super::probe(provider, score);
UInt8 msiCap;
UInt8 msixCap;
IOPCIDevice* device = OSDynamicCast(IOPCIDevice, provider);
if (!device)
return NULL;
if (ItlIwx::iwx_match(device)) {
isMatch = true;
fHalService = new ItlIwx;
}
if (!isMatch && ItlIwm::iwm_match(device)) {
isMatch = true;
fHalService = new ItlIwm;
}
if (!isMatch && ItlIwn::iwn_match(device)) {
isMatch = true;
fHalService = new ItlIwn;
}
if (isMatch) {
device->findPCICapability(PCI_CAP_ID_MSIX, &msixCap);
if (msixCap)
pciMsiXClearAndSet(device, msixCap, PCI_MSIX_FLAGS_ENABLE, 0);
device->findPCICapability(PCI_CAP_ID_MSI, &msiCap);
if (msiCap)
pciMsiSetEnable(device, msiCap, 1);
if (!msiCap && !msixCap) {
XYLog("%s No MSI cap\n", __FUNCTION__);
fHalService->release();
fHalService = NULL;
return NULL;
}
return this;
}
return NULL;
}
bool AirportItlwm::configureInterface(IONetworkInterface *netif)
{
IONetworkData *nd;
struct _ifnet *ifp = &fHalService->get80211Controller()->ic_ac.ac_if;
if (super::configureInterface(netif) == false) {
XYLog("super failed\n");
return false;
}
nd = netif->getParameter(kIONetworkStatsKey);
if (!nd || !(fpNetStats = (IONetworkStats *)nd->getBuffer())) {
XYLog("network statistics buffer unavailable?\n");
return false;
}
ifp->netStat = fpNetStats;
ether_ifattach(ifp, OSDynamicCast(IOEthernetInterface, netif));
fpNetStats->collisions = 0;
#ifdef __PRIVATE_SPI__
netif->configureOutputPullModel(fHalService->getDriverInfo()->getTxQueueSize(), 0, 0, IOEthernetInterface::kOutputPacketSchedulingModelNormal, 0);
#endif
return true;
}
IONetworkInterface *AirportItlwm::createInterface()
{
AirportItlwmInterface *netif = new AirportItlwmInterface;
if (!netif)
return NULL;
if (!netif->init(this, fHalService)) {
netif->release();
return NULL;
}
return netif;
}
void AirportItlwm::associateSSID(uint8_t *ssid, uint32_t ssid_len, const struct ether_addr &bssid, uint32_t authtype_lower, uint32_t authtype_upper, uint8_t *key, uint32_t key_len, int key_index)
{
struct ieee80211com *ic = fHalService->get80211Controller();
ieee80211_disable_rsn(ic);
ieee80211_disable_wep(ic);
struct ieee80211_wpaparams wpa;
struct ieee80211_nwkey nwkey;
bzero(&wpa, sizeof(wpa));
bzero(&nwkey, sizeof(nwkey));
memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
memcpy(ic->ic_des_essid, ssid, ssid_len);
ic->ic_des_esslen = ssid_len;
bool is_zero = true;
for (int i = 0; i < IEEE80211_ADDR_LEN; i++)
is_zero &= bssid.octet[i] == 0;
if (!is_zero) {
IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid.octet);
ic->ic_flags |= IEEE80211_F_DESBSSID;
}
else {
memset(ic->ic_des_bssid, 0, IEEE80211_ADDR_LEN);
ic->ic_flags &= ~IEEE80211_F_DESBSSID;
}
// AUTHTYPE_WPA3_SAE AUTHTYPE_WPA3_FT_SAE
// we don't really support WPA3, but we have announced we support WPA3 in card capability function. so we fake it as WPA2 to support some WPA2/WPA3 mix wifi connection.
if (authtype_upper == APPLE80211_AUTHTYPE_WPA3_SAE || authtype_upper == APPLE80211_AUTHTYPE_WPA3_FT_SAE) {
wpa.i_protos |= IEEE80211_WPA_PROTO_WPA2;
authtype_upper |= APPLE80211_AUTHTYPE_WPA2_PSK;// hack
}
// AUTHTYPE_WPA3_ENTERPRISE AUTHTYPE_WPA3_FT_ENTERPRISE
if (authtype_upper == APPLE80211_AUTHTYPE_WPA3_ENTERPRISE || authtype_upper == APPLE80211_AUTHTYPE_WPA3_FT_ENTERPRISE) {
wpa.i_protos |= IEEE80211_WPA_PROTO_WPA2;
authtype_upper |= APPLE80211_AUTHTYPE_WPA2;// hack
}
if (authtype_upper & (APPLE80211_AUTHTYPE_WPA | APPLE80211_AUTHTYPE_WPA_PSK | APPLE80211_AUTHTYPE_WPA2 | APPLE80211_AUTHTYPE_WPA2_PSK | APPLE80211_AUTHTYPE_SHA256_PSK | APPLE80211_AUTHTYPE_SHA256_8021X)) {
XYLog("%s %d\n", __FUNCTION__, __LINE__);
wpa.i_protos = IEEE80211_WPA_PROTO_WPA1 | IEEE80211_WPA_PROTO_WPA2;
}
if (authtype_upper & (APPLE80211_AUTHTYPE_WPA_PSK | APPLE80211_AUTHTYPE_WPA2_PSK | APPLE80211_AUTHTYPE_SHA256_PSK)) {
XYLog("%s %d\n", __FUNCTION__, __LINE__);
wpa.i_akms |= IEEE80211_WPA_AKM_PSK | IEEE80211_WPA_AKM_SHA256_PSK;
wpa.i_enabled = 1;
memcpy(ic->ic_psk, key, sizeof(ic->ic_psk));
ic->ic_flags |= IEEE80211_F_PSK;
ieee80211_ioctl_setwpaparms(ic, &wpa);
}
if (authtype_upper & (APPLE80211_AUTHTYPE_WPA | APPLE80211_AUTHTYPE_WPA2 | APPLE80211_AUTHTYPE_SHA256_8021X)) {
XYLog("%s %d\n", __FUNCTION__, __LINE__);
wpa.i_akms |= IEEE80211_WPA_AKM_8021X | IEEE80211_WPA_AKM_SHA256_8021X;
wpa.i_enabled = 1;
ieee80211_ioctl_setwpaparms(ic, &wpa);
}
if (authtype_lower == APPLE80211_AUTHTYPE_SHARED) {
XYLog("shared key authentication is not supported!\n");
return;
}
if (authtype_upper == APPLE80211_AUTHTYPE_NONE && authtype_lower == APPLE80211_AUTHTYPE_OPEN) { // Open or WEP Open System
if (key_len > 0) {
XYLog("%s %d\n", __FUNCTION__, __LINE__);
nwkey.i_wepon = IEEE80211_NWKEY_WEP;
nwkey.i_defkid = key_index + 1;
nwkey.i_key[key_index].i_keylen = (int)key_len;
nwkey.i_key[key_index].i_keydat = key;
ieee80211_ioctl_setnwkeys(ic, &nwkey);
}
}
}
void AirportItlwm::setPTK(const u_int8_t *key, size_t key_len) {
struct ieee80211com *ic = fHalService->get80211Controller();
struct ieee80211_node * ni = ic->ic_bss;
struct ieee80211_key *k;
int keylen;
ni->ni_rsn_supp_state = RNSA_SUPP_PTKDONE;
if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) {
u_int64_t prsc;
/* check that key length matches that of pairwise cipher */
keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
if (key_len != keylen) {
XYLog("PTK length mismatch. expected %d, got %zu\n", keylen, key_len);
return;
}
prsc = /*(gtk == NULL) ? LE_READ_6(key->rsc) :*/ 0;
/* map PTK to 802.11 key */
k = &ni->ni_pairwise_key;
memset(k, 0, sizeof(*k));
k->k_cipher = ni->ni_rsncipher;
k->k_rsc[0] = prsc;
k->k_len = keylen;
memcpy(k->k_key, key, k->k_len);
/* install the PTK */
if ((*ic->ic_set_key)(ic, ni, k) != 0) {
XYLog("setting PTK failed\n");
return;
}
else
XYLog("setting PTK successfully\n");
ni->ni_flags &= ~IEEE80211_NODE_RSN_NEW_PTK;
ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT;
ni->ni_flags |= IEEE80211_NODE_RXPROT;
} else if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP)
XYLog("%s: unexpected pairwise key update received from %s\n",
ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr));
}
void AirportItlwm::setGTK(const u_int8_t *gtk, size_t key_len, u_int8_t kid, u_int8_t *rsc) {
struct ieee80211com *ic = fHalService->get80211Controller();
struct ieee80211_node * ni = ic->ic_bss;
struct ieee80211_key *k;
int keylen;
if (gtk != NULL) {
/* check that key length matches that of group cipher */
keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher);
if (key_len != keylen) {
XYLog("GTK length mismatch. expected %d, got %zu\n", keylen, key_len);
return;
}
/* map GTK to 802.11 key */
k = &ic->ic_nw_keys[kid];
if (k->k_cipher == IEEE80211_CIPHER_NONE || k->k_len != keylen || memcmp(k->k_key, gtk, keylen) != 0) {
memset(k, 0, sizeof(*k));
k->k_id = kid; /* 0-3 */
k->k_cipher = ni->ni_rsngroupcipher;
k->k_flags = IEEE80211_KEY_GROUP;
//if (gtk[6] & (1 << 2))
// k->k_flags |= IEEE80211_KEY_TX;
k->k_rsc[0] = LE_READ_6(rsc);
k->k_len = keylen;
memcpy(k->k_key, gtk, k->k_len);
/* install the GTK */
if ((*ic->ic_set_key)(ic, ni, k) != 0) {
XYLog("setting GTK failed\n");
return;
}
else
XYLog("setting GTK successfully\n");
}
}
if (true) {
ni->ni_flags |= IEEE80211_NODE_TXRXPROT;
#ifndef IEEE80211_STA_ONLY
if (ic->ic_opmode != IEEE80211_M_IBSS ||
++ni->ni_key_count == 2)
#endif
{
XYLog("marking port %s valid\n",
ether_sprintf(ni->ni_macaddr));
ni->ni_port_valid = 1;
ieee80211_set_link_state(ic, LINK_STATE_UP);
ni->ni_assoc_fail = 0;
if (ic->ic_opmode == IEEE80211_M_STA)
ic->ic_rsngroupcipher = ni->ni_rsngroupcipher;
}
}
}
bool AirportItlwm::
createMediumTables(const IONetworkMedium **primary)
{
IONetworkMedium *medium;
OSDictionary *mediumDict = OSDictionary::withCapacity(1);
if (mediumDict == NULL) {
XYLog("Cannot allocate OSDictionary\n");
return false;
}
medium = IONetworkMedium::medium(kIOMediumIEEE80211Auto, 11000000);
IONetworkMedium::addMedium(mediumDict, medium);
medium->release();
if (primary) {
*primary = medium;
}
bool result = publishMediumDictionary(mediumDict);
if (!result)
XYLog("Cannot publish medium dictionary!\n");
mediumDict->release();
return result;
}
bool AirportItlwm::start(IOService *provider)
{
int boot_value = 0;
if (!super::start(provider)) {
return false;
}
if (!serviceMatching("AppleSMC")) {
super::stop(provider);
XYLog("No matching AppleSMC dictionary, failing\n");
return false;
}
pciNub = OSDynamicCast(IOPCIDevice, provider);
if (!pciNub) {
super::stop(provider);
return false;
}
pciNub->setBusMasterEnable(true);
pciNub->setIOEnable(true);
pciNub->setMemoryEnable(true);
pciNub->configWrite8(0x41, 0);
if (pciNub->requestPowerDomainState(kIOPMPowerOn,
(IOPowerConnection *) getParentEntry(gIOPowerPlane), IOPMLowestState) != IOPMNoErr) {
super::stop(provider);
return false;
}
if (initPCIPowerManagment(pciNub) == false) {
super::stop(pciNub);
return false;
}
if (_fWorkloop == NULL) {
XYLog("No _fWorkloop!!\n");
super::stop(pciNub);
releaseAll();
return false;
}
_fCommandGate = IOCommandGate::commandGate(this, (IOCommandGate::Action)AirportItlwm::tsleepHandler);
if (_fCommandGate == 0) {
XYLog("No command gate!!\n");
super::stop(pciNub);
releaseAll();
return false;
}
_fWorkloop->addEventSource(_fCommandGate);
const IONetworkMedium *primaryMedium;
if (!createMediumTables(&primaryMedium) ||
!setCurrentMedium(primaryMedium) || !setSelectedMedium(primaryMedium)) {
XYLog("setup medium fail\n");
releaseAll();
return false;
}
fHalService->initWithController(this, _fWorkloop, _fCommandGate);
fHalService->get80211Controller()->ic_event_handler = eventHandler;
if (PE_parse_boot_argn("-novht", &boot_value, sizeof(boot_value)))
fHalService->get80211Controller()->ic_userflags |= IEEE80211_F_NOVHT;
if (PE_parse_boot_argn("-noht40", &boot_value, sizeof(boot_value)))
fHalService->get80211Controller()->ic_userflags |= IEEE80211_F_NOHT40;
if (!fHalService->attach(pciNub)) {
XYLog("attach fail\n");
super::stop(pciNub);
releaseAll();
return false;
}
if (!attachInterface((IONetworkInterface **)&fNetIf, true)) {
XYLog("attach to interface fail\n");
fHalService->detach(pciNub);
super::stop(pciNub);
releaseAll();
return false;
}
fWatchdogWorkLoop = IOWorkLoop::workLoop();
if (fWatchdogWorkLoop == NULL) {
XYLog("init watchdog workloop fail\n");
fHalService->detach(pciNub);
super::stop(pciNub);
releaseAll();
return false;
}
watchdogTimer = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &AirportItlwm::watchdogAction));
if (!watchdogTimer) {
XYLog("init watchdog fail\n");
fHalService->detach(pciNub);
super::stop(pciNub);
releaseAll();
return false;
}
fWatchdogWorkLoop->addEventSource(watchdogTimer);
scanSource = IOTimerEventSource::timerEventSource(this, &fakeScanDone);
_fWorkloop->addEventSource(scanSource);
scanSource->enable();
setLinkStatus(kIONetworkLinkValid);
if (TAILQ_EMPTY(&fHalService->get80211Controller()->ic_ess))
fHalService->get80211Controller()->ic_flags |= IEEE80211_F_AUTO_JOIN;
registerService();
fNetIf->registerService();
return true;
}
void AirportItlwm::watchdogAction(IOTimerEventSource *timer)
{
struct _ifnet *ifp = &fHalService->get80211Controller()->ic_ac.ac_if;
(*ifp->if_watchdog)(ifp);
watchdogTimer->setTimeoutMS(kWatchDogTimerPeriod);
}
void AirportItlwm::fakeScanDone(OSObject *owner, IOTimerEventSource *sender)
{
AirportItlwm *that = (AirportItlwm *)owner;
that->getNetworkInterface()->postMessage(APPLE80211_M_SCAN_DONE);
}
const OSString * AirportItlwm::newVendorString() const
{
return OSString::withCString("Apple");
}
const OSString * AirportItlwm::newModelString() const
{
return OSString::withCString(fHalService->getDriverInfo()->getFirmwareName());
}
bool AirportItlwm::initPCIPowerManagment(IOPCIDevice *provider)
{
UInt16 reg16;
reg16 = provider->configRead16(kIOPCIConfigCommand);
reg16 |= ( kIOPCICommandBusMaster |
kIOPCICommandMemorySpace |
kIOPCICommandMemWrInvalidate );
reg16 &= ~kIOPCICommandIOSpace; // disable I/O space
provider->configWrite16( kIOPCIConfigCommand, reg16 );
provider->findPCICapability(kIOPCIPowerManagementCapability,
&pmPCICapPtr);
if (pmPCICapPtr) {
UInt16 pciPMCReg = provider->configRead32( pmPCICapPtr ) >> 16;
if (pciPMCReg & kPCIPMCPMESupportFromD3Cold)
magicPacketSupported = true;
provider->configWrite16((pmPCICapPtr + 4), 0x8000 );
IOSleep(10);
}
return true;
}
bool AirportItlwm::createWorkLoop()
{
_fWorkloop = IO80211WorkLoop::workLoop();
return _fWorkloop != 0;
}
IOWorkLoop *AirportItlwm::getWorkLoop() const
{
return _fWorkloop;
}
IOReturn AirportItlwm::selectMedium(const IONetworkMedium *medium)
{
setSelectedMedium(medium);
return kIOReturnSuccess;
}
void AirportItlwm::stop(IOService *provider)
{
XYLog("%s\n", __FUNCTION__);
struct _ifnet *ifp = &fHalService->get80211Controller()->ic_ac.ac_if;
super::stop(provider);
disableAdapter(fNetIf);
setLinkStatus(kIONetworkLinkValid);
fHalService->detach(pciNub);
ether_ifdetach(ifp);
detachInterface(fNetIf, true);
OSSafeReleaseNULL(fNetIf);
releaseAll();
}
bool AirportItlwm::
setLinkStatus(UInt32 status, const IONetworkMedium * activeMedium, UInt64 speed, OSData * data)
{
struct _ifnet *ifq = &fHalService->get80211Controller()->ic_ac.ac_if;
if (status == currentStatus) {
return true;
}
bool ret = super::setLinkStatus(status, activeMedium, speed, data);
currentStatus = status;
if (fNetIf) {
if (status & kIONetworkLinkActive) {
#ifdef __PRIVATE_SPI__
fNetIf->startOutputThread();
#endif
getCommandGate()->runAction(setLinkStateGated, (void *)kIO80211NetworkLinkUp, (void *)0);
fNetIf->setLinkQualityMetric(100);
} else if (!(status & kIONetworkLinkNoNetworkChange)) {
#ifdef __PRIVATE_SPI__
fNetIf->stopOutputThread();
fNetIf->flushOutputQueue();
#endif
ifq_flush(&ifq->if_snd);
mq_purge(&fHalService->get80211Controller()->ic_mgtq);
getCommandGate()->runAction(setLinkStateGated, (void *)kIO80211NetworkLinkDown, (void *)fHalService->get80211Controller()->ic_deauth_reason);
}
}
return ret;
}
IOReturn AirportItlwm::
setLinkStateGated(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
{
AirportItlwm *that = OSDynamicCast(AirportItlwm, target);
IOReturn ret = that->getNetworkInterface()->setLinkState((IO80211LinkState)(uint64_t)arg0, (unsigned int)(uint64_t)arg1);
if (that->fAWDLInterface) {
#if __IO80211_TARGET >= __MAC_13_0
that->fAWDLInterface->setEnabledBySystem(true);
#endif
that->fAWDLInterface->setLinkState((IO80211LinkState)(uint64_t)arg0, (unsigned int)(uint64_t)arg1);
}
return ret;
}
void AirportItlwm::releaseAll()
{
if (fHalService) {
fHalService->release();
fHalService = NULL;
}
if (_fWorkloop) {
if (_fCommandGate) {
// _fCommandGate->disable();
_fWorkloop->removeEventSource(_fCommandGate);
_fCommandGate->release();
_fCommandGate = NULL;
}
if (scanSource) {
scanSource->cancelTimeout();
scanSource->disable();
_fWorkloop->removeEventSource(scanSource);
scanSource->release();
scanSource = NULL;
}
if (fWatchdogWorkLoop && watchdogTimer) {
watchdogTimer->cancelTimeout();
fWatchdogWorkLoop->removeEventSource(watchdogTimer);
watchdogTimer->release();
watchdogTimer = NULL;
fWatchdogWorkLoop->release();
fWatchdogWorkLoop = NULL;
}
_fWorkloop->release();
_fWorkloop = NULL;
}
unregistPM();
}
void AirportItlwm::free()
{
XYLog("%s\n", __FUNCTION__);
if (fHalService != NULL) {
fHalService->release();
fHalService = NULL;
}
if (syncFrameTemplate != NULL && syncFrameTemplateLength > 0) {
IOFree(syncFrameTemplate, syncFrameTemplateLength);
syncFrameTemplateLength = 0;
syncFrameTemplate = NULL;
}
if (roamProfile != NULL) {
IOFree(roamProfile, sizeof(struct apple80211_roam_profile_band_data));
roamProfile = NULL;
}
if (btcProfile != NULL) {
IOFree(btcProfile, sizeof(struct apple80211_btc_profiles_data));
btcProfile = NULL;
}
super::free();
}
IOReturn AirportItlwm::enable(IONetworkInterface *netif)
{
XYLog("%s\n", __PRETTY_FUNCTION__);
super::enable(netif);
_fCommandGate->enable();
if (power_state)
enableAdapter(netif);
return kIOReturnSuccess;
}
IOReturn AirportItlwm::disable(IONetworkInterface *netif)
{
XYLog("%s\n", __PRETTY_FUNCTION__);
super::disable(netif);
setLinkStatus(kIONetworkLinkValid);
return kIOReturnSuccess;
}
IOReturn AirportItlwm::enableAdapter(IONetworkInterface *netif)
{
fHalService->enable(netif);
watchdogTimer->setTimeoutMS(kWatchDogTimerPeriod);
watchdogTimer->enable();
return kIOReturnSuccess;
}
void AirportItlwm::disableAdapter(IONetworkInterface *netif)
{
watchdogTimer->cancelTimeout();
watchdogTimer->disable();
fHalService->disable(netif);
}
IOReturn AirportItlwm::getHardwareAddress(IOEthernetAddress *addrP)
{
if (IEEE80211_ADDR_EQ(etheranyaddr, fHalService->get80211Controller()->ic_myaddr))
return kIOReturnError;
else {
IEEE80211_ADDR_COPY(addrP, fHalService->get80211Controller()->ic_myaddr);
return kIOReturnSuccess;
}
}
IOReturn AirportItlwm::setHardwareAddress(const IOEthernetAddress *addrP)
{
if (!fNetIf || !addrP)
return kIOReturnError;
if_setlladdr(&fHalService->get80211Controller()->ic_ac.ac_if, addrP->bytes);
if (fHalService->get80211Controller()->ic_state > IEEE80211_S_INIT) {
fHalService->disable(fNetIf);
fHalService->enable(fNetIf);
}
return kIOReturnSuccess;
}
IOReturn AirportItlwm::getHardwareAddressForInterface(
IO80211Interface *netif, IOEthernetAddress *addr)
{
return getHardwareAddress(addr);
}
#ifdef __PRIVATE_SPI__
IOReturn AirportItlwm::outputStart(IONetworkInterface *interface, IOOptionBits options)
{
struct _ifnet *ifp = &fHalService->get80211Controller()->ic_ac.ac_if;
mbuf_t m = NULL;
if (ifq_is_oactive(&ifp->if_snd))
return kIOReturnNoResources;
while (kIOReturnSuccess == interface->dequeueOutputPackets(1, &m)) {
if (outputPacket(m, NULL)!= kIOReturnOutputSuccess ||
ifq_is_oactive(&ifp->if_snd))
return kIOReturnNoResources;
}
return kIOReturnSuccess;
}
#endif
UInt32 AirportItlwm::outputPacket(mbuf_t m, void *param)
{
// XYLog("%s\n", __FUNCTION__);
IOReturn ret = kIOReturnOutputSuccess;
struct _ifnet *ifp = &fHalService->get80211Controller()->ic_ac.ac_if;
if (fHalService->get80211Controller()->ic_state != IEEE80211_S_RUN || ifp->if_snd.queue == NULL) {
if (m && mbuf_type(m) != MBUF_TYPE_FREE)
freePacket(m);
return kIOReturnOutputDropped;
}
if (m == NULL) {
XYLog("%s m==NULL!!\n", __FUNCTION__);
ifp->netStat->outputErrors++;
ret = kIOReturnOutputDropped;
}
if (!(mbuf_flags(m) & MBUF_PKTHDR) ){
XYLog("%s pkthdr is NULL!!\n", __FUNCTION__);
ifp->netStat->outputErrors++;
freePacket(m);
ret = kIOReturnOutputDropped;
}
if (mbuf_type(m) == MBUF_TYPE_FREE) {
XYLog("%s mbuf is FREE!!\n", __FUNCTION__);
ifp->netStat->outputErrors++;
ret = kIOReturnOutputDropped;
}
if (!ifp->if_snd.queue->lockEnqueue(m)) {
freePacket(m);
ret = kIOReturnOutputDropped;
}
(*ifp->if_start)(ifp);
return ret;
}
UInt32 AirportItlwm::getFeatures() const
{
return fHalService->getDriverInfo()->supportedFeatures();
}
IOReturn AirportItlwm::setPromiscuousMode(IOEnetPromiscuousMode mode)
{
return kIOReturnSuccess;
}
IOReturn AirportItlwm::setMulticastMode(IOEnetMulticastMode mode)
{
return kIOReturnSuccess;
}
IOReturn AirportItlwm::setMulticastList(IOEthernetAddress* addr, UInt32 len)
{
return fHalService->getDriverController()->setMulticastList(addr, len);
}
SInt32 AirportItlwm::monitorModeSetEnabled(
IO80211Interface *interface, bool enabled, UInt32 dlt)
{
return kIOReturnSuccess;
}
bool AirportItlwm::
useAppleRSNSupplicant(IO80211Interface *interface)
{
#ifdef USE_APPLE_SUPPLICANT
return true;
#else
return false;
#endif
}
IOReturn AirportItlwm::getPacketFilters(const OSSymbol *group, UInt32 *filters) const
{
IOReturn rtn = kIOReturnSuccess;
if (group == gIOEthernetWakeOnLANFilterGroup && magicPacketSupported)
*filters = kIOEthernetWakeOnMagicPacket;
else if (group == gIONetworkFilterGroup)
*filters = kIOPacketFilterMulticast | kIOPacketFilterPromiscuous;
else
rtn = IOEthernetController::getPacketFilters(group, filters);
return rtn;
}
IOReturn AirportItlwm::
tsleepHandler(OSObject* owner, void* arg0, void* arg1, void* arg2, void* arg3)
{
AirportItlwm* dev = OSDynamicCast(AirportItlwm, owner);
if (dev == 0)
return kIOReturnError;
if (arg1 == 0) {
if (_fCommandGate->commandSleep(arg0, THREAD_INTERRUPTIBLE) == THREAD_AWAKENED)
return kIOReturnSuccess;
else
return kIOReturnTimeout;
} else {
AbsoluteTime deadline;
clock_interval_to_deadline((*(int*)arg1), kNanosecondScale, reinterpret_cast<uint64_t*> (&deadline));
if (_fCommandGate->commandSleep(arg0, deadline, THREAD_INTERRUPTIBLE) == THREAD_AWAKENED)
return kIOReturnSuccess;
else
return kIOReturnTimeout;
}
}
static IOPMPowerState powerStateArray[kPowerStateCount] =
{
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, kIOPMDeviceUsable, kIOPMPowerOn, kIOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0}
};
void AirportItlwm::unregistPM()
{
if (powerOffThreadCall) {
thread_call_free(powerOffThreadCall);
powerOffThreadCall = NULL;
}
if (powerOnThreadCall) {
thread_call_free(powerOnThreadCall);
powerOnThreadCall = NULL;
}
}
IOReturn AirportItlwm::setPowerState(unsigned long powerStateOrdinal, IOService *policyMaker)
{
IOReturn result = IOPMAckImplied;
if (pmPowerState == powerStateOrdinal)
return result;
switch (powerStateOrdinal) {
case kPowerStateOff:
if (powerOffThreadCall) {
retain();
if (thread_call_enter(powerOffThreadCall))
release();
result = 5000000;
}
break;
case kPowerStateOn:
if (powerOnThreadCall) {
retain();
if (thread_call_enter(powerOnThreadCall))
release();
result = 5000000;
}
break;
default:
break;
}
return result;
}
IOReturn AirportItlwm::setWakeOnMagicPacket(bool active)
{
magicPacketEnabled = active;
return kIOReturnSuccess;
}
static void handleSetPowerStateOff(thread_call_param_t param0,
thread_call_param_t param1)
{
AirportItlwm *self = (AirportItlwm *)param0;
if (param1 == 0)
{
self->getCommandGate()->runAction((IOCommandGate::Action)
handleSetPowerStateOff,
(void *) 1);
}
else
{
self->setPowerStateOff();
self->release();
}
}
static void handleSetPowerStateOn(thread_call_param_t param0,
thread_call_param_t param1)
{
AirportItlwm *self = (AirportItlwm *) param0;
if (param1 == 0)
{
self->getCommandGate()->runAction((IOCommandGate::Action)
handleSetPowerStateOn,
(void *) 1);
}
else
{
self->setPowerStateOn();
self->release();
}
}
IOReturn AirportItlwm::registerWithPolicyMaker(IOService *policyMaker)
{
IOReturn ret;
pmPowerState = kPowerStateOn;
pmPolicyMaker = policyMaker;
powerOffThreadCall = thread_call_allocate(
(thread_call_func_t)handleSetPowerStateOff,
(thread_call_param_t)this);
powerOnThreadCall = thread_call_allocate(
(thread_call_func_t)handleSetPowerStateOn,
(thread_call_param_t)this);
ret = pmPolicyMaker->registerPowerDriver(this,
powerStateArray,
kPowerStateCount);
return ret;
}
void AirportItlwm::setPowerStateOff()
{
XYLog("%s\n", __FUNCTION__);
pmPowerState = kPowerStateOff;
disableAdapter(fNetIf);
pmPolicyMaker->acknowledgeSetPowerState();
}
void AirportItlwm::setPowerStateOn()
{
XYLog("%s\n", __FUNCTION__);
pmPowerState = kPowerStateOn;
pmPolicyMaker->acknowledgeSetPowerState();
}
int AirportItlwm::
outputRaw80211Packet(IO80211Interface *interface, mbuf_t m)
{
XYLog("%s len=%zu\n", __FUNCTION__, mbuf_len(m));
freePacket(m);
return kIOReturnOutputDropped;
}
UInt32 AirportItlwm::
hardwareOutputQueueDepth(IO80211Interface *interface)
{
return 0;
}
SInt32 AirportItlwm::
performCountryCodeOperation(IO80211Interface *interface, IO80211CountryCodeOp op)
{
return 0;
}
SInt32 AirportItlwm::
stopDMA()
{
if (fNetIf)
disable(fNetIf);
return 0;
}
SInt32 AirportItlwm::
enableFeature(IO80211FeatureCode code, void *data)
{
if (code == kIO80211Feature80211n) {
return 0;
}
return 102;
}
int AirportItlwm::
outputActionFrame(OSObject *object, mbuf_t m)
{
XYLog("%s len=%zu\n", __FUNCTION__, mbuf_len(m));
mbuf_freem(m);
return 0;
}
int AirportItlwm::
bpfOutput80211Radio(OSObject *object, mbuf_t m)
{
XYLog("%s len=%zu\n", __FUNCTION__, mbuf_len(m));
mbuf_freem(m);
return 0;
}
SInt32 AirportItlwm::
enableVirtualInterface(IO80211VirtualInterface *interface)
{
XYLog("%s interface=%s role=%d\n", __FUNCTION__, interface->getBSDName(), interface->getInterfaceRole());
SInt32 ret = super::enableVirtualInterface(interface);
if (!ret) {
#if __IO80211_TARGET >= __MAC_13_0
interface->setEnabledBySystem(true);
#endif
interface->setLinkState(kIO80211NetworkLinkUp, 0);
interface->postMessage(APPLE80211_M_LINK_CHANGED);
return kIOReturnSuccess;
}
return ret;
}
SInt32 AirportItlwm::
disableVirtualInterface(IO80211VirtualInterface *interface)
{
XYLog("%s interface=%s role=%d\n", __FUNCTION__, interface->getBSDName(), interface->getInterfaceRole());
SInt32 ret = super::disableVirtualInterface(interface);
if (!ret) {
interface->setLinkState(kIO80211NetworkLinkDown, 0);
interface->postMessage(APPLE80211_M_LINK_CHANGED);
return kIOReturnSuccess;
}
return ret;
}
IO80211VirtualInterface *AirportItlwm::
createVirtualInterface(ether_addr *ether, UInt role)
{
if (role - 1 > 3)
return super::createVirtualInterface(ether, role);
IO80211VirtualInterface *inf = new IO80211VirtualInterface;
if (inf) {
if (inf->init(this, ether, role, role == APPLE80211_VIF_AWDL ? "awdl" : "p2p"))
XYLog("%s role=%d succeed\n", __FUNCTION__, role);
else {
inf->release();
return NULL;
}
}
return inf;
}
int AirportItlwm::
bpfOutputPacket(OSObject *object, UInt dltType, mbuf_t m)
{
XYLog("%s dltType=%d\n", __FUNCTION__, dltType);
if (dltType == DLT_IEEE802_11_RADIO || dltType == DLT_IEEE802_11)
return bpfOutput80211Radio(object, m);
if (dltType == DLT_RAW)
return outputActionFrame(object, m);
mbuf_freem(m);
return 1;
}
void AirportItlwm::
requestPacketTx(void *object, UInt )
{
UInt32 ret;
struct TxPacketRequest request;
if (object == NULL)
return;
IO80211VirtualInterface *interface = OSDynamicCast(IO80211VirtualInterface, (OSObject *)object);
if (interface) {
memset(&request, 0, sizeof(request));
if (interface->getInterfaceRole() == APPLE80211_VIF_AWDL) {
// interface->dequeueTxPackets(&request);
//
// ret = outputPacket(NULL, interface);
// if (ret == kIOReturnSuccess) {
// interface->reportTransmitStatus(NULL, ret, NULL);
// }
}
}
}