Repository: OpenIntelWireless/itlwm Branch: master Commit: 53c51c2cdd6e Files: 246 Total size: 4.3 MB Directory structure: gitextract_w4xojz7w/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ └── Bug.md │ └── workflows/ │ └── main.yml ├── .gitignore ├── AirportItlwm/ │ ├── AirportAWDL.cpp │ ├── AirportItlwm-Monterey-Info.plist │ ├── AirportItlwm-Sonoma-Info.plist │ ├── AirportItlwm.cpp │ ├── AirportItlwm.hpp │ ├── AirportItlwmEthernetInterface.cpp │ ├── AirportItlwmEthernetInterface.hpp │ ├── AirportItlwmInterface.cpp │ ├── AirportItlwmInterface.hpp │ ├── AirportItlwmSkywalkInterface.cpp │ ├── AirportItlwmSkywalkInterface.hpp │ ├── AirportItlwmV2.cpp │ ├── AirportItlwmV2.hpp │ ├── AirportSTAIOCTL.cpp │ ├── AirportVirtualIOCTL.cpp │ ├── IOPCIEDeviceWrapper.cpp │ ├── IOPCIEDeviceWrapper.hpp │ └── Info.plist ├── LICENSE ├── README.md ├── include/ │ ├── Airport/ │ │ ├── Apple80211.h │ │ ├── CCDataPipe.h │ │ ├── CCLogPipe.h │ │ ├── CCLogStream.h │ │ ├── CCPipe.h │ │ ├── CCStream.h │ │ ├── IO80211Controller.h │ │ ├── IO80211ControllerV2.h │ │ ├── IO80211InfraInterface.h │ │ ├── IO80211InfraProtocol.h │ │ ├── IO80211Interface.h │ │ ├── IO80211P2PInterface.h │ │ ├── IO80211SkywalkInterface.h │ │ ├── IO80211VirtualInterface.h │ │ ├── IO80211WorkLoop.h │ │ ├── IO80211WorkQueue.h │ │ ├── IOSkywalkEthernetInterface.h │ │ ├── IOSkywalkInterface.h │ │ ├── IOSkywalkLegacyEthernetInterface.h │ │ ├── IOSkywalkLogicalLink.h │ │ ├── IOSkywalkNetworkInterface.h │ │ ├── IOSkywalkNetworkPacket.h │ │ ├── IOSkywalkPacketBufferPool.h │ │ ├── apple80211_ioctl.h │ │ ├── apple80211_var.h │ │ ├── apple80211_wps.h │ │ ├── apple_private_spi.h │ │ └── debug.h │ ├── ClientKit/ │ │ ├── Common.h │ │ └── IoctlId.h │ ├── FwData.h │ └── HAL/ │ ├── ItlDriverController.hpp │ ├── ItlDriverInfo.hpp │ ├── ItlHalService.cpp │ └── ItlHalService.hpp ├── itl80211/ │ ├── Info.plist │ ├── compat.cpp │ ├── compat.h │ ├── linux/ │ │ ├── bitfield.h │ │ ├── kernel.h │ │ ├── random.h │ │ └── types.h │ ├── openbsd/ │ │ ├── crypto/ │ │ │ ├── aes.c │ │ │ ├── aes.h │ │ │ ├── arc4.c │ │ │ ├── arc4.h │ │ │ ├── blf.c │ │ │ ├── blf.h │ │ │ ├── cast.c │ │ │ ├── cast.h │ │ │ ├── castsb.h │ │ │ ├── chacha_private.h │ │ │ ├── chachapoly.c │ │ │ ├── chachapoly.h │ │ │ ├── cmac.c │ │ │ ├── cmac.h │ │ │ ├── cryptodev.h │ │ │ ├── des_locl.h │ │ │ ├── ecb3_enc.c │ │ │ ├── ecb_enc.c │ │ │ ├── gmac.c │ │ │ ├── gmac.h │ │ │ ├── hmac.c │ │ │ ├── hmac.h │ │ │ ├── idgen.c │ │ │ ├── idgen.h │ │ │ ├── key_wrap.c │ │ │ ├── key_wrap.h │ │ │ ├── md5.c │ │ │ ├── md5.h │ │ │ ├── michael.c │ │ │ ├── michael.h │ │ │ ├── podd.h │ │ │ ├── poly1305.c │ │ │ ├── poly1305.h │ │ │ ├── rijndael.c │ │ │ ├── rijndael.h │ │ │ ├── rmd160.c │ │ │ ├── rmd160.h │ │ │ ├── set_key.c │ │ │ ├── sha1-pbkdf2.c │ │ │ ├── sha1.c │ │ │ ├── sha1.h │ │ │ ├── sha2.c │ │ │ ├── sha2.h │ │ │ ├── sk.h │ │ │ └── spr.h │ │ ├── net80211/ │ │ │ ├── CTimeout.cpp │ │ │ ├── _string.c │ │ │ ├── ieee80211.c │ │ │ ├── ieee80211.h │ │ │ ├── ieee80211_amrr.c │ │ │ ├── ieee80211_amrr.h │ │ │ ├── ieee80211_crypto.c │ │ │ ├── ieee80211_crypto.h │ │ │ ├── ieee80211_crypto_bip.c │ │ │ ├── ieee80211_crypto_ccmp.c │ │ │ ├── ieee80211_crypto_tkip.c │ │ │ ├── ieee80211_crypto_wep.c │ │ │ ├── ieee80211_input.c │ │ │ ├── ieee80211_ioctl.c │ │ │ ├── ieee80211_ioctl.h │ │ │ ├── ieee80211_mira.c │ │ │ ├── ieee80211_mira.h │ │ │ ├── ieee80211_node.c │ │ │ ├── ieee80211_node.h │ │ │ ├── ieee80211_output.c │ │ │ ├── ieee80211_pae_input.c │ │ │ ├── ieee80211_pae_output.c │ │ │ ├── ieee80211_priv.h │ │ │ ├── ieee80211_proto.c │ │ │ ├── ieee80211_proto.h │ │ │ ├── ieee80211_ra.c │ │ │ ├── ieee80211_ra.h │ │ │ ├── ieee80211_radiotap.h │ │ │ ├── ieee80211_regdomain.c │ │ │ ├── ieee80211_regdomain.h │ │ │ ├── ieee80211_rssadapt.c │ │ │ ├── ieee80211_rssadapt.h │ │ │ ├── ieee80211_var.h │ │ │ └── timeout.c │ │ └── sys/ │ │ ├── CTimeout.hpp │ │ ├── _arc4random.h │ │ ├── _buf.h │ │ ├── _clock.h │ │ ├── _if_ether.h │ │ ├── _if_media.h │ │ ├── _ifq.cpp │ │ ├── _ifq.h │ │ ├── _malloc.h │ │ ├── _mbuf.cpp │ │ ├── _mbuf.h │ │ ├── _netstat.h │ │ ├── _null.h │ │ ├── _task.cpp │ │ ├── _task.h │ │ ├── arp.c │ │ ├── arp.h │ │ ├── endian.h │ │ ├── pcireg.h │ │ ├── timeout.h │ │ └── tree.h │ ├── zutil.c │ └── zutil.h ├── itlwm/ │ ├── Info.plist │ ├── ItlNetworkUserClient.cpp │ ├── ItlNetworkUserClient.hpp │ ├── PrivateSPI.pch │ ├── firmware/ │ │ ├── iwlwifi-Qu-b0-hr-b0-68.ucode │ │ ├── iwlwifi-Qu-b0-jf-b0-68.ucode │ │ ├── iwlwifi-Qu-c0-hr-b0-68.ucode │ │ ├── iwlwifi-Qu-c0-jf-b0-68.ucode │ │ ├── iwlwifi-QuZ-a0-hr-b0-68.ucode │ │ ├── iwlwifi-QuZ-a0-jf-b0-68.ucode │ │ ├── iwlwifi-cc-a0-68.ucode │ │ ├── iwlwifi-so-a0-gf-a0-68.ucode │ │ ├── iwlwifi-so-a0-gf-a0.pnvm │ │ ├── iwlwifi-so-a0-gf4-a0-68.ucode │ │ ├── iwlwifi-so-a0-gf4-a0.pnvm │ │ ├── iwlwifi-so-a0-hr-b0-68.ucode │ │ ├── iwlwifi-so-a0-jf-b0-68.ucode │ │ ├── iwlwifi-ty-a0-gf-a0-68.ucode │ │ ├── iwlwifi-ty-a0-gf-a0.pnvm │ │ ├── iwm-3160-17 │ │ ├── iwm-3168-29 │ │ ├── iwm-7260-17 │ │ ├── iwm-7265-17 │ │ ├── iwm-8000C-36 │ │ ├── iwm-8265-36 │ │ ├── iwm-9000-46 │ │ ├── iwm-9260-46 │ │ ├── iwn-1000 │ │ ├── iwn-105 │ │ ├── iwn-135 │ │ ├── iwn-2000 │ │ ├── iwn-2030 │ │ ├── iwn-4965 │ │ ├── iwn-5000 │ │ ├── iwn-5150 │ │ ├── iwn-6000 │ │ ├── iwn-6005 │ │ ├── iwn-6030 │ │ └── iwn-6050 │ ├── hal_iwm/ │ │ ├── ItlIwm.cpp │ │ ├── ItlIwm.hpp │ │ ├── coex.cpp │ │ ├── ctxt.cpp │ │ ├── fw.cpp │ │ ├── hw.cpp │ │ ├── if_iwmreg.h │ │ ├── if_iwmvar.h │ │ ├── io.cpp │ │ ├── itlhdr.h │ │ ├── led.cpp │ │ ├── mac80211.cpp │ │ ├── nvm.cpp │ │ ├── phy.cpp │ │ ├── power.cpp │ │ ├── rs.cpp │ │ ├── rs.h │ │ ├── rx.cpp │ │ ├── scan.cpp │ │ ├── tx.cpp │ │ └── utils.cpp │ ├── hal_iwn/ │ │ ├── ItlIwn.cpp │ │ ├── ItlIwn.hpp │ │ ├── if_iwnreg.h │ │ └── if_iwnvar.h │ ├── hal_iwx/ │ │ ├── ItlIwx.cpp │ │ ├── ItlIwx.hpp │ │ ├── if_iwxreg.h │ │ └── if_iwxvar.h │ ├── itlwm.cpp │ ├── itlwm.hpp │ └── pm.cpp ├── itlwm.xcodeproj/ │ ├── project.pbxproj │ └── xcshareddata/ │ └── xcschemes/ │ ├── AirportItlwm (all).xcscheme │ └── itlwm.xcscheme ├── iwlwifi-firmware-license └── scripts/ ├── fw_gen.sh ├── load.sh ├── unload.sh └── zlib_compress_fw.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/Bug.md ================================================ --- name: Bug report about: Report a bug labels: '' assignees: '' --- **Have You Read Our Docs** **Are You Reporting A Bug** **Environment** - Kext Version: - WiFi Card Model: - PCI Product ID: - macOS Version: **Description** **Bug Report Archive** **Kext Download Source** ================================================ FILE: .github/workflows/main.yml ================================================ name: CD on: push: branches: master env: BUILD_OUTPUT: 'build/Build/Products/Debug' jobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v2 with: fetch-depth: '5' - name: Manage Version run: | git fetch --prune --unshallow --tags GIT_SHA="$(git rev-parse --short HEAD)" CUR_TAG="$(git tag -l | grep 'alpha\|beta' | tail -1)" eval $(grep -m 1 "MODULE_VERSION =" itlwm.xcodeproj/project.pbxproj | tr -d ';' | tr -d '\t' | tr -d " ") echo "SHORT_SHA=$GIT_SHA" >> $GITHUB_ENV echo "ITLWM_VER=$MODULE_VERSION" >> $GITHUB_ENV if [[ -z $CUR_TAG ]]; then echo "OLD_PRE_TAG=NULL" >> $GITHUB_ENV else echo "OLD_PRE_TAG=$CUR_TAG" >> $GITHUB_ENV fi - name: Install MacKernelSDK run: | git clone --depth=1 https://github.com/acidanthera/MacKernelSDK.git - name: Build itlwm run: | xcodebuild -scheme itlwm -configuration Debug -derivedDataPath build GIT_COMMIT=_${SHORT_SHA} | xcpretty && exit ${PIPESTATUS[0]} - name: Build AirportItlwm run: | xcodebuild -scheme "AirportItlwm (all)" -configuration Debug -derivedDataPath build GIT_COMMIT=_${SHORT_SHA} | xcpretty && exit ${PIPESTATUS[0]} - name: Pack Artifacts run: | cd $BUILD_OUTPUT zip -r itlwm-v${ITLWM_VER}-DEBUG-alpha-${SHORT_SHA}.zip itlwm.kext while read -r tgt ; do zip -r AirportItlwm-${tgt// /_}-v${ITLWM_VER}-DEBUG-alpha-${SHORT_SHA}.zip "$tgt" done < <(find . -mindepth 1 -maxdepth 1 -type d -not -path "*.kext" | cut -c 3-) cd - - name: Generate Prerelease Release Notes run: | echo '### Disclaimer:' >> ReleaseNotes.md echo '***This alpha version is for testing only.***' >> ReleaseNotes.md echo 'It is not ready for daily use and we do not guarantee its usability.' >> ReleaseNotes.md echo 'If you discovered an issue and you do not have debugging skills, please check with the [Gitter Chat Room](https://gitter.im/OpenIntelWireless/itlwm) in advance before opening an Issue.' >> ReleaseNotes.md echo '### The latest five updates are:' >> ReleaseNotes.md git log -"5" --format="- %H %s" | sed '/^$/d' >> ReleaseNotes.md - name: Delete Old Prerelease uses: dev-drprasad/delete-tag-and-release@v0.2.1 with: tag_name: ${{ env.OLD_PRE_TAG }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Publish GitHub Release if: contains(github.event.head_commit.message, 'Bump version') == false uses: ncipollo/release-action@v1.12.0 with: prerelease: true bodyFile: ReleaseNotes.md artifacts: "${{ env.BUILD_OUTPUT }}/*.zip" tag: "v${{ env.ITLWM_VER }}-alpha" token: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .gitignore ================================================ .DS_Store DerivedData build xcuserdata project.xcworkspace FwBinary.cpp *.pyc MacKernelSDK ================================================ FILE: AirportItlwm/AirportAWDL.cpp ================================================ // // AirportAWDL.cpp // AirportItlwm // // Created by qcwap on 2020/9/4. // Copyright © 2020 钟先耀. All rights reserved. // #include "AirportItlwm.hpp" #include #include #define INTERFACE_NAME(object) \ OSDynamicCast(IO80211Interface, object) == nullptr ? (OSDynamicCast(IO80211P2PInterface, object) == nullptr ? "???" : OSDynamicCast(IO80211P2PInterface, object)->getBSDName()) : OSDynamicCast(IO80211Interface, object)->getBSDName() IOReturn AirportItlwm:: getIE(OSObject *object, struct apple80211_ie_data *data) { XYLog("%s %s Error\n", __FUNCTION__, INTERFACE_NAME(object)); return kIOReturnError; } IOReturn AirportItlwm:: setIE(OSObject *object, struct apple80211_ie_data *data) { XYLog("%s %s frame_type_flags %x add %d signature_len %d ie_len %d\n", __FUNCTION__, INTERFACE_NAME(object), data->frame_type_flags, data->add, data->signature_len, data->ie_len); if (data->frame_type_flags == APPLE80211_IE_FLAG_ASSOC_REQ && data->add && data->ie_len && *(uint8_t*)data->ie == 68) { XYLog("%s setCustomAssocIE\n", __FUNCTION__); return kIOReturnSuccess; } return kIOReturnSuccess; } IOReturn AirportItlwm:: setP2P_SCAN(OSObject *object, struct apple80211_scan_data *data) { XYLog("%s %s ssid=%s bssid=%s channel=%d phy_mode=%d scan_type=%d\n", __FUNCTION__, INTERFACE_NAME(object), data->ssid, ether_sprintf(data->bssid.octet), data->num_channels, data->phy_mode, data->scan_type); return kIOReturnSuccess; } IOReturn AirportItlwm:: setP2P_LISTEN(OSObject *object, struct apple80211_p2p_listen_data *data) { XYLog("%s %s channel=%d pad1=%d flags=%d duration=%d\n", __FUNCTION__, INTERFACE_NAME(object), data->channel, data->pad1, data->flags, data->duration); return kIOReturnSuccess; } IOReturn AirportItlwm:: setP2P_GO_CONF(OSObject *object, struct apple80211_p2p_go_conf_data *data) { XYLog("%s %s auth_upper=%d auth_lower=%d channel=%d bcn_len=%d ssid=%s suppress_beacon=%d\n", __FUNCTION__, INTERFACE_NAME(object), data->auth_upper, data->auth_lower, data->channel, data->bcn_len, data->ssid, data->suppress_beacon); return kIOReturnSuccess; } ================================================ FILE: AirportItlwm/AirportItlwm-Monterey-Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString $(MODULE_VERSION) CFBundleVersion $(MODULE_VERSION) IOKitPersonalities itlwm CFBundleIdentifier com.zxystd.AirportItlwm IOClass AirportItlwm IOMatchCategory IODefaultMatchCategory IOPCIMatch 0x27238086 0x43F08086 0xA0F08086 0x34F08086 0x4DF08086 0x02F08086 0x3DF08086 0x06F08086 0x27208086 0x08b18086 0x08b28086 0x08b38086 0x08b48086 0x095a8086 0x095b8086 0x31658086 0x31668086 0x24f38086 0x24f48086 0x24f58086 0x24f68086 0x24fb8086 0x24fd8086 0x25268086 0x9df08086 0xa3708086 0x31DC8086 0x30DC8086 0x271C8086 0x271B8086 0x42a48086 0x00a08086 0x00a48086 0x02a08086 0x40a48086 0x00608086 0x00648086 0x02608086 0x02648086 0x42298086 0x422b8086 0x422c8086 0x42308086 0x42328086 0x42358086 0x42368086 0x42378086 0x42388086 0x42398086 0x423a8086 0x423b8086 0x423c8086 0x423d8086 0x00828086 0x00838086 0x00848086 0x00858086 0x00878086 0x00898086 0x008a8086 0x008b8086 0x00908086 0x00918086 0x08928086 0x08938086 0x08948086 0x08958086 0x08968086 0x08978086 0x08ae8086 0x08af8086 0x088e8086 0x088f8086 0x08908086 0x08918086 0x08878086 0x08888086 0x27258086 0x27268086 0x7A708086 0x7AF08086 0x51F08086 0x54F08086 0x27298086 0x7E408086 0x7F708086 0x51F18086 IOProbeScore 2000 IOProviderClass IOPCIDevice NSHumanReadableCopyright Copyright © 2020 钟先耀. All rights reserved. OSBundleLibraries com.apple.iokit.IO80211FamilyLegacy 600.0 com.apple.iokit.IONetworkingFamily 3.2 com.apple.iokit.IOPCIFamily 2.9 com.apple.kpi.bsd 16.7 com.apple.kpi.iokit 16.7 com.apple.kpi.libkern 16.7 com.apple.kpi.mach 16.7 OSBundleRequired Network-Root ================================================ FILE: AirportItlwm/AirportItlwm-Sonoma-Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString $(MODULE_VERSION) CFBundleVersion $(MODULE_VERSION) IOKitPersonalities NetworkController CFBundleIdentifier com.zxystd.AirportItlwm IOClass AirportItlwm IOMatchCategory WiFiDriver IONetworkRootType airport IOProbeScore 70000 IOProviderClass IOPCIEDeviceWrapper IOResourceMatch IOBSD itlwm CFBundleIdentifier com.zxystd.AirportItlwm IOClass IOPCIEDeviceWrapper IOPCIMatch 0x27238086 0x43F08086 0xA0F08086 0x34F08086 0x4DF08086 0x02F08086 0x3DF08086 0x06F08086 0x27208086 0x08b18086 0x08b28086 0x08b38086 0x08b48086 0x095a8086 0x095b8086 0x31658086 0x31668086 0x24f38086 0x24f48086 0x24f58086 0x24f68086 0x24fb8086 0x24fd8086 0x25268086 0x9df08086 0xa3708086 0x31DC8086 0x30DC8086 0x271C8086 0x271B8086 0x42a48086 0x00a08086 0x00a48086 0x02a08086 0x40a48086 0x00608086 0x00648086 0x02608086 0x02648086 0x42298086 0x422b8086 0x422c8086 0x42308086 0x42328086 0x42358086 0x42368086 0x42378086 0x42388086 0x42398086 0x423a8086 0x423b8086 0x423c8086 0x423d8086 0x00828086 0x00838086 0x00848086 0x00858086 0x00878086 0x00898086 0x008a8086 0x008b8086 0x00908086 0x00918086 0x08928086 0x08938086 0x08948086 0x08958086 0x08968086 0x08978086 0x08ae8086 0x08af8086 0x088e8086 0x088f8086 0x08908086 0x08918086 0x08878086 0x08888086 0x27258086 0x27268086 0x7A708086 0x7AF08086 0x51F08086 0x54F08086 0x27298086 0x7E408086 0x7F708086 0x51F18086 IOProbeScore 70000 IOProviderClass IOPCIDevice NSHumanReadableCopyright Copyright © 2020 钟先耀. All rights reserved. OSBundleLibraries com.apple.driver.corecapture 1.0.0 com.apple.iokit.IO80211Family 1.5.0 com.apple.iokit.IONetworkingFamily 3.2 com.apple.iokit.IOPCIFamily 2.9 com.apple.iokit.IOSkywalkFamily 1.0 com.apple.kpi.bsd 16.7 com.apple.kpi.iokit 16.7 com.apple.kpi.libkern 16.7 com.apple.kpi.mach 16.7 OSBundleRequired Network-Root ================================================ FILE: AirportItlwm/AirportItlwm.cpp ================================================ /* * 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 #include #include #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); } IOService* AirportItlwm::probe(IOService *provider, SInt32 *score) { bool isMatch = false; 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(0x80, 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 (&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); // } } } } ================================================ FILE: AirportItlwm/AirportItlwm.hpp ================================================ /* * 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 "Apple80211.h" #include "IOKit/network/IOGatedOutputQueue.h" #include #include #include #include #include #include #include #include "ItlIwm.hpp" #include "ItlIwx.hpp" #include "ItlIwn.hpp" #include "AirportItlwmInterface.hpp" enum { kPowerStateOff = 0, kPowerStateOn, kPowerStateCount }; #define kWatchDogTimerPeriod 1000 class AirportItlwm : public IO80211Controller { OSDeclareDefaultStructors(AirportItlwm) #define IOCTL(REQ_TYPE, REQ, DATA_TYPE) \ if (REQ_TYPE == SIOCGA80211) { \ ret = get##REQ(interface, (struct DATA_TYPE* )data); \ } else { \ ret = set##REQ(interface, (struct DATA_TYPE* )data); \ } #define IOCTL_GET(REQ_TYPE, REQ, DATA_TYPE) \ if (REQ_TYPE == SIOCGA80211) { \ ret = get##REQ(interface, (struct DATA_TYPE* )data); \ } #define IOCTL_SET(REQ_TYPE, REQ, DATA_TYPE) \ if (REQ_TYPE == SIOCSA80211) { \ ret = set##REQ(interface, (struct DATA_TYPE* )data); \ } #define FUNC_IOCTL(REQ, DATA_TYPE) \ FUNC_IOCTL_GET(REQ, DATA_TYPE) \ FUNC_IOCTL_SET(REQ, DATA_TYPE) #define FUNC_IOCTL_GET(REQ, DATA_TYPE) \ IOReturn get##REQ(OSObject *object, struct DATA_TYPE *data); #define FUNC_IOCTL_SET(REQ, DATA_TYPE) \ IOReturn set##REQ(OSObject *object, struct DATA_TYPE *data); public: virtual bool init(OSDictionary *properties) override; virtual void free() override; virtual IOService* probe(IOService* provider, SInt32* score) override; virtual bool start(IOService *provider) override; virtual void stop(IOService *provider) override; virtual IOReturn getHardwareAddress(IOEthernetAddress* addrP) override; virtual IOReturn setHardwareAddress(const IOEthernetAddress * addrP) override; virtual IOReturn enable(IONetworkInterface *netif) override; virtual IOReturn disable(IONetworkInterface *netif) override; virtual UInt32 outputPacket(mbuf_t, void * param) override; virtual IOReturn setPromiscuousMode(IOEnetPromiscuousMode mode) override; virtual IOReturn setMulticastMode(IOEnetMulticastMode mode) override; virtual IOReturn setMulticastList(IOEthernetAddress* addr, UInt32 len) override; virtual bool configureInterface(IONetworkInterface *netif) override; virtual bool createWorkLoop() override; virtual IOWorkLoop* getWorkLoop() const override; virtual const OSString * newVendorString() const override; virtual const OSString * newModelString() const override; virtual IONetworkInterface * createInterface() override; virtual bool setLinkStatus( UInt32 status, const IONetworkMedium * activeMedium = 0, UInt64 speed = 0, OSData * data = 0) override; static IOReturn setLinkStateGated(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); #ifdef __PRIVATE_SPI__ virtual IOReturn outputStart(IONetworkInterface *interface, IOOptionBits options) override; #endif void releaseAll(); void 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); void setPTK(const u_int8_t *key, size_t key_len); void setGTK(const u_int8_t *key, size_t key_len, u_int8_t kid, u_int8_t *rsc); void watchdogAction(IOTimerEventSource *timer); bool initPCIPowerManagment(IOPCIDevice *provider); static IOReturn tsleepHandler(OSObject* owner, void* arg0 = 0, void* arg1 = 0, void* arg2 = 0, void* arg3 = 0); static void eventHandler(struct ieee80211com *, int, void *); IOReturn enableAdapter(IONetworkInterface *netif); void disableAdapter(IONetworkInterface *netif); //IO80211 virtual IOReturn getHardwareAddressForInterface(IO80211Interface* netif, IOEthernetAddress* addr) override; virtual SInt32 monitorModeSetEnabled(IO80211Interface* interface, bool enabled, UInt32 dlt) override; virtual SInt32 apple80211Request(unsigned int request_type, int request_number, IO80211Interface* interface, void* data) override; //scan static void fakeScanDone(OSObject *owner, IOTimerEventSource *sender); //authentication virtual bool useAppleRSNSupplicant(IO80211Interface *interface) override; virtual int outputRaw80211Packet(IO80211Interface *interface, mbuf_t m) override; //virtual interface virtual SInt32 enableVirtualInterface(IO80211VirtualInterface *interface) override; virtual SInt32 disableVirtualInterface(IO80211VirtualInterface *interface) override; virtual IO80211VirtualInterface* createVirtualInterface(ether_addr *eth,uint role) override; virtual SInt32 apple80211VirtualRequest(uint request_type, int request_number,IO80211VirtualInterface *interface,void *data) override; virtual SInt32 stopDMA() override; virtual UInt32 hardwareOutputQueueDepth(IO80211Interface* interface) override; virtual SInt32 performCountryCodeOperation(IO80211Interface* interface, IO80211CountryCodeOp op) override; virtual SInt32 enableFeature(IO80211FeatureCode code, void* data) override; virtual void requestPacketTx(void*, UInt) override; virtual int bpfOutputPacket(OSObject *,UInt,mbuf_t) override; int outputActionFrame(OSObject *, mbuf_t m); int bpfOutput80211Radio(OSObject *, mbuf_t m); //AirportSTAIOCTL FUNC_IOCTL(SSID, apple80211_ssid_data) FUNC_IOCTL(AUTH_TYPE, apple80211_authtype_data) FUNC_IOCTL(CHANNEL, apple80211_channel_data) FUNC_IOCTL(PROTMODE, apple80211_protmode_data) FUNC_IOCTL_GET(TXPOWER, apple80211_txpower_data) FUNC_IOCTL_GET(RATE, apple80211_rate_data) FUNC_IOCTL(BSSID, apple80211_bssid_data) FUNC_IOCTL_SET(SCAN_REQ, apple80211_scan_data) FUNC_IOCTL_SET(SCAN_REQ_MULTIPLE, apple80211_scan_multiple_data) FUNC_IOCTL_GET(SCAN_RESULT, apple80211_scan_result*) FUNC_IOCTL_GET(CARD_CAPABILITIES, apple80211_capability_data) FUNC_IOCTL_GET(STATE, apple80211_state_data) FUNC_IOCTL_GET(PHY_MODE, apple80211_phymode_data) FUNC_IOCTL_GET(OP_MODE, apple80211_opmode_data) FUNC_IOCTL_GET(RSSI, apple80211_rssi_data) FUNC_IOCTL_GET(NOISE, apple80211_noise_data) FUNC_IOCTL_GET(INT_MIT, apple80211_intmit_data) FUNC_IOCTL(POWER, apple80211_power_data) FUNC_IOCTL_SET(ASSOCIATE, apple80211_assoc_data) FUNC_IOCTL_GET(ASSOCIATE_RESULT, apple80211_assoc_result_data) IOReturn setDISASSOCIATE(OSObject *); FUNC_IOCTL_GET(RATE_SET, apple80211_rate_set_data) FUNC_IOCTL_GET(MCS_INDEX_SET, apple80211_mcs_index_set_data) FUNC_IOCTL_GET(VHT_MCS_INDEX_SET, apple80211_vht_mcs_index_set_data) FUNC_IOCTL(MCS_VHT, apple80211_mcs_vht_data) FUNC_IOCTL_GET(SUPPORTED_CHANNELS, apple80211_sup_channel_data) FUNC_IOCTL_GET(LOCALE, apple80211_locale_data) FUNC_IOCTL(DEAUTH, apple80211_deauth_data) FUNC_IOCTL_GET(TX_ANTENNA, apple80211_antenna_data) FUNC_IOCTL_GET(ANTENNA_DIVERSITY, apple80211_antenna_data) FUNC_IOCTL_GET(DRIVER_VERSION, apple80211_version_data) FUNC_IOCTL_GET(HARDWARE_VERSION, apple80211_version_data) FUNC_IOCTL(RSN_IE, apple80211_rsn_ie_data) FUNC_IOCTL_GET(AP_IE_LIST, apple80211_ap_ie_data) FUNC_IOCTL_GET(LINK_CHANGED_EVENT_DATA, apple80211_link_changed_event_data) FUNC_IOCTL_GET(ASSOCIATION_STATUS, apple80211_assoc_status_data) FUNC_IOCTL(COUNTRY_CODE, apple80211_country_code_data) FUNC_IOCTL_GET(RADIO_INFO, apple80211_radio_info_data) FUNC_IOCTL_GET(MCS, apple80211_mcs_data) FUNC_IOCTL_SET(VIRTUAL_IF_CREATE, apple80211_virt_if_create_data) FUNC_IOCTL_SET(VIRTUAL_IF_DELETE, apple80211_virt_if_delete_data) FUNC_IOCTL_GET(ROAM_THRESH, apple80211_roam_threshold_data) FUNC_IOCTL_GET(POWERSAVE, apple80211_powersave_data) FUNC_IOCTL_SET(CIPHER_KEY, apple80211_key) FUNC_IOCTL_SET(SCANCACHE_CLEAR, apple80211req) FUNC_IOCTL(TX_NSS, apple80211_tx_nss_data) FUNC_IOCTL_GET(NSS, apple80211_nss_data) FUNC_IOCTL_SET(ROAM, apple80211_sta_roam_data); //AirportVirtualIOCTL FUNC_IOCTL(AWDL_PEER_TRAFFIC_REGISTRATION, apple80211_awdl_peer_traffic_registration) FUNC_IOCTL(AWDL_ELECTION_METRIC, apple80211_awdl_election_metric) FUNC_IOCTL(SYNC_ENABLED, apple80211_awdl_sync_enabled) FUNC_IOCTL(SYNC_FRAME_TEMPLATE, apple80211_awdl_sync_frame_template) FUNC_IOCTL_GET(AWDL_HT_CAPABILITY, apple80211_ht_capability) FUNC_IOCTL_GET(AWDL_VHT_CAPABILITY, apple80211_vht_capability) //AWDL FUNC_IOCTL(AWDL_BSSID, apple80211_awdl_bssid) FUNC_IOCTL_GET(CHANNELS_INFO, apple80211_channels_info) FUNC_IOCTL(PEER_CACHE_MAXIMUM_SIZE, apple80211_peer_cache_maximum_size) FUNC_IOCTL(AWDL_ELECTION_ID, apple80211_awdl_election_id) FUNC_IOCTL(AWDL_MASTER_CHANNEL, apple80211_awdl_master_channel) FUNC_IOCTL(AWDL_SECONDARY_MASTER_CHANNEL, apple80211_awdl_secondary_master_channel) FUNC_IOCTL(AWDL_MIN_RATE, apple80211_awdl_min_rate) FUNC_IOCTL(AWDL_ELECTION_RSSI_THRESHOLDS, apple80211_awdl_election_rssi_thresholds) FUNC_IOCTL(AWDL_SYNCHRONIZATION_CHANNEL_SEQUENCE, apple80211_awdl_sync_channel_sequence) FUNC_IOCTL(AWDL_PRESENCE_MODE, apple80211_awdl_presence_mode) FUNC_IOCTL(AWDL_EXTENSION_STATE_MACHINE_PARAMETERS, apple80211_awdl_extension_state_machine_parameter) FUNC_IOCTL(AWDL_SYNC_STATE, apple80211_awdl_sync_state) FUNC_IOCTL(AWDL_SYNC_PARAMS, apple80211_awdl_sync_params) FUNC_IOCTL_GET(AWDL_CAPABILITIES, apple80211_awdl_cap) FUNC_IOCTL(AWDL_AF_TX_MODE, apple80211_awdl_af_tx_mode) FUNC_IOCTL_SET(AWDL_OOB_AUTO_REQUEST, apple80211_awdl_oob_request) FUNC_IOCTL(ROAM_PROFILE, apple80211_roam_profile_band_data) FUNC_IOCTL(WOW_PARAMETERS, apple80211_wow_parameter_data) FUNC_IOCTL(IE, apple80211_ie_data) FUNC_IOCTL_SET(P2P_SCAN, apple80211_scan_data) FUNC_IOCTL_SET(P2P_LISTEN, apple80211_p2p_listen_data) FUNC_IOCTL_SET(P2P_GO_CONF, apple80211_p2p_go_conf_data) FUNC_IOCTL(BTCOEX_PROFILES, apple80211_btc_profiles_data) FUNC_IOCTL(BTCOEX_CONFIG, apple80211_btc_config_data) FUNC_IOCTL(BTCOEX_OPTIONS, apple80211_btc_options_data) FUNC_IOCTL(BTCOEX_MODE, apple80211_btc_mode_data) //----------------------------------------------------------------------- // Power management support. //----------------------------------------------------------------------- virtual IOReturn registerWithPolicyMaker( IOService * policyMaker ) override; virtual IOReturn setPowerState( unsigned long powerStateOrdinal, IOService * policyMaker) override; virtual IOReturn setWakeOnMagicPacket( bool active ) override; void setPowerStateOff(void); void setPowerStateOn(void); void unregistPM(); bool createMediumTables(const IONetworkMedium **primary); virtual IOReturn getPacketFilters(const OSSymbol *group, UInt32 *filters) const override; virtual IOReturn selectMedium(const IONetworkMedium *medium) override; virtual UInt32 getFeatures() const override; public: IOInterruptEventSource* fInterrupt; IOTimerEventSource *watchdogTimer; IOPCIDevice *pciNub; IONetworkStats *fpNetStats; AirportItlwmInterface *fNetIf; IOWorkLoop *fWatchdogWorkLoop; ItlHalService *fHalService; //pm thread_call_t powerOnThreadCall; thread_call_t powerOffThreadCall; UInt32 pmPowerState; IOService *pmPolicyMaker; UInt8 pmPCICapPtr; bool magicPacketEnabled; bool magicPacketSupported; //IO80211 uint8_t power_state; struct ieee80211_node *fNextNodeToSend; bool fScanResultWrapping; IOTimerEventSource *scanSource; u_int32_t current_authtype_lower; u_int32_t current_authtype_upper; UInt64 currentSpeed; UInt32 currentStatus; bool disassocIsVoluntary; char geo_location_cc[3]; IO80211P2PInterface *fP2PDISCInterface; IO80211P2PInterface *fP2PGOInterface; IO80211P2PInterface *fAWDLInterface; //AWDL uint8_t *syncFrameTemplate; uint32_t syncFrameTemplateLength; uint8_t awdlBSSID[6]; uint32_t awdlSyncState; uint32_t awdlElectionId; uint32_t awdlPresenceMode; uint16_t awdlMasterChannel; uint16_t awdlSecondaryMasterChannel; uint8_t *roamProfile; struct apple80211_btc_profiles_data *btcProfile; struct apple80211_btc_config_data btcConfig; uint32_t btcMode; uint32_t btcOptions; bool awdlSyncEnable; }; ================================================ FILE: AirportItlwm/AirportItlwmEthernetInterface.cpp ================================================ // // AirportItlwmEthernetInterface.cpp // AirportItlwm-Sonoma // // Created by qcwap on 2023/6/27. // Copyright © 2023 钟先耀. All rights reserved. // #include "AirportItlwmEthernetInterface.hpp" #include #include #define super IOEthernetInterface OSDefineMetaClassAndStructors(AirportItlwmEthernetInterface, IOEthernetInterface); bool AirportItlwmEthernetInterface:: initWithSkywalkInterfaceAndProvider(IONetworkController *controller, IO80211SkywalkInterface *interface) { bool ret = super::init(controller); if (ret) this->interface = interface; this->isAttach = false; return ret; } IOReturn AirportItlwmEthernetInterface:: attachToDataLinkLayer( IOOptionBits options, void *parameter ) { XYLog("%s\n", __FUNCTION__); char infName[IFNAMSIZ]; IOReturn ret = super::attachToDataLinkLayer(options, parameter); if (ret == kIOReturnSuccess && interface) { UInt8 builtIn = 0; IOEthernetAddress addr; interface->setProperty("built-in", OSData::withBytes(&builtIn, sizeof(builtIn))); snprintf(infName, sizeof(infName), "%s%u", ifnet_name(getIfnet()), ifnet_unit(getIfnet())); interface->setProperty("IOInterfaceName", OSString::withCString(infName)); interface->setProperty(kIOInterfaceUnit, OSNumber::withNumber(ifnet_unit(getIfnet()), 8)); interface->setProperty(kIOInterfaceNamePrefix, OSString::withCString(ifnet_name(getIfnet()))); if (OSDynamicCast(IOEthernetController, getController())->getHardwareAddress(&addr) == kIOReturnSuccess) setProperty(kIOMACAddress, (void *) &addr, kIOEthernetAddressSize); interface->registerService(); interface->prepareBSDInterface(getIfnet(), 0); // ret = bpf_attach(getIfnet(), DLT_RAW, 0x48, &AirportItlwmEthernetInterface::bpfOutputPacket, &AirportItlwmEthernetInterface::bpfTap); } isAttach = true; return ret; } void AirportItlwmEthernetInterface:: detachFromDataLinkLayer(IOOptionBits options, void *parameter) { super::detachFromDataLinkLayer(options, parameter); isAttach = false; } /** Add another hack to fake that the provider is IOSkywalkNetworkInterface, to avoid skywalkfamily instance cast panic. */ IOService *AirportItlwmEthernetInterface:: getProvider() const { return isAttach ? this->interface : super::getProvider(); } errno_t AirportItlwmEthernetInterface:: bpfOutputPacket(ifnet_t interface, u_int32_t data_link_type, mbuf_t packet) { XYLog("%s data_link_type: %d\n", __FUNCTION__, data_link_type); AirportItlwmEthernetInterface *networkInterface = (AirportItlwmEthernetInterface *)ifnet_softc(interface); return networkInterface->enqueueOutputPacket(packet); } errno_t AirportItlwmEthernetInterface:: bpfTap(ifnet_t interface, u_int32_t data_link_type, bpf_tap_mode direction) { XYLog("%s data_link_type: %d direction: %d\n", __FUNCTION__, data_link_type, direction); return 0; } bool AirportItlwmEthernetInterface:: setLinkState(IO80211LinkState state) { if (state == kIO80211NetworkLinkUp) { ifnet_set_flags(getIfnet(), ifnet_flags(getIfnet()) | (IFF_UP | IFF_RUNNING), (IFF_UP | IFF_RUNNING)); } else { ifnet_set_flags(getIfnet(), ifnet_flags(getIfnet()) & ~(IFF_UP | IFF_RUNNING), 0); } return true; } extern const char* hexdump(uint8_t *buf, size_t len); UInt32 AirportItlwmEthernetInterface:: inputPacket(mbuf_t packet, UInt32 length, IOOptionBits options, void *param) { ether_header_t *eh; size_t len = mbuf_len(packet); eh = (ether_header_t *)mbuf_data(packet); if (len >= sizeof(ether_header_t) && eh->ether_type == htons(ETHERTYPE_PAE)) { // EAPOL packet const char* dump = hexdump((uint8_t*)mbuf_data(packet), len); XYLog("input EAPOL packet, len: %zu, data: %s\n", len, dump ? dump : "Failed to allocate memory"); if (dump) IOFree((void*)dump, 3 * len + 1); } return IOEthernetInterface::inputPacket(packet, length, options, param); } ================================================ FILE: AirportItlwm/AirportItlwmEthernetInterface.hpp ================================================ // // AirportItlwmEthernetInterface.hpp // AirportItlwm-Sonoma // // Created by qcwap on 2023/6/27. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef AirportItlwmEthernetInterface_hpp #define AirportItlwmEthernetInterface_hpp extern "C" { #include } #include "Airport/Apple80211.h" #include #include #include #include class AirportItlwmEthernetInterface : public IOEthernetInterface { OSDeclareDefaultStructors(AirportItlwmEthernetInterface) public: virtual IOReturn attachToDataLinkLayer( IOOptionBits options, void * parameter ) override; virtual void detachFromDataLinkLayer( IOOptionBits options, void * parameter ) override; virtual bool initWithSkywalkInterfaceAndProvider(IONetworkController *controller, IO80211SkywalkInterface *interface); virtual bool setLinkState(IO80211LinkState state); static errno_t bpfOutputPacket(ifnet_t interface, u_int32_t data_link_type, mbuf_t packet); static errno_t bpfTap(ifnet_t interface, u_int32_t data_link_type, bpf_tap_mode direction); virtual UInt32 inputPacket( mbuf_t packet, UInt32 length = 0, IOOptionBits options = 0, void * param = 0 ) override; virtual IOService * getProvider( void ) const override; private: IO80211SkywalkInterface *interface; bool isAttach; }; #endif /* AirportItlwmEthernetInterface_hpp */ ================================================ FILE: AirportItlwm/AirportItlwmInterface.cpp ================================================ // // AirportItlwmInterface.cpp // AirportItlwm // // Created by qcwap on 2020/9/7. // Copyright © 2020 钟先耀. All rights reserved. // #include "AirportItlwmInterface.hpp" #define super IO80211Interface OSDefineMetaClassAndStructors(AirportItlwmInterface, IO80211Interface); const char* hexdump(uint8_t *buf, size_t len) { ssize_t str_len = len * 3 + 1; char *str = (char*)IOMalloc(str_len); if (!str) return nullptr; for (size_t i = 0; i < len; i++) snprintf(str + 3 * i, (len - i) * 3, "%02x ", buf[i]); str[MAX(str_len - 2, 0)] = 0; return str; } bool AirportItlwmInterface:: init(IO80211Controller *controller, ItlHalService *halService) { if (!super::init(controller)) return false; this->fHalService = halService; return true; } UInt32 AirportItlwmInterface:: inputPacket(mbuf_t packet, UInt32 length, IOOptionBits options, void *param) { ether_header_t *eh; size_t len = mbuf_len(packet); eh = (ether_header_t *)mbuf_data(packet); if (len >= sizeof(ether_header_t) && eh->ether_type == htons(ETHERTYPE_PAE)) { // EAPOL packet const char* dump = hexdump((uint8_t*)mbuf_data(packet), len); XYLog("input EAPOL packet, len: %zu, data: %s\n", len, dump ? dump : "Failed to allocate memory"); if (dump) IOFree((void*)dump, 3 * len + 1); return IO80211Interface::inputPacket(packet, (UInt32)len, 0, param); } return IOEthernetInterface::inputPacket(packet, length, options, param); } ================================================ FILE: AirportItlwm/AirportItlwmInterface.hpp ================================================ // // AirportItlwmInterface.hpp // AirportItlwm // // Created by qcwap on 2020/9/7. // Copyright © 2020 钟先耀. All rights reserved. // #ifndef AirportItlwmInterface_hpp #define AirportItlwmInterface_hpp #include "Airport/Apple80211.h" #include #include #include #include class AirportItlwmInterface : public IO80211Interface { OSDeclareDefaultStructors(AirportItlwmInterface) public: virtual UInt32 inputPacket( mbuf_t packet, UInt32 length = 0, IOOptionBits options = 0, void * param = 0 ) override; bool init(IO80211Controller *controller, ItlHalService *halService); private: ItlHalService *fHalService; }; #endif /* AirportItlwmInterface_hpp */ ================================================ FILE: AirportItlwm/AirportItlwmSkywalkInterface.cpp ================================================ // // AirportItlwmSkywalkInterface.cpp // AirportItlwm-Sonoma // // Created by qcwap on 2023/6/27. // Copyright © 2023 钟先耀. All rights reserved. // #include "AirportItlwmV2.hpp" #include "AirportItlwmSkywalkInterface.hpp" #include #include #include #include #include #include #define super IO80211InfraProtocol OSDefineMetaClassAndStructors(AirportItlwmSkywalkInterface, IO80211InfraProtocol); const char* hexdump(uint8_t *buf, size_t len) { ssize_t str_len = len * 3 + 1; char *str = (char*)IOMalloc(str_len); if (!str) return nullptr; for (size_t i = 0; i < len; i++) snprintf(str + 3 * i, (len - i) * 3, "%02x ", buf[i]); str[MAX(str_len - 2, 0)] = 0; return str; } static int ieeeChanFlag2appleScanFlagVentura(int flags) { int ret = 0; if (flags & IEEE80211_CHAN_2GHZ) ret |= APPLE80211_C_FLAG_2GHZ; if (flags & IEEE80211_CHAN_5GHZ) ret |= APPLE80211_C_FLAG_5GHZ; ret |= (APPLE80211_C_FLAG_ACTIVE | APPLE80211_C_FLAG_20MHZ); return ret; } static int ieeeChanFlag2apple(int flags, int bw) { int ret = 0; if (flags & IEEE80211_CHAN_2GHZ) ret |= APPLE80211_C_FLAG_2GHZ; if (flags & IEEE80211_CHAN_5GHZ) ret |= APPLE80211_C_FLAG_5GHZ; if (!(flags & IEEE80211_CHAN_PASSIVE)) ret |= APPLE80211_C_FLAG_ACTIVE; if (flags & IEEE80211_CHAN_DFS) ret |= APPLE80211_C_FLAG_DFS; if (bw == -1) { if (flags & IEEE80211_CHAN_VHT) { if ((flags & IEEE80211_CHAN_VHT160) || (flags & IEEE80211_CHAN_VHT80_80)) ret |= APPLE80211_C_FLAG_160MHZ; if (flags & IEEE80211_CHAN_VHT80) ret |= APPLE80211_C_FLAG_80MHZ; } else if ((flags & IEEE80211_CHAN_HT40) && (flags & IEEE80211_CHAN_HT)) { ret |= APPLE80211_C_FLAG_40MHZ; if (flags & IEEE80211_CHAN_HT40U) ret |= APPLE80211_C_FLAG_EXT_ABV; } else if (flags & IEEE80211_CHAN_HT20) ret |= APPLE80211_C_FLAG_20MHZ; else if ((flags & IEEE80211_CHAN_CCK) || (flags & IEEE80211_CHAN_OFDM)) ret |= APPLE80211_C_FLAG_10MHZ; } else { switch (bw) { case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: ret |= APPLE80211_C_FLAG_160MHZ; break; case IEEE80211_CHAN_WIDTH_80: ret |= APPLE80211_C_FLAG_80MHZ; break; case IEEE80211_CHAN_WIDTH_40: ret |= APPLE80211_C_FLAG_40MHZ; if (flags & IEEE80211_CHAN_HT40U) ret |= APPLE80211_C_FLAG_EXT_ABV; break; case IEEE80211_CHAN_WIDTH_20: ret |= APPLE80211_C_FLAG_20MHZ; break; default: if (flags & IEEE80211_CHAN_HT20) ret |= APPLE80211_C_FLAG_20MHZ; else if ((flags & IEEE80211_CHAN_CCK) || (flags & IEEE80211_CHAN_OFDM)) ret |= APPLE80211_C_FLAG_10MHZ; break; } } return ret; } void AirportItlwmSkywalkInterface::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 AirportItlwmSkywalkInterface::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 AirportItlwmSkywalkInterface::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 AirportItlwmSkywalkInterface:: init(IOService *provider) { bool ret = IO80211InfraInterface::init(); if (!ret) { XYLog("%s IO80211InfraInterface init failed\n", __PRETTY_FUNCTION__); return false; } instance = OSDynamicCast(AirportItlwm, provider); if (!instance) return false; this->fHalService = instance->fHalService; this->scanSource = instance->scanSource; return ret; } //ifnet_t AirportItlwmSkywalkInterface:: //getBSDInterface() //{ // if (instance->bsdInterface) // return instance->bsdInterface->getIfnet(); // return NULL; //} IOReturn AirportItlwmSkywalkInterface:: getSSID(struct apple80211_ssid_data *sd) { struct ieee80211com * ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(sd, 0, sizeof(*sd)); sd->version = APPLE80211_VERSION; memcpy(sd->ssid_bytes, ic->ic_des_essid, strlen((const char*)ic->ic_des_essid)); sd->ssid_len = (uint32_t)strlen((const char*)ic->ic_des_essid); return kIOReturnSuccess; } return 6; } IOReturn AirportItlwmSkywalkInterface:: getAUTH_TYPE(struct apple80211_authtype_data *ad) { ad->version = APPLE80211_VERSION; ad->authtype_lower = current_authtype_lower; ad->authtype_upper = current_authtype_upper; return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: setAUTH_TYPE(struct apple80211_authtype_data *ad) { current_authtype_lower = ad->authtype_lower; current_authtype_upper = ad->authtype_upper; return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: setCIPHER_KEY(struct apple80211_key *key) { XYLog("%s\n", __FUNCTION__); const char* keydump = hexdump(key->key, key->key_len); const char* rscdump = hexdump(key->key_rsc, key->key_rsc_len); const char* eadump = hexdump(key->key_ea.octet, APPLE80211_ADDR_LEN); static_assert(__offsetof(struct apple80211_key, key_ea) == 92, "struct corrupted"); static_assert(__offsetof(struct apple80211_key, key_rsc_len) == 80, "struct corrupted"); static_assert(__offsetof(struct apple80211_key, wowl_kck_len) == 100, "struct corrupted"); static_assert(__offsetof(struct apple80211_key, wowl_kek_len) == 120, "struct corrupted"); static_assert(__offsetof(struct apple80211_key, wowl_kck_key) == 104, "struct corrupted"); if (keydump && rscdump && eadump) XYLog("Set key request: len=%d cipher_type=%d flags=%d index=%d key=%s rsc_len=%d rsc=%s ea=%s\n", key->key_len, key->key_cipher_type, key->key_flags, key->key_index, keydump, key->key_rsc_len, rscdump, eadump); else XYLog("Set key request, but failed to allocate memory for hexdump\n"); if (keydump) IOFree((void*)keydump, 3 * key->key_len + 1); if (rscdump) IOFree((void*)rscdump, 3 * key->key_rsc_len + 1); if (eadump) IOFree((void*)eadump, 3 * APPLE80211_ADDR_LEN + 1); switch (key->key_cipher_type) { case APPLE80211_CIPHER_NONE: // clear existing key // XYLog("Setting NONE key is not supported\n"); break; case APPLE80211_CIPHER_WEP_40: case APPLE80211_CIPHER_WEP_104: XYLog("Setting WEP key %d is not supported\n", key->key_index); break; case APPLE80211_CIPHER_TKIP: case APPLE80211_CIPHER_AES_OCB: case APPLE80211_CIPHER_AES_CCM: switch (key->key_flags) { case 4: // PTK setPTK(key->key, key->key_len); break; case 0: // GTK setGTK(key->key, key->key_len, key->key_index, key->key_rsc); break; } break; case APPLE80211_CIPHER_PMK: XYLog("Setting WPA PMK is not supported\n"); break; case APPLE80211_CIPHER_MSK: XYLog("Setting MSK\n"); ieee80211_pmksa_add(fHalService->get80211Controller(), IEEE80211_AKM_8021X, fHalService->get80211Controller()->ic_bss->ni_macaddr, key->key, 0); break; case APPLE80211_CIPHER_PMKSA: XYLog("Setting WPA PMKSA\n"); ieee80211_pmksa_add(fHalService->get80211Controller(), IEEE80211_AKM_8021X, fHalService->get80211Controller()->ic_bss->ni_macaddr, key->key, 0); break; } //fInterface->postMessage(APPLE80211_M_CIPHER_KEY_CHANGED); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getPHY_MODE(struct apple80211_phymode_data *pd) { struct ieee80211com *ic = fHalService->get80211Controller(); pd->version = APPLE80211_VERSION; pd->phy_mode = APPLE80211_MODE_11A | APPLE80211_MODE_11B | APPLE80211_MODE_11G | APPLE80211_MODE_11N; if (ic->ic_flags & IEEE80211_F_VHTON) pd->phy_mode |= APPLE80211_MODE_11AC; if (ic->ic_flags & IEEE80211_F_HEON) pd->phy_mode |= APPLE80211_MODE_11AX; switch (fHalService->get80211Controller()->ic_curmode) { case IEEE80211_MODE_AUTO: pd->active_phy_mode = APPLE80211_MODE_AUTO; break; case IEEE80211_MODE_11A: pd->active_phy_mode = APPLE80211_MODE_11A; break; case IEEE80211_MODE_11B: pd->active_phy_mode = APPLE80211_MODE_11B; break; case IEEE80211_MODE_11G: pd->active_phy_mode = APPLE80211_MODE_11G; break; case IEEE80211_MODE_11N: pd->active_phy_mode = APPLE80211_MODE_11N; break; case IEEE80211_MODE_11AC: pd->active_phy_mode = APPLE80211_MODE_11AC; break; case IEEE80211_MODE_11AX: pd->active_phy_mode = APPLE80211_MODE_11AX; break; default: pd->active_phy_mode = APPLE80211_MODE_AUTO; break; } return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getCHANNEL(struct apple80211_channel_data *cd) { struct ieee80211com * ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(cd, 0, sizeof(apple80211_channel_data)); cd->version = APPLE80211_VERSION; cd->channel.version = APPLE80211_VERSION; cd->channel.channel = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); cd->channel.flags = ieeeChanFlag2apple(ic->ic_bss->ni_chan->ic_flags, ic->ic_bss->ni_chw); return kIOReturnSuccess; } return 6; } IOReturn AirportItlwmSkywalkInterface:: getSTATE(struct apple80211_state_data *sd) { memset(sd, 0, sizeof(*sd)); sd->version = APPLE80211_VERSION; sd->state = fHalService->get80211Controller()->ic_state; return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getMCS_INDEX_SET(struct apple80211_mcs_index_set_data *ad) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(ad, 0, sizeof(*ad)); ad->version = APPLE80211_VERSION; size_t size = min(ARRAY_SIZE(ic->ic_bss->ni_rxmcs), ARRAY_SIZE(ad->mcs_set_map)); for (int i = 0; i < size; i++) ad->mcs_set_map[i] = ic->ic_bss->ni_rxmcs[i]; return kIOReturnSuccess; } return 6; } IOReturn AirportItlwmSkywalkInterface:: getVHT_MCS_INDEX_SET(struct apple80211_vht_mcs_index_set_data *data) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_bss == NULL || ic->ic_curmode < IEEE80211_MODE_11AC) { return kIOReturnError; } memset(data, 0, sizeof(struct apple80211_vht_mcs_index_set_data)); data->version = APPLE80211_VERSION; data->mcs_map = ic->ic_bss->ni_vht_mcsinfo.tx_mcs_map; return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getMCS_VHT(struct apple80211_mcs_vht_data *data) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_bss == NULL || ic->ic_curmode < IEEE80211_MODE_11AC) { return kIOReturnError; } memset(data, 0, sizeof(struct apple80211_mcs_vht_data)); data->version = APPLE80211_VERSION; data->guard_interval = (ieee80211_node_supports_vht_sgi80(ic->ic_bss) || ieee80211_node_supports_vht_sgi160(ic->ic_bss)) ? APPLE80211_GI_SHORT : APPLE80211_GI_LONG; data->index = ic->ic_bss->ni_txmcs; data->nss = fHalService->getDriverInfo()->getTxNSS(); switch (ic->ic_bss->ni_chw) { case IEEE80211_CHAN_WIDTH_40: data->bw = 40; break; case IEEE80211_CHAN_WIDTH_80: data->bw = 80; break; case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: data->bw = 160; break; default: data->bw = 20; break; } return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getRATE_SET(struct apple80211_rate_set_data *ad) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(ad, 0, sizeof(*ad)); ad->version = APPLE80211_VERSION; ad->num_rates = ic->ic_bss->ni_rates.rs_nrates; size_t size = min(ic->ic_bss->ni_rates.rs_nrates, ARRAY_SIZE(ad->rates)); for (int i=0; i < size; i++) { struct apple80211_rate apple_rate = ad->rates[i]; apple_rate.version = APPLE80211_VERSION; apple_rate.rate = ic->ic_bss->ni_rates.rs_rates[i]; apple_rate.flags = 0; } return kIOReturnSuccess; } return 6; } IOReturn AirportItlwmSkywalkInterface:: getOP_MODE(struct apple80211_opmode_data *od) { od->version = APPLE80211_VERSION; od->op_mode = APPLE80211_M_STA; return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getTXPOWER(struct apple80211_txpower_data *txd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(txd, 0, sizeof(*txd)); txd->version = APPLE80211_VERSION; txd->txpower = ic->ic_txpower; txd->txpower_unit = APPLE80211_UNIT_PERCENT; return kIOReturnSuccess; } return 6; } IOReturn AirportItlwmSkywalkInterface:: getRATE(struct apple80211_rate_data *rd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_bss == NULL) return 6; int nss; int sgi; int index = 0; if (ic->ic_state == IEEE80211_S_RUN) { memset(rd, 0, sizeof(*rd)); rd->version = APPLE80211_VERSION; rd->num_radios = 1; sgi = ieee80211_node_supports_sgi(ic->ic_bss); if (ic->ic_curmode == IEEE80211_MODE_11AC) { if (sgi) index += 1; nss = fHalService->getDriverInfo()->getTxNSS(); switch (ic->ic_bss->ni_chw) { case IEEE80211_CHAN_WIDTH_40: index += 4; break; case IEEE80211_CHAN_WIDTH_80: index += 8; break; case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: index += 12; break; default: break; } index += 2 * (nss - 1); const struct ieee80211_vht_rateset *rs = &ieee80211_std_ratesets_11ac[index]; rd->rate[0] = rs->rates[ic->ic_bss->ni_txmcs % rs->nrates] / 2; } else if (ic->ic_curmode == IEEE80211_MODE_11N) { int is_40mhz = ic->ic_bss->ni_chw == IEEE80211_CHAN_WIDTH_40; if (sgi) index += 1; if (is_40mhz) index += (IEEE80211_HT_RATESET_MIMO4_SGI + 1); index += (ic->ic_bss->ni_txmcs / 16); nss = ic->ic_bss->ni_txmcs / 8 + 1; index += 2 * (nss - 1); rd->rate[0] = ieee80211_std_ratesets_11n[index].rates[ic->ic_bss->ni_txmcs % 8] / 2; } else rd->rate[0] = ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate]; return kIOReturnSuccess; } return 6; } IOReturn AirportItlwmSkywalkInterface:: getBSSID(struct apple80211_bssid_data *bd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(bd, 0, sizeof(*bd)); bd->version = APPLE80211_VERSION; memcpy(bd->bssid.octet, ic->ic_bss->ni_bssid, APPLE80211_ADDR_LEN); return kIOReturnSuccess; } return 6; } IOReturn AirportItlwmSkywalkInterface:: getRSSI(struct apple80211_rssi_data *rd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(rd, 0, sizeof(*rd)); rd->num_radios = 1; rd->rssi_unit = APPLE80211_UNIT_DBM; rd->rssi[0] = rd->aggregate_rssi = rd->rssi_ext[0] = rd->aggregate_rssi_ext = -(0 - IWM_MIN_DBM - ic->ic_bss->ni_rssi); return kIOReturnSuccess; } return 6; } IOReturn AirportItlwmSkywalkInterface:: getRSN_IE(struct apple80211_rsn_ie_data *data) { #ifdef USE_APPLE_SUPPLICANT struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_bss == NULL || ic->ic_bss->ni_rsnie == NULL) { return kIOReturnError; } data->version = APPLE80211_VERSION; if (ic->ic_rsn_ie_override[1] > 0) { data->len = 2 + ic->ic_rsn_ie_override[1]; memcpy(data->ie, ic->ic_rsn_ie_override, data->len); } else { data->len = 2 + ic->ic_bss->ni_rsnie[1]; memcpy(data->ie, ic->ic_bss->ni_rsnie, data->len); } return kIOReturnSuccess; #else return kIOReturnUnsupported; #endif } IOReturn AirportItlwmSkywalkInterface:: setRSN_IE(struct apple80211_rsn_ie_data *data) { #ifdef USE_APPLE_SUPPLICANT struct ieee80211com *ic = fHalService->get80211Controller(); if (!data) return kIOReturnError; static_assert(sizeof(ic->ic_rsn_ie_override) == APPLE80211_MAX_RSN_IE_LEN, "Max RSN IE length mismatch"); memcpy(ic->ic_rsn_ie_override, data->ie, APPLE80211_MAX_RSN_IE_LEN); if (ic->ic_state == IEEE80211_S_RUN && ic->ic_bss != nullptr) ieee80211_save_ie(data->ie, &ic->ic_bss->ni_rsnie); return kIOReturnSuccess; #else return kIOReturnUnsupported; #endif } IOReturn AirportItlwmSkywalkInterface:: getAP_IE_LIST(struct apple80211_ap_ie_data *data) { struct ieee80211com *ic = fHalService->get80211Controller(); if (!data) return kIOReturnError; if (ic->ic_bss == NULL || ic->ic_bss->ni_rsnie_tlv == NULL || ic->ic_bss->ni_rsnie_tlv_len == 0 || ic->ic_bss->ni_rsnie_tlv_len > data->len || ic->ic_bss->ni_rsnie_tlv_len > 1024) return kIOReturnError; data->version = APPLE80211_VERSION; data->len = ic->ic_bss->ni_rsnie_tlv_len; memcpy(data->ie_data, ic->ic_bss->ni_rsnie_tlv, data->len); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getNOISE(struct apple80211_noise_data *nd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(nd, 0, sizeof(*nd)); nd->version = APPLE80211_VERSION; nd->num_radios = 1; nd->noise[0] = nd->aggregate_noise = -fHalService->getDriverInfo()->getBSSNoise(); nd->noise_unit = APPLE80211_UNIT_DBM; return kIOReturnSuccess; } return 6; } IOReturn AirportItlwmSkywalkInterface:: getPOWERSAVE(struct apple80211_powersave_data *pd) { pd->version = APPLE80211_VERSION; pd->powersave_level = APPLE80211_POWERSAVE_MODE_DISABLED; return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getNSS(struct apple80211_nss_data *data) { memset(data, 0, sizeof(*data)); data->version = APPLE80211_VERSION; data->nss = fHalService->getDriverInfo()->getTxNSS(); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: setASSOCIATE(struct apple80211_assoc_data *ad) { XYLog("%s [%s] mode=%d ad_auth_lower=%d ad_auth_upper=%d rsn_ie_len=%d%s%s%s%s%s%s%s\n", __FUNCTION__, ad->ad_ssid, ad->ad_mode, ad->ad_auth_lower, ad->ad_auth_upper, ad->ad_rsn_ie_len, (ad->ad_flags & 2) ? ", Instant Hotspot" : "", (ad->ad_flags & 4) ? ", Auto Instant Hotspot" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 1) ? ", don't disassociate" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 2) ? ", don't blacklist" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 4) ? ", closed Network" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 8) ? ", 802.1X" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 0x20) ? ", force BSSID" : ""); struct apple80211_rsn_ie_data rsn_ie_data; struct apple80211_authtype_data auth_type_data; struct ieee80211com *ic = fHalService->get80211Controller(); if (!ad) return kIOReturnError; if (ic->ic_state < IEEE80211_S_SCAN) return kIOReturnSuccess; if (ic->ic_state == IEEE80211_S_ASSOC || ic->ic_state == IEEE80211_S_AUTH) return kIOReturnSuccess; if (ad->ad_mode != APPLE80211_AP_MODE_IBSS) { disassocIsVoluntary = false; auth_type_data.version = APPLE80211_VERSION; auth_type_data.authtype_upper = ad->ad_auth_upper; auth_type_data.authtype_lower = ad->ad_auth_lower; setAUTH_TYPE(&auth_type_data); rsn_ie_data.version = APPLE80211_VERSION; rsn_ie_data.len = ad->ad_rsn_ie[1] + 2; memcpy(rsn_ie_data.ie, ad->ad_rsn_ie, rsn_ie_data.len); setRSN_IE(&rsn_ie_data); associateSSID(ad->ad_ssid, ad->ad_ssid_len, ad->ad_bssid, ad->ad_auth_lower, ad->ad_auth_upper, ad->ad_key.key, ad->ad_key.key_len, ad->ad_key.key_index); } return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: setDISASSOCIATE(struct apple80211_disassoc_data *ad) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state < IEEE80211_S_SCAN) return kIOReturnSuccess; if (ic->ic_state > IEEE80211_S_AUTH && ic->ic_bss != NULL) IEEE80211_SEND_MGMT(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); if (ic->ic_state == IEEE80211_S_ASSOC || ic->ic_state == IEEE80211_S_AUTH) return kIOReturnSuccess; disassocIsVoluntary = true; ieee80211_del_ess(ic, nullptr, 0, 1); ieee80211_deselect_ess(ic); #ifdef USE_APPLE_SUPPLICANT ic->ic_rsn_ie_override[1] = 0; #endif ic->ic_assoc_status = APPLE80211_STATUS_UNAVAILABLE; ic->ic_deauth_reason = APPLE80211_REASON_ASSOC_LEAVING; ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getSUPPORTED_CHANNELS(struct apple80211_sup_channel_data *ad) { if (!ad) return kIOReturnError; ad->version = APPLE80211_VERSION; ad->num_channels = 0; struct ieee80211com *ic = fHalService->get80211Controller(); for (int i = 0; i < IEEE80211_CHAN_MAX; i++) { if (ic->ic_channels[i].ic_freq != 0) { ad->supported_channels[ad->num_channels].channel = ieee80211_chan2ieee(ic, &ic->ic_channels[i]); ad->supported_channels[ad->num_channels].flags = ieeeChanFlag2appleScanFlagVentura(ic->ic_channels[i].ic_flags); ad->num_channels++; } } return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getLOCALE(struct apple80211_locale_data *ld) { if (!ld) return kIOReturnError; ld->version = APPLE80211_VERSION; ld->locale = APPLE80211_LOCALE_FCC; return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getDEAUTH(struct apple80211_deauth_data *da) { if (!da) return kIOReturnError; da->version = APPLE80211_VERSION; struct ieee80211com *ic = fHalService->get80211Controller(); da->deauth_reason = ic->ic_deauth_reason; // XYLog("%s, %d\n", __FUNCTION__, da->deauth_reason); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getASSOCIATION_STATUS(struct apple80211_assoc_status_data *hv) { struct ieee80211com *ic = fHalService->get80211Controller(); if (!hv) return kIOReturnError; memset(hv, 0, sizeof(*hv)); hv->version = APPLE80211_VERSION; if (ic->ic_state == IEEE80211_S_RUN) hv->status = APPLE80211_STATUS_SUCCESS; else hv->status = APPLE80211_STATUS_UNAVAILABLE; // XYLog("%s, %d\n", __FUNCTION__, hv->status); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: setSCANCACHE_CLEAR(void *req) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = fHalService->get80211Controller(); //if doing background or active scan, don't free nodes. if ((ic->ic_flags & IEEE80211_F_BGSCAN) || (ic->ic_flags & IEEE80211_F_ASCAN)) return kIOReturnSuccess; ieee80211_free_allnodes(ic, 0); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: setDEAUTH(struct apple80211_deauth_data *da) { XYLog("%s\n", __FUNCTION__); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getMCS(struct apple80211_mcs_data* md) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state != IEEE80211_S_RUN || ic->ic_bss == NULL || !md) return 6; md->version = APPLE80211_VERSION; md->index = ic->ic_bss->ni_txmcs; return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getLINK_CHANGED_EVENT_DATA(struct apple80211_link_changed_event_data *ed) { if (ed == nullptr) return 16; struct ieee80211com *ic = fHalService->get80211Controller(); bzero(ed, sizeof(apple80211_link_changed_event_data)); ed->isLinkDown = !(instance->currentStatus & kIONetworkLinkActive); if (ed->isLinkDown) { ed->voluntary = disassocIsVoluntary; ed->reason = APPLE80211_LINK_DOWN_REASON_DEAUTH; } else ed->rssi = -(0 - IWM_MIN_DBM - ic->ic_bss->ni_rssi); XYLog("Link %s, reason: %d, voluntary: %d\n", ed->isLinkDown ? "down" : "up", ed->reason, ed->voluntary); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: setSCAN_REQ(struct apple80211_scan_data *sd) { struct ieee80211com *ic = fHalService->get80211Controller(); #if 0 XYLog("%s Type: %u BSS Type: %u PHY Mode: %u Dwell time: %u Rest time: %u Num channels: %u SSID: %s BSSID: %s\n", __FUNCTION__, sd->scan_type, sd->bss_type, sd->phy_mode, sd->dwell_time, sd->rest_time, sd->num_channels, sd->ssid, ether_sprintf(sd->bssid.octet)); #endif if (fScanResultWrapping) return 22; if (ic->ic_state <= IEEE80211_S_INIT) return 22; if (sd->scan_type == APPLE80211_SCAN_TYPE_FAST || sd->scan_type == APPLE80211_SCAN_TYPE_PASSIVE) { if (scanSource) { scanSource->setTimeoutMS(100); scanSource->enable(); } return kIOReturnSuccess; } ieee80211_begin_cache_bgscan(&ic->ic_ac.ac_if); if (scanSource) { scanSource->setTimeoutMS(100); scanSource->enable(); } return kIOReturnSuccess; } extern OSDictionary *convertScanToDictionary(apple80211_scan_result *a1); static int convertNodeToScanResult(ItlHalService *fHalService, struct ieee80211_node *fNextNodeToSend, apple80211_scan_result *result) { bzero(result, sizeof(*result)); result->version = APPLE80211_VERSION; if (fNextNodeToSend->ni_rsnie_tlv && fNextNodeToSend->ni_rsnie_tlv_len > 0) { result->asr_ie_len = fNextNodeToSend->ni_rsnie_tlv_len; memcpy(result->asr_ie_data, fNextNodeToSend->ni_rsnie_tlv, MIN(result->asr_ie_len, sizeof(result->asr_ie_data))); } else { result->asr_ie_len = 0; } result->asr_beacon_int = fNextNodeToSend->ni_intval; for (int i = 0; i < result->asr_nrates; i++ ) result->asr_rates[i] = fNextNodeToSend->ni_rates.rs_rates[i]; result->asr_nrates = fNextNodeToSend->ni_rates.rs_nrates; result->asr_age = (uint32_t)(airport_up_time() - fNextNodeToSend->ni_age_ts); result->asr_cap = fNextNodeToSend->ni_capinfo; result->asr_channel.version = APPLE80211_VERSION; result->asr_channel.channel = ieee80211_chan2ieee(fHalService->get80211Controller(), fNextNodeToSend->ni_chan); result->asr_channel.flags = ieeeChanFlag2appleScanFlagVentura(fNextNodeToSend->ni_chan->ic_flags); result->asr_noise = -fHalService->getDriverInfo()->getBSSNoise(); result->asr_rssi = -(0 - IWM_MIN_DBM - fNextNodeToSend->ni_rssi); memcpy(result->asr_bssid, fNextNodeToSend->ni_bssid, IEEE80211_ADDR_LEN); result->asr_ssid_len = fNextNodeToSend->ni_esslen; if (result->asr_ssid_len != 0) memcpy(&result->asr_ssid, fNextNodeToSend->ni_essid, result->asr_ssid_len); return 0; } IOReturn AirportItlwmSkywalkInterface:: getCURRENT_NETWORK(apple80211_scan_result *sr) { if (fHalService->get80211Controller()->ic_state != IEEE80211_S_RUN || fHalService->get80211Controller()->ic_bss == NULL) return kIOReturnError; convertNodeToScanResult(fHalService, fHalService->get80211Controller()->ic_bss, sr); return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getCOLOCATED_NETWORK_SCOPE_ID(apple80211_colocated_network_scope_id *as) { if (!as) return kIOReturnBadArgument; as->version = APPLE80211_VERSION; return kIOReturnSuccess; } IOReturn AirportItlwmSkywalkInterface:: getSCAN_RESULT(struct apple80211_scan_result *sr) { if (fNextNodeToSend == NULL) { if (fScanResultWrapping) { fScanResultWrapping = false; return 5; } else { fNextNodeToSend = RB_MIN(ieee80211_tree, &fHalService->get80211Controller()->ic_tree); if (fNextNodeToSend == NULL) { return 5; } } } // XYLog("%s ni_bssid=%s ni_essid=%s channel=%d flags=%d asr_cap=%d asr_nrates=%d asr_ssid_len=%d asr_ie_len=%d asr_rssi=%d\n", __FUNCTION__, ether_sprintf(fNextNodeToSend->ni_bssid), fNextNodeToSend->ni_essid, ieee80211_chan2ieee(ic, fNextNodeToSend->ni_chan), ieeeChanFlag2apple(fNextNodeToSend->ni_chan->ic_flags, -1), fNextNodeToSend->ni_capinfo, fNextNodeToSend->ni_rates.rs_nrates, fNextNodeToSend->ni_esslen, fNextNodeToSend->ni_rsnie_tlv == NULL ? 0 : fNextNodeToSend->ni_rsnie_tlv_len, fNextNodeToSend->ni_rssi); convertNodeToScanResult(fHalService, fNextNodeToSend, sr); fNextNodeToSend = RB_NEXT(ieee80211_tree, &HalService->get80211Controller()->ic_tree, fNextNodeToSend); if (fNextNodeToSend == NULL) fScanResultWrapping = true; return kIOReturnSuccess; } ================================================ FILE: AirportItlwm/AirportItlwmSkywalkInterface.hpp ================================================ // // AirportItlwmSkywalkInterface.hpp // AirportItlwm-Sonoma // // Created by qcwap on 2023/6/27. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef AirportItlwmSkywalkInterface_hpp #define AirportItlwmSkywalkInterface_hpp #include class AirportItlwmSkywalkInterface : public IO80211InfraProtocol { OSDeclareDefaultStructors(AirportItlwmSkywalkInterface) public: virtual bool init(IOService *) override; // virtual ifnet_t getBSDInterface(void) override; void 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); void setPTK(const u_int8_t *key, size_t key_len); void setGTK(const u_int8_t *key, size_t key_len, u_int8_t kid, u_int8_t *rsc); public: virtual IOReturn getSSID(apple80211_ssid_data *) override; virtual IOReturn getAUTH_TYPE(apple80211_authtype_data *) override; virtual IOReturn getCHANNEL(apple80211_channel_data *) override; virtual IOReturn getPOWERSAVE(apple80211_powersave_data *) override; virtual IOReturn getTXPOWER(apple80211_txpower_data *) override; virtual IOReturn getRATE(apple80211_rate_data *) override; virtual IOReturn getBSSID(apple80211_bssid_data *) override; virtual IOReturn getSCAN_RESULT(apple80211_scan_result *) override; virtual IOReturn getSTATE(apple80211_state_data *) override; virtual IOReturn getPHY_MODE(apple80211_phymode_data *) override; virtual IOReturn getOP_MODE(apple80211_opmode_data *) override; virtual IOReturn getRSSI(apple80211_rssi_data *) override; virtual IOReturn getNOISE(apple80211_noise_data *) override; virtual IOReturn getSUPPORTED_CHANNELS(apple80211_sup_channel_data *) override; virtual IOReturn getLOCALE(apple80211_locale_data *) override; virtual IOReturn getDEAUTH(apple80211_deauth_data *) override; virtual IOReturn getRATE_SET(apple80211_rate_set_data *) override; virtual IOReturn getDTIM_INT(apple80211_dtim_int_data *) override { return kIOReturnUnsupported; } virtual IOReturn getSTATION_LIST(apple80211_sta_data *) override { return kIOReturnUnsupported; } virtual IOReturn getRSN_IE(apple80211_rsn_ie_data *) override; virtual IOReturn getAP_IE_LIST(apple80211_ap_ie_data *) override; virtual IOReturn getSTATS(apple80211_stats_data *) override { return kIOReturnUnsupported; } virtual IOReturn getASSOCIATION_STATUS(apple80211_assoc_status_data *) override; virtual IOReturn getGUARD_INTERVAL(apple80211_guard_interval_data *) override { return kIOReturnUnsupported; } virtual IOReturn getMCS(apple80211_mcs_data *) override; virtual IOReturn getMCS_INDEX_SET(apple80211_mcs_index_set_data *) override; virtual IOReturn getWOW_PARAMETERS(apple80211_wow_parameter_data *) override { return kIOReturnUnsupported; } virtual IOReturn getWOW_ENABLED(apple80211_state_data *) override { return kIOReturnUnsupported; } virtual IOReturn getPID_LOCK(apple80211_state_data *) override { return kIOReturnUnsupported; } virtual IOReturn getSTA_IE_LIST(apple80211_sta_ie_data *) override { return kIOReturnUnsupported; } virtual IOReturn getSTA_STATS(apple80211_sta_stats_data *) override { return kIOReturnUnsupported; } virtual IOReturn getBT_COEX_FLAGS(apple80211_state_data *) override { return kIOReturnUnsupported; } virtual IOReturn getCURRENT_NETWORK(apple80211_scan_result *) override; virtual IOReturn getRSSI_BOUNDS(apple80211_rssi_bounds_data *) override { return kIOReturnUnsupported; } virtual IOReturn getPOWER_DEBUG_INFO(apple80211_power_debug_info *) override { return kIOReturnUnsupported; } virtual IOReturn getHT_CAPABILITY(apple80211_ht_capability *) override { return kIOReturnUnsupported; } virtual IOReturn getLINK_CHANGED_EVENT_DATA(apple80211_link_changed_event_data *) override; virtual IOReturn getEXTENDED_STATS(apple80211_extended_stats *) override { return kIOReturnUnsupported; } virtual IOReturn getBEACON_PERIOD(apple80211_beacon_period_data *) override { return kIOReturnUnsupported; } virtual IOReturn getVHT_MCS_INDEX_SET(apple80211_vht_mcs_index_set_data *) override; virtual IOReturn getMCS_VHT(apple80211_mcs_vht_data *) override; virtual IOReturn getGAS_RESULTS(apple80211_gas_result_t *) override { return kIOReturnUnsupported; } virtual IOReturn getCHANNELS_INFO(apple80211_channels_info *) override { return kIOReturnUnsupported; } virtual IOReturn getVHT_CAPABILITY(apple80211_vht_capability *) override { return kIOReturnUnsupported; } virtual IOReturn getBGSCAN_CACHE_RESULTS(apple80211_bgscan_cached_network_data_list *) override { return kIOReturnUnsupported; } virtual IOReturn getROAM_PROFILE(apple80211_roam_profile_band_data *) override { return kIOReturnUnsupported; } virtual IOReturn getCHIP_COUNTER_STATS(apple80211_chip_stats *) override { return kIOReturnUnsupported; } virtual IOReturn getDBG_GUARD_TIME_PARAMS(apple80211_dbg_guard_time_params *) override { return kIOReturnUnsupported; } virtual IOReturn getLEAKY_AP_STATS_MODE(apple80211_leaky_ap_setting *) override { return kIOReturnUnsupported; } virtual IOReturn getCOUNTRY_CHANNELS(apple80211_country_channel_data *) override { return kIOReturnUnsupported; } virtual IOReturn getPRIVATE_MAC(apple80211_private_mac_data *) override { return kIOReturnUnsupported; } virtual IOReturn getRANGING_ENABLE(apple80211_ranging_enable_request_t *) override { return kIOReturnUnsupported; } virtual IOReturn getRANGING_START(apple80211_ranging_start_request_t *) override { return kIOReturnUnsupported; } virtual IOReturn getAWDL_RSDB_CAPS(apple80211_rsdb_capability *) override { return kIOReturnUnsupported; } virtual IOReturn getTKO_PARAMS(apple80211_tko_params *) override { return kIOReturnUnsupported; } virtual IOReturn getTKO_DUMP(apple80211_tko_dump *) override { return kIOReturnUnsupported; } virtual IOReturn getHW_SUPPORTED_CHANNELS(apple80211_sup_channel_data *) override { return kIOReturnUnsupported; } virtual IOReturn getBTCOEX_PROFILE(apple80211_btcoex_profile *) override { return kIOReturnUnsupported; } virtual IOReturn getBTCOEX_PROFILE_ACTIVE(apple80211_btcoex_profile_active_data *) override { return kIOReturnUnsupported; } virtual IOReturn getTRAP_INFO(apple80211_trap_info_data *) override { return kIOReturnUnsupported; } virtual IOReturn getTHERMAL_INDEX(apple80211_thermal_index_t *) override { return kIOReturnUnsupported; } virtual IOReturn getMAX_NSS_FOR_AP(apple80211_btcoex_max_nss_for_ap_data *) override { return kIOReturnUnsupported; } virtual IOReturn getBTCOEX_2G_CHAIN_DISABLE(apple80211_btcoex_2g_chain_disable *) override { return kIOReturnUnsupported; } virtual IOReturn getPOWER_BUDGET(apple80211_power_budget_t *) override { return kIOReturnUnsupported; } virtual IOReturn getOFFLOAD_TCPKA_ENABLE(apple80211_offload_tcpka_enable_t *) override { return kIOReturnUnsupported; } virtual IOReturn getRANGING_CAPS(apple80211_ranging_capabilities_t *) override { return kIOReturnUnsupported; } virtual IOReturn getSUPPRESS_SCANS(apple80211_suppress_scans_t *) override { return kIOReturnUnsupported; } virtual IOReturn getHOST_AP_MODE_HIDDEN(apple80211_host_ap_mode_hidden_t *) override { return kIOReturnUnsupported; } virtual IOReturn getLQM_CONFIG(apple80211_lqm_config_t *) override { return kIOReturnUnsupported; } virtual IOReturn getTRAP_CRASHTRACER_MINI_DUMP(apple80211_trap_mini_dump_data *) override { return kIOReturnUnsupported; } virtual IOReturn getHE_CAPABILITY(apple80211_he_capability *) override { return kIOReturnUnsupported; } virtual IOReturn getBEACON_INFO(apple80211_beacon_info_t *) override { return kIOReturnUnsupported; } virtual IOReturn getSOFTAP_PARAMS(apple80211_softap_params *) override { return kIOReturnUnsupported; } virtual IOReturn getCHIP_POWER_RANGE(apple80211_chip_power_limit *) override { return kIOReturnUnsupported; } virtual IOReturn getSOFTAP_STATS(apple80211_softap_stats *) override { return kIOReturnUnsupported; } virtual IOReturn getNSS(apple80211_nss_data *) override; virtual IOReturn getHW_ADDR(apple80211_hw_mac_address *) override { return kIOReturnUnsupported; } virtual IOReturn getHE_MCS_INDEX_SET(apple80211_he_mcs_index_set_data *) override { return kIOReturnUnsupported; } virtual IOReturn getCHIP_DIAGS(appl80211_chip_diags_data *) override { return kIOReturnUnsupported; } virtual IOReturn getHP2P_CTRL(apple80211_hp2p_ctrl *) override { return kIOReturnUnsupported; } virtual IOReturn getREQUEST_BSS_BLACKLIST(void *) override { return kIOReturnUnsupported; } virtual IOReturn getASSOC_READY_STATUS(apple80211_assoc_ready *) override { return kIOReturnUnsupported; } virtual IOReturn getTXRX_CHAIN_INFO(apple80211_txrx_chain_info *) override { return kIOReturnUnsupported; } virtual IOReturn getMIMO_STATUS(apple80211_mimo_status *) override { return kIOReturnUnsupported; } virtual IOReturn getCUR_PMK(apple80211_pmk *) override { return kIOReturnUnsupported; } virtual IOReturn getDYNSAR_DETAIL(apple80211_dynsar_detail *) override { return kIOReturnUnsupported; } virtual IOReturn getRANDOMISATION_STATUS(apple80211_mac_randomisation_status *) override { return kIOReturnUnsupported; } virtual IOReturn getCOUNTRY_CHANNELS_INFO(apple80211_channels_info *) override { return kIOReturnUnsupported; } virtual IOReturn getLQM_SUMMARY(apple80211_lqm_summary *) override { return kIOReturnUnsupported; } virtual IOReturn getCOLOCATED_NETWORK_SCOPE_ID(apple80211_colocated_network_scope_id *) override; virtual IOReturn getBEACON_SCAN_CACHE_REQ(apple80211_scan_result *) override { return kIOReturnUnsupported; } virtual IOReturn getSLOW_WIFI_FEATURE_ENABLED(apple80211_slow_wifi_feature_enabled *) override { return kIOReturnUnsupported; } virtual IOReturn getCCA(apple80211_interface_cca_data *) override { return kIOReturnUnsupported; } virtual IOReturn getRX_RATE(apple80211_rate_data *) override { return kIOReturnUnsupported; } virtual IOReturn getTIMESYNC_INFO(apple80211_timesync_info *) override { return kIOReturnUnsupported; } virtual IOReturn getSENSING_DATA(apple80211_sensing_data_t *) override { return kIOReturnUnsupported; } virtual IOReturn getCOUNTRY_BAND_SUPPORT(apple80211_country_band_support *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_FW_HOT_CHANNELS(apple80211_fw_hot_channels *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_LOW_LATENCY_INFO(apple80211_low_latency_info *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_BSS_INFO(apple80211_beacon_msg *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_TRAFFIC_COUNTERS(apple80211_wcl_traffic_counters *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_GET_TX_BLANKING_STATUS(uint *) override { return kIOReturnUnsupported; } virtual IOReturn getSSID_TRANSITION_SUPPORT(apple80211_ssid_transition_feature_enabled *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_VALID_CHANNEL_COUNT(unsigned long *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_P2P_STATUS_FOR_SCAN(p2pStatusForScan *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_CHANNELS_INFO(apple80211ChannelInfo *) override { return kIOReturnUnsupported; } virtual IOReturn getP2P_STEERING_METRIC(apple80211_p2p_steering_metrics *) override { return kIOReturnUnsupported; } virtual IOReturn getRSN_XE(apple80211_rsn_xe_data *) override { return kIOReturnUnsupported; } virtual IOReturn getSIB_COEX_STATUS(apple80211_sib_coex_status *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_EXTENDED_BSS_INFO(apple80211_extended_bss_info *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_LOW_LATENCY_INFO_STATS(apple80211_wcl_low_latency_stats *) override { return kIOReturnUnsupported; } virtual IOReturn getWCL_BGSCAN_CACHE_RESULT(apple80211_bgscan_cached_network_data_list *) override { return kIOReturnUnsupported; } virtual IOReturn getWIFI_NOISE_PER_ANT(apple80211_noise_per_ant_t *) override { return kIOReturnUnsupported; } virtual IOReturn getBLOCKED_BANDS(apple80211_blocked_bands *) override { return kIOReturnUnsupported; } virtual IOReturn setSSID(apple80211_ssid_data *) override { return kIOReturnUnsupported; } virtual IOReturn setAUTH_TYPE(apple80211_authtype_data *) override; virtual IOReturn setCIPHER_KEY(apple80211_key *) override; virtual IOReturn setCHANNEL(apple80211_channel_data *) override { return kIOReturnUnsupported; } virtual IOReturn setPOWERSAVE(apple80211_powersave_data *) override { return kIOReturnUnsupported; } virtual IOReturn setTXPOWER(apple80211_txpower_data *) override { return kIOReturnUnsupported; } virtual IOReturn setRATE(apple80211_rate_data *) override { return kIOReturnUnsupported; } virtual IOReturn setSCAN_REQ(apple80211_scan_data *) override; virtual IOReturn setASSOCIATE(apple80211_assoc_data *) override; virtual IOReturn setDISASSOCIATE(apple80211_disassoc_data *) override; virtual IOReturn setIBSS_MODE(apple80211_network_data *) override { return kIOReturnUnsupported; } virtual IOReturn setHOST_AP_MODE(apple80211_network_data *) override { return kIOReturnUnsupported; } virtual IOReturn setAP_MODE(apple80211_apmode_data *) override { return kIOReturnUnsupported; } virtual IOReturn setDEAUTH(apple80211_deauth_data *) override; virtual IOReturn setTX_ANTENNA(void *) override { return kIOReturnUnsupported; } virtual IOReturn setANTENNA_DIVERSITY(void *) override { return kIOReturnUnsupported; } virtual IOReturn setRSN_IE(apple80211_rsn_ie_data *) override; virtual IOReturn setBACKGROUND_SCAN(apple80211_bgscan_data *) override { return kIOReturnUnsupported; } virtual IOReturn setWOW_PARAMETERS(apple80211_wow_parameter_data *) override { return kIOReturnUnsupported; } virtual IOReturn setWOW_ENABLED(apple80211_state_data *) override { return kIOReturnUnsupported; } virtual IOReturn setPID_LOCK(apple80211_state_data *) override { return kIOReturnUnsupported; } virtual IOReturn setSTA_AUTHORIZE(apple80211_sta_authorize_data *) override { return kIOReturnUnsupported; } virtual IOReturn setSTA_DISASSOCIATE(apple80211_sta_disassoc_data *) override { return kIOReturnUnsupported; } virtual IOReturn setSTA_DEAUTH(apple80211_sta_disassoc_data *) override { return kIOReturnUnsupported; } virtual IOReturn setRSN_CONF(apple80211_rsn_conf_data *) override { return kIOReturnUnsupported; } virtual IOReturn setIE(apple80211_ie_data *) override { return kIOReturnUnsupported; } virtual IOReturn setWOW_TEST(apple80211_wow_test_data *) override { return kIOReturnUnsupported; } virtual IOReturn setSCANCACHE_CLEAR(void *) override; virtual IOReturn setVIRTUAL_IF_CREATE(apple80211_virt_if_create_data *) override { return kIOReturnUnsupported; } virtual IOReturn setBT_COEX_FLAGS(apple80211_state_data *) override { return kIOReturnUnsupported; } virtual IOReturn setROAM(apple80211_sta_roam_data *) override { return kIOReturnUnsupported; } virtual IOReturn setHT_CAPABILITY(apple80211_ht_capability *) override { return kIOReturnUnsupported; } virtual IOReturn setAWDL_FORCED_ROAM_CONFIG(apple80211_awdl_forced_roam_config *) override { return kIOReturnUnsupported; } virtual IOReturn setOFFLOAD_ARP(apple80211_offload_arp_data *) override { return kIOReturnUnsupported; } virtual IOReturn setOFFLOAD_NDP(apple80211_offload_ndp_data *) override { return kIOReturnUnsupported; } virtual IOReturn setOFFLOAD_SCAN(apple80211_offload_scan_data *) override { return kIOReturnUnsupported; } virtual IOReturn setGAS_REQ(apple80211_gas_query_t *) override { return kIOReturnUnsupported; } virtual IOReturn setGAS_START(apple80211_gas_query_t *) override { return kIOReturnUnsupported; } virtual IOReturn setGAS_SET_PEER(apple80211_gas_peer_t *) override { return kIOReturnUnsupported; } virtual IOReturn setVHT_CAPABILITY(apple80211_vht_capability *) override { return kIOReturnUnsupported; } virtual IOReturn setROAM_PROFILE(apple80211_roam_profile_band_data *) override { return kIOReturnUnsupported; } virtual IOReturn setAWDL_ENABLE_ROAMING(void *) override { return kIOReturnUnsupported; } virtual IOReturn setDBG_GUARD_TIME_PARAMS(apple80211_dbg_guard_time_params *) override { return kIOReturnUnsupported; } virtual IOReturn setLEAKY_AP_STATS_MODE(apple80211_leaky_ap_setting *) override { return kIOReturnUnsupported; } virtual IOReturn setPRIVATE_MAC(apple80211_private_mac_data *) override { return kIOReturnUnsupported; } virtual IOReturn setRESET_CHIP(apple80211_reset_command *) override { return kIOReturnUnsupported; } virtual IOReturn setCRASH(apple80211_crash_command *) override { return kIOReturnUnsupported; } virtual IOReturn setRANGING_ENABLE(apple80211_ranging_enable_request_t *) override { return kIOReturnUnsupported; } virtual IOReturn setRANGING_START(apple80211_ranging_start_request_t *) override { return kIOReturnUnsupported; } virtual IOReturn setRANGING_AUTHENTICATE(apple80211_ranging_authenticate_request_t *) override { return kIOReturnUnsupported; } virtual IOReturn setTKO_PARAMS(apple80211_tko_params *) override { return kIOReturnUnsupported; } virtual IOReturn setBTCOEX_PROFILE(apple80211_btcoex_profile *) override { return kIOReturnUnsupported; } virtual IOReturn setBTCOEX_PROFILE_ACTIVE(apple80211_btcoex_profile_active_data *) override { return kIOReturnUnsupported; } virtual IOReturn setTHERMAL_INDEX(apple80211_thermal_index_t *) override { return kIOReturnUnsupported; } virtual IOReturn setBTCOEX_2G_CHAIN_DISABLE(apple80211_btcoex_2g_chain_disable *) override { return kIOReturnUnsupported; } virtual IOReturn setPOWER_BUDGET(apple80211_power_budget_t *) override { return kIOReturnUnsupported; } virtual IOReturn setOFFLOAD_TCPKA_ENABLE(apple80211_offload_tcpka_enable_t *) override { return kIOReturnUnsupported; } virtual IOReturn setSUPPRESS_SCANS(apple80211_suppress_scans_t *) override { return kIOReturnUnsupported; } virtual IOReturn setHOST_AP_MODE_HIDDEN(apple80211_host_ap_mode_hidden_t *) override { return kIOReturnUnsupported; } virtual IOReturn setLQM_CONFIG(apple80211_lqm_config_t *) override { return kIOReturnUnsupported; } virtual IOReturn setSOFTAP_PARAMS(apple80211_softap_params *) override { return kIOReturnUnsupported; } virtual IOReturn setSOFTAP_TRIGGER_CSA(apple80211_softap_csa_params *) override { return kIOReturnUnsupported; } virtual IOReturn setSOFTAP_WIFI_NETWORK_INFO_IE(apple80211_softap_wifi_network_info *) override { return kIOReturnUnsupported; } virtual IOReturn setBTCOEX_DISABLE_ULOFDMA(uint *) override { return kIOReturnUnsupported; } virtual IOReturn setSCAN_CONTROL(apple80211_scan_control_params *) override { return kIOReturnUnsupported; } virtual IOReturn setUSB_HOST_NOTIFICATION(apple80211_usb_host_notification_data *) override { return kIOReturnUnsupported; } virtual IOReturn setSET_MAC_ADDRESS(apple80211_set_mac_address *) override { return kIOReturnUnsupported; } virtual IOReturn setHP2P_CTRL(apple80211_hp2p_ctrl *) override { return kIOReturnUnsupported; } virtual IOReturn setABORT_SCAN(apple80211_abort_scan *) override { return kIOReturnUnsupported; } virtual IOReturn setSET_PROPERTY(apple80211_set_property_unserialized_data *) override { return kIOReturnUnsupported; } virtual IOReturn setROAM_CACHE_UPDATE(apple80211_roam_cache_data *) override { return kIOReturnUnsupported; } virtual IOReturn setPM_MODE(apple80211_pm_mode *) override { return kIOReturnUnsupported; } virtual IOReturn setSET_WIFI_ASSERTION_STATE(apple80211_wifi_assertion_data *) override { return kIOReturnUnsupported; } virtual IOReturn setREASSOCIATE_WITH_CORECAPTURE(apple80211_capture_debug_info_t *) override { return kIOReturnUnsupported; } virtual IOReturn setLINKDOWN_DEBOUNCE_STATUS(apple80211_linkdown_debounce_status *) override { return kIOReturnUnsupported; } virtual IOReturn setSOFTAP_EXTENDED_CAPABILITIES_IE(apple80211_softap_extended_capabilities_info *) override { return kIOReturnUnsupported; } virtual IOReturn setREALTIME_QOS_MSCS(apple80211_state_data *) override { return kIOReturnUnsupported; } virtual IOReturn setSENSING_ENABLE(apple80211_sensing_enable_t *) override { return kIOReturnUnsupported; } virtual IOReturn setSENSING_DISABLE(apple80211_sensing_disable_t *) override { return kIOReturnUnsupported; } virtual IOReturn setNANPHS_ASSOCIATION(apple80211_nan_link_association_info *) override { return kIOReturnUnsupported; } virtual IOReturn setNANPHS_TERMINATED(apple80211_nan_link_association_info *) override { return kIOReturnUnsupported; } virtual IOReturn set6G_MODE(apple80211_6G_mode *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_LEAVE_NETWORK(apple80211_leave_network *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_REASSOC(apple80211_reassoc *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_SET_ROAM_LOCK(apple80211_set_roam_lock *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_ROAM_PROFILE_CONFIG(apple80211_roam_profile_config *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_ROAM_PROFILE_CONFIGV1(apple80211_roam_profile_configV1 *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_ROAM_USER_CACHE(apple80211_user_roam_cache *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_SET_MULTI_AP_ENV(apple80211_set_multi_ap_env *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_SCAN_ABORT(void *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_REAL_TIME_MODE(apple80211_wcl_real_time_mode *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_GARP_MODE(apple80211_wcl_garp_mode *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_JOIN_ABORT(void *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_TRIGGER_CC(triggerCC *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_SCAN_REQ(apple80211ScanRequest *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_ASSOCIATE(apple80211_assoc_candidates *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_PROTECT_IP(apple80211_wcl_protect_ip_mode *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_LINK_UP_DONE(void *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_SET_SCAN_HOME_AWAY_TIME(scanHomeAndAwayTime *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_VOLUNTARY_NETWORK_DISCONNECT(apple80211_wcl_voluntary_network_disconnect *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_LINK_STATE_UPDATE(apple80211_wcl_update_link_state *) override { return kIOReturnUnsupported; } virtual IOReturn setSLOW_WIFI_RECOVERY(void *) override { return kIOReturnUnsupported; } virtual IOReturn setRSN_XE(apple80211_rsn_xe_data *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_ULOFDMA_STATE(apple80211_wcl_ulofdma_state *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_ACTION_FRAME(apple80211_wcl_action_frame *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_REAL_TIME_POLICY(apple80211_wcl_real_time_policy *) override { return kIOReturnUnsupported; } virtual IOReturn setGAS_ABORT(void *) override { return kIOReturnUnsupported; } virtual IOReturn setOS_FEATURE_FLAGS(apple80211_feature_flags *) override { return kIOReturnUnsupported; } virtual IOReturn setDHCP_RENEWAL_DATA(apple80211_dhcp_renewal_data *) override { return kIOReturnUnsupported; } virtual IOReturn setMOVING_NETWORK(apple80211_network_flags *) override { return kIOReturnUnsupported; } virtual IOReturn setBATTERY_POWERSAVE_CONFIG(apple80211_battery_ps_config *) override { return kIOReturnUnsupported; } virtual IOReturn setMIMO_CONFIG(apple80211_mimo_config *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_CONFIG_BG_MOTIONPROFILE(apple80211_bg_motion_profile *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_CONFIG_BG_NETWORK(apple80211_bg_network *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_CONFIG_BGSCAN(apple80211_bg_scan *) override { return kIOReturnUnsupported; } virtual IOReturn setWCL_CONFIG_BG_PARAMS(apple80211_bg_params *) override { return kIOReturnUnsupported; } virtual IOReturn setBLOCKED_BANDS(apple80211_blocked_bands *) override { return kIOReturnUnsupported; } private: AirportItlwm *instance; ItlHalService *fHalService; //IO80211 struct ieee80211_node *fNextNodeToSend; IOTimerEventSource *scanSource; bool fScanResultWrapping; u_int32_t current_authtype_lower; u_int32_t current_authtype_upper; bool disassocIsVoluntary; }; #endif /* AirportItlwmSkywalkInterface_hpp */ ================================================ FILE: AirportItlwm/AirportItlwmV2.cpp ================================================ // // AirportItlwmV2.cpp // AirportItlwm-Sonoma // // Created by qcwap on 2023/6/27. // Copyright © 2023 钟先耀. All rights reserved. // #include "AirportItlwmV2.hpp" #include #include #include #include #include "AirportItlwmSkywalkInterface.hpp" #include "IOPCIEDeviceWrapper.hpp" #define super IO80211Controller OSDefineMetaClassAndStructors(AirportItlwm, IO80211Controller); OSDefineMetaClassAndStructors(CTimeout, OSObject) IO80211WorkQueue *_fWorkloop; IOCommandGate *_fCommandGate; void AirportItlwm::releaseAll() { OSSafeReleaseNULL(driverLogPipe); OSSafeReleaseNULL(driverDataPathPipe); OSSafeReleaseNULL(driverSnapshotsPipe); OSSafeReleaseNULL(driverFaultReporter); 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:: eventHandler(struct ieee80211com *ic, int msgCode, void *data) { AirportItlwm *that = OSDynamicCast(AirportItlwm, ic->ic_ac.ac_if.controller); IO80211SkywalkInterface *interface = that->fNetIf; if (!interface) return; switch (msgCode) { case IEEE80211_EVT_COUNTRY_CODE_UPDATE: interface->postMessage(APPLE80211_M_COUNTRY_CODE_CHANGED, NULL, 0, 0); break; case IEEE80211_EVT_STA_ASSOC_DONE: interface->postMessage(APPLE80211_M_ASSOC_DONE, NULL, 0, 0); break; case IEEE80211_EVT_STA_DEAUTH: interface->postMessage(APPLE80211_M_DEAUTH_RECEIVED, NULL, 0, 0); break; default: break; } } 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) { UInt32 msg = 0; AirportItlwm *that = (AirportItlwm *)owner; that->fNetIf->postMessage(APPLE80211_M_SCAN_DONE, &msg, 4, 0); } bool AirportItlwm::init(OSDictionary *properties) { XYLog("%s\n", __PRETTY_FUNCTION__); bool ret = super::init(properties); awdlSyncEnable = true; power_state = 0; memset(geo_location_cc, 0, sizeof(geo_location_cc)); return ret; } IOService* AirportItlwm::probe(IOService *provider, SInt32 *score) { XYLog("%s\n", __PRETTY_FUNCTION__); IOPCIEDeviceWrapper *wrapper = OSDynamicCast(IOPCIEDeviceWrapper, provider); if (!wrapper) { XYLog("%s Not a IOPCIEDeviceWrapper instance\n", __FUNCTION__); return NULL; } pciNub = wrapper->pciNub; fHalService = wrapper->fHalService; if (!pciNub || !fHalService) { XYLog("%s Not a valid IOPCIEDeviceWrapper instance\n", __FUNCTION__); return NULL; } return super::probe(provider, score); } #define LOWER32(x) ((uint64_t)(x) & 0xffffffff) #define HIGHER32(x) ((uint64_t)(x) >> 32) bool AirportItlwm:: initCCLogs() { CCPipeOptions driverLogOptions = { 0 }; driverLogOptions.pipe_type = 0; driverLogOptions.log_data_type = 1; driverLogOptions.pipe_size = 0x200000; driverLogOptions.min_log_size_notify = 0xccccc; driverLogOptions.notify_threshold = 1000; strlcpy(driverLogOptions.file_name, "Itlwm_Logs", sizeof(driverLogOptions.file_name)); snprintf(driverLogOptions.name, sizeof(driverLogOptions.name), "wlan%d", 0); strlcpy(driverLogOptions.directory_name, "WiFi", sizeof(driverLogOptions.directory_name)); driverLogOptions.pad9 = 0x1000000; driverLogOptions.pad10 = 2; driverLogOptions.file_options = 0; driverLogOptions.log_policy = 0; driverLogPipe = CCPipe::withOwnerNameCapacity(this, "com.zxystd.AirportItlwm", "DriverLogs", &driverLogOptions); XYLog("%s driverLogPipeRet %d\n", __FUNCTION__, driverLogPipe != NULL); memset(&driverLogOptions, 0, sizeof(driverLogOptions)); driverLogOptions.pipe_type = 0; driverLogOptions.log_data_type = 0; driverLogOptions.pipe_size = 0x200000; driverLogOptions.min_log_size_notify = 0xccccc; driverLogOptions.notify_threshold = 1000; strlcpy(driverLogOptions.file_name, "AppleBCMWLAN_Datapath", sizeof(driverLogOptions.file_name)); strlcpy(driverLogOptions.directory_name, "WiFi", sizeof(driverLogOptions.directory_name)); driverLogOptions.pad9 = HIGHER32(0x202800000); driverLogOptions.pad10 = LOWER32(0x202800000); driverLogOptions.file_options = 0; driverLogOptions.log_policy = 0; driverDataPathPipe = CCPipe::withOwnerNameCapacity(this, "com.zxystd.AirportItlwm", "DatapathEvents", &driverLogOptions); XYLog("%s driverDataPathPipeRet %d\n", __FUNCTION__, driverDataPathPipe != NULL); memset(&driverLogOptions, 0, sizeof(driverLogOptions)); driverLogOptions.pipe_type = 0x200000001; driverLogOptions.log_data_type = 2; strlcpy(driverLogOptions.file_name, "StateSnapshots", sizeof(driverLogOptions.file_name)); strlcpy(driverLogOptions.name, "0", sizeof(driverLogOptions.name)); strlcpy(driverLogOptions.directory_name, "WiFi", sizeof(driverLogOptions.directory_name)); driverLogOptions.pipe_size = 128; driverSnapshotsPipe = CCPipe::withOwnerNameCapacity(this, "com.zxystd.AirportItlwm", "StateSnapshots", &driverLogOptions); XYLog("%s driverSnapshotsPipeRet %d\n", __FUNCTION__, driverSnapshotsPipe != NULL); CCStreamOptions faultReportOptions = { 0 }; faultReportOptions.stream_type = 1; faultReportOptions.console_level = 0xFFFFFFFFFFFFFFFF; driverFaultReporter = CCStream::withPipeAndName(driverSnapshotsPipe, "FaultReporter", &faultReportOptions); XYLog("%s driverFaultReporterRet %d\n", __FUNCTION__, driverFaultReporter != NULL); return driverLogPipe && driverDataPathPipe && driverSnapshotsPipe && driverFaultReporter; } bool AirportItlwm::start(IOService *provider) { XYLog("%s\n", __PRETTY_FUNCTION__); struct IOSkywalkEthernetInterface::RegistrationInfo registInfo; int boot_value = 0; UInt8 builtIn = 0; setProperty("built-in", OSData::withBytes(&builtIn, sizeof(builtIn))); setProperty("DriverKitDriver", kOSBooleanFalse); if (!super::start(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; } 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(); fNetIf = new AirportItlwmSkywalkInterface; if (!fNetIf->init(this)) { XYLog("Skywalk interface init fail\n"); super::stop(provider); releaseAll(); return false; } fNetIf->setInterfaceRole(1); fNetIf->setInterfaceId(1); if (!initCCLogs()) { XYLog("CCLog init fail\n"); super::stop(provider); releaseAll(); return false; } if (!fNetIf->attach(this)) { XYLog("attach to service fail\n"); super::stop(provider); releaseAll(); return false; } if (!attachInterface(fNetIf, this)) { XYLog("attach to interface fail\n"); super::stop(provider); releaseAll(); return false; } if (!IONetworkController::attachInterface((IONetworkInterface **)&bsdInterface, true)) { XYLog("attach to IONetworkController interface fail\n"); super::stop(provider); releaseAll(); return false; } memset(®istInfo, 0, sizeof(registInfo)); if (!fNetIf->initRegistrationInfo(®istInfo, 1, sizeof(registInfo))) { XYLog("initRegistrationInfo fail\n"); super::stop(provider); releaseAll(); return false; } if (!fNetIf->initRegistrationInfo(®istInfo, 1, sizeof(registInfo))) { XYLog("initRegistrationInfo fail\n"); super::stop(provider); releaseAll(); return false; } fNetIf->mExpansionData->fRegistrationInfo = (struct IOSkywalkNetworkInterface::RegistrationInfo *)IOMalloc(sizeof(struct IOSkywalkNetworkInterface::RegistrationInfo)); fNetIf->mExpansionData2->fRegistrationInfo = (struct IOSkywalkEthernetInterface::RegistrationInfo *)IOMalloc(sizeof(struct IOSkywalkEthernetInterface::RegistrationInfo)); memcpy(fNetIf->mExpansionData->fRegistrationInfo, ®istInfo, sizeof(registInfo)); memcpy(fNetIf->mExpansionData2->fRegistrationInfo, ®istInfo, sizeof(registInfo)); if (fNetIf->getInterfaceRole() == 1) fNetIf->deferBSDAttach(true); fNetIf->start(this); setLinkStatus(kIONetworkLinkValid); if (TAILQ_EMPTY(&fHalService->get80211Controller()->ic_ess)) fHalService->get80211Controller()->ic_flags |= IEEE80211_F_AUTO_JOIN; registerService(); return true; } void AirportItlwm::stop(IOService *provider) { XYLog("%s\n", __PRETTY_FUNCTION__);XYLog("%s\n", __PRETTY_FUNCTION__); struct _ifnet *ifp = &fHalService->get80211Controller()->ic_ac.ac_if; super::stop(provider); disableAdapter(bsdInterface); setLinkStatus(kIONetworkLinkValid); fHalService->detach(pciNub); ether_ifdetach(ifp); detachInterface(fNetIf, true); OSSafeReleaseNULL(fNetIf); releaseAll(); } void AirportItlwm::free() { XYLog("%s\n", __PRETTY_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(); } bool AirportItlwm::createWorkQueue() { XYLog("%s %d\n", __FUNCTION__, _fWorkloop != 0); return _fWorkloop != 0; } IO80211WorkQueue *AirportItlwm::getWorkQueue() { return _fWorkloop; } void *AirportItlwm::getFaultReporterFromDriver() { return driverFaultReporter; } IOReturn AirportItlwm::enable(IO80211SkywalkInterface *netif) { XYLog("%s\n", __PRETTY_FUNCTION__); super::enable(netif); _fCommandGate->enable(); if (power_state) enableAdapter(bsdInterface); return kIOReturnSuccess; } IOReturn AirportItlwm::disable(IO80211SkywalkInterface *netif) { XYLog("%s\n", __PRETTY_FUNCTION__); super::disable(netif); setLinkStatus(kIONetworkLinkValid); return kIOReturnSuccess; } 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() { AirportItlwmEthernetInterface *netif = new AirportItlwmEthernetInterface; if (!netif) return NULL; if (!netif->initWithSkywalkInterfaceAndProvider(this, fNetIf)) { netif->release(); return NULL; } return netif; } bool AirportItlwm::createMediumTables(const IONetworkMedium **primary) { IONetworkMedium *medium; OSDictionary *mediumDict = OSDictionary::withCapacity(2); if (mediumDict == NULL) { XYLog("Cannot allocate OSDictionary\n"); return false; } medium = IONetworkMedium::medium(kIOMediumIEEE80211, 54000000); IONetworkMedium::addMedium(mediumDict, medium); medium->release(); if (primary) { *primary = medium; } medium = IONetworkMedium::medium(kIOMediumIEEE80211None, 0); IONetworkMedium::addMedium(mediumDict, medium); medium->release(); bool result = publishMediumDictionary(mediumDict); if (!result) { XYLog("Cannot publish medium dictionary!\n"); } mediumDict->release(); return result; } IOReturn AirportItlwm::selectMedium(const IONetworkMedium *medium) { setSelectedMedium(medium); return kIOReturnSuccess; } 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__ bsdInterface->startOutputThread(); #endif getCommandGate()->runAction(setLinkStateGated, (void *)kIO80211NetworkLinkUp, (void *)0); // fNetIf->setLinkQualityMetric(100); } else if (!(status & kIONetworkLinkNoNetworkChange)) { #ifdef __PRIVATE_SPI__ bsdInterface->stopOutputThread(); bsdInterface->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->fNetIf->setLinkState((IO80211LinkState)(uint64_t)arg0, (unsigned int)(uint64_t)arg1); that->fNetIf->setRunningState((IO80211LinkState)(uint64_t)arg0 == kIO80211NetworkLinkUp); that->fNetIf->postMessage(APPLE80211_M_LINK_CHANGED, NULL, 0, false); that->fNetIf->postMessage(APPLE80211_M_BSSID_CHANGED, NULL, 0, false); that->fNetIf->postMessage(APPLE80211_M_SSID_CHANGED, NULL, 0, false); if ((IO80211LinkState)(uint64_t)arg0 == kIO80211NetworkLinkUp) { that->fNetIf->reportLinkStatus(3, 0x80); } else { that->fNetIf->reportLinkStatus(1, 0); } that->bsdInterface->setLinkState((IO80211LinkState)(uint64_t)arg0); return ret; } #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; } IOReturn AirportItlwm::networkInterfaceNotification( IONetworkInterface * interface, uint32_t type, void * argument ) { XYLog("%s\n", __FUNCTION__); return kIOReturnSuccess; } #endif extern const char* hexdump(uint8_t *buf, size_t len); 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; } size_t len = mbuf_len(m); ether_header_t *eh = (ether_header_t *)mbuf_data(m); if (len >= sizeof(ether_header_t) && eh->ether_type == htons(ETHERTYPE_PAE)) { // EAPOL packet const char* dump = hexdump((uint8_t*)mbuf_data(m), len); XYLog("output EAPOL packet, len: %zu, data: %s\n", len, dump ? dump : "Failed to allocate memory"); if (dump) IOFree((void*)dump, 3 * len + 1); } if (!ifp->if_snd.queue->lockEnqueue(m)) { freePacket(m); ret = kIOReturnOutputDropped; } (*ifp->if_start)(ifp); return ret; } const OSString * AirportItlwm::newVendorString() const { return OSString::withCString("Apple"); } const OSString * AirportItlwm::newModelString() const { return OSString::withCString(fHalService->getDriverInfo()->getFirmwareName()); } 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 void *addrP, UInt32 addrBytes) { if (!fNetIf || !addrP) return kIOReturnError; if_setlladdr(&fHalService->get80211Controller()->ic_ac.ac_if, (const UInt8 *)addrP); if (fHalService->get80211Controller()->ic_state > IEEE80211_S_INIT) { fHalService->disable(bsdInterface); fHalService->enable(bsdInterface); } return kIOReturnSuccess; } 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); } 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; } SInt32 AirportItlwm:: enableFeature(IO80211FeatureCode code, void *data) { if (code == kIO80211Feature80211n) { return 0; } return 102; } bool AirportItlwm::getLogPipes(CCPipe**logPipe, CCPipe**eventPipe, CCPipe**snapshotsPipe) { bool ret = false; if (logPipe) { *logPipe = driverLogPipe; ret = true; } if (eventPipe) { *eventPipe = driverDataPathPipe; ret = true; } if (snapshotsPipe) { *snapshotsPipe = driverSnapshotsPipe; ret = true; } return ret; } #define APPLE80211_CAPA_AWDL_FEATURE_AUTO_UNLOCK 0x00000004 #define APPLE80211_CAPA_AWDL_FEATURE_WOW 0x00000080 IOReturn AirportItlwm:: getCARD_CAPABILITIES(OSObject *object, struct apple80211_capability_data *cd) { uint32_t caps = fHalService->get80211Controller()->ic_caps; memset(cd, 0, sizeof(struct apple80211_capability_data)); if (caps & IEEE80211_C_WEP) cd->capabilities[0] |= 1 << APPLE80211_CAP_WEP; if (caps & IEEE80211_C_RSN) cd->capabilities[0] |= 1 << APPLE80211_CAP_TKIP | 1 << APPLE80211_CAP_AES_CCM; // Disable not implemented capabilities // if (caps & IEEE80211_C_PMGT) // cd->capabilities[0] |= 1 << APPLE80211_CAP_PMGT; // if (caps & IEEE80211_C_IBSS) // cd->capabilities[0] |= 1 << APPLE80211_CAP_IBSS; // if (caps & IEEE80211_C_HOSTAP) // cd->capabilities[0] |= 1 << APPLE80211_CAP_HOSTAP; // AES not enabled, like on Apple cards if (caps & IEEE80211_C_SHSLOT) cd->capabilities[1] |= 1 << (APPLE80211_CAP_SHSLOT - 8); if (caps & IEEE80211_C_SHPREAMBLE) cd->capabilities[1] |= 1 << (APPLE80211_CAP_SHPREAMBLE - 8); if (caps & IEEE80211_C_RSN) cd->capabilities[1] |= 1 << (APPLE80211_CAP_WPA1 - 8) | 1 << (APPLE80211_CAP_WPA2 - 8) | 1 << (APPLE80211_CAP_TKIPMIC - 8); // Disable not implemented capabilities // if (caps & IEEE80211_C_TXPMGT) // cd->capabilities[1] |= 1 << (APPLE80211_CAP_TXPMGT - 8); // if (caps & IEEE80211_C_MONITOR) // cd->capabilities[1] |= 1 << (APPLE80211_CAP_MONITOR - 8); // WPA not enabled, like on Apple cards cd->version = APPLE80211_VERSION; cd->capabilities[2] = 0xFF; // BURST, WME, SHORT_GI_40MHZ, SHORT_GI_20MHZ, WOW, TSN, ?, ? cd->capabilities[3] = 0x2B; cd->capabilities[5] = 0x40; cd->capabilities[6] = ( // 1 | //MFP capable 0x8 | 0x4 | 0x80 ); *(uint16_t *)&cd->capabilities[8] = 0x201; // // cd->capabilities[2] |= 0x10; // cd->capabilities[5] |= 0x1; // // cd->capabilities[2] |= 0x2; // // cd->capabilities[3] |= 0x20; // // cd->capabilities[0] |= 0x80; // // cd->capabilities[3] |= 0x80; // cd->capabilities[4] |= 0x4; // // cd->capabilities[4] |= 0x1; // cd->capabilities[3] |= 0x1; // cd->capabilities[6] |= 0x8; // // cd->capabilities[3] |= 3; // cd->capabilities[4] |= 2; // cd->capabilities[6] |= 0x10; // cd->capabilities[5] |= 0x20; // cd->capabilities[5] |= 0x80; // // if (cd->capabilities[6] & 0x20) { // cd->capabilities[2] |= 8; // } // cd->capabilities[5] |= 8; // cd->capabilities[8] |= 2; // // cd->capabilities[11] |= (2 | 4 | 8 | 0x10 | 0x20 | 0x40 | 0x80); return kIOReturnSuccess; } IOReturn AirportItlwm:: getDRIVER_VERSION(OSObject *object, struct apple80211_version_data *hv) { if (!hv) return kIOReturnError; hv->version = APPLE80211_VERSION; snprintf(hv->string, sizeof(hv->string), "itlwm: %s%s fw: %s", ITLWM_VERSION, GIT_COMMIT, fHalService->getDriverInfo()->getFirmwareVersion()); hv->string_len = strlen(hv->string); return kIOReturnSuccess; } IOReturn AirportItlwm:: getHARDWARE_VERSION(OSObject *object, struct apple80211_version_data *hv) { if (!hv) return kIOReturnError; hv->version = APPLE80211_VERSION; strncpy(hv->string, fHalService->getDriverInfo()->getFirmwareVersion(), sizeof(hv->string)); hv->string_len = strlen(fHalService->getDriverInfo()->getFirmwareVersion()); return kIOReturnSuccess; } IOReturn AirportItlwm:: getCOUNTRY_CODE(OSObject *object, struct apple80211_country_code_data *cd) { char user_override_cc[3]; const char *cc_fw = fHalService->getDriverInfo()->getFirmwareCountryCode(); if (!cd) return kIOReturnError; cd->version = APPLE80211_VERSION; memset(user_override_cc, 0, sizeof(user_override_cc)); PE_parse_boot_argn("itlwm_cc", user_override_cc, 3); /* user_override_cc > firmware_cc > geo_location_cc */ strncpy((char*)cd->cc, user_override_cc[0] ? user_override_cc : ((cc_fw[0] == 'Z' && cc_fw[1] == 'Z' && geo_location_cc[0]) ? geo_location_cc : cc_fw), sizeof(cd->cc)); return kIOReturnSuccess; } IOReturn AirportItlwm:: setCOUNTRY_CODE(OSObject *object, struct apple80211_country_code_data *data) { XYLog("%s cc=%s\n", __FUNCTION__, data->cc); if (data && data->cc[0] != 120 && data->cc[0] != 88) { memcpy(geo_location_cc, data->cc, sizeof(geo_location_cc)); fNetIf->postMessage(APPLE80211_M_COUNTRY_CODE_CHANGED, NULL, 0, 0); } return kIOReturnSuccess; } IOReturn AirportItlwm:: getPOWER(OSObject *object, struct apple80211_power_data *pd) { if (!pd) return kIOReturnError; pd->version = APPLE80211_VERSION; pd->num_radios = 4; pd->power_state[0] = power_state; pd->power_state[1] = power_state; pd->power_state[2] = power_state; pd->power_state[3] = power_state; return kIOReturnSuccess; } IOReturn AirportItlwm:: setPOWER(OSObject *object, struct apple80211_power_data *pd) { if (!pd) return kIOReturnError; IOLog("itlwm: setPOWER: num_radios[%d] power_state(0:%u 1:%u 2:%u 3:%u)\n", pd->num_radios, pd->power_state[0], pd->power_state[1], pd->power_state[2], pd->power_state[3]); if (pd->num_radios > 0) { bool isRunning = (fHalService->get80211Controller()->ic_ac.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) != 0; if (pd->power_state[0] == 0) { changePowerStateToPriv(1); if (isRunning) { net80211_ifstats(fHalService->get80211Controller()); disableAdapter(bsdInterface); } } else { changePowerStateToPriv(2); if (!isRunning) enableAdapter(bsdInterface); } power_state = (pd->power_state[0]); } return kIOReturnSuccess; } SInt32 AirportItlwm::apple80211_ioctl(IO80211SkywalkInterface *interface,unsigned long cmd,void *data, bool b1, bool b2) { if (!ml_at_interrupt_context()) XYLog("%s cmd: %s b1: %d b2: %d\n", __FUNCTION__, convertApple80211IOCTLToString((unsigned int)cmd), b1, b2); return super::apple80211_ioctl(interface, cmd, data, b1, b2); } SInt32 AirportItlwm::apple80211SkywalkRequest(UInt request,int cmd,IO80211SkywalkInterface *interface,void *data) { if (!ml_at_interrupt_context()) XYLog("%s 1 cmd: %s request: %d\n", __FUNCTION__, convertApple80211IOCTLToString(cmd), request); return kIOReturnUnsupported; } SInt32 AirportItlwm::apple80211SkywalkRequest(UInt request,int cmd,IO80211SkywalkInterface *interface,void *data,void *) { if (!ml_at_interrupt_context()) XYLog("%s 2 cmd: %s request: %d\n", __FUNCTION__, convertApple80211IOCTLToString(cmd), request); return kIOReturnUnsupported; } 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:: 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 (&deadline)); if (_fCommandGate->commandSleep(arg0, deadline, THREAD_INTERRUPTIBLE) == THREAD_AWAKENED) return kIOReturnSuccess; else return kIOReturnTimeout; } } 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; } 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(bsdInterface); pmPolicyMaker->acknowledgeSetPowerState(); } void AirportItlwm::setPowerStateOn() { XYLog("%s\n", __FUNCTION__); pmPowerState = kPowerStateOn; pmPolicyMaker->acknowledgeSetPowerState(); } ================================================ FILE: AirportItlwm/AirportItlwmV2.hpp ================================================ // // AirportItlwmV2.hpp // AirportItlwm-Sonoma // // Created by qcwap on 2023/6/27. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef AirportItlwmV2_hpp #define AirportItlwmV2_hpp #include "Apple80211.h" #include "IOKit/network/IOGatedOutputQueue.h" #include #include #include #include #include #include #include #include "ItlIwm.hpp" #include "ItlIwx.hpp" #include "ItlIwn.hpp" #include "AirportItlwmEthernetInterface.hpp" enum { kPowerStateOff = 0, kPowerStateOn, kPowerStateCount }; #define kWatchDogTimerPeriod 1000 extern "C" { const char *convertApple80211IOCTLToString(signed int cmd); } class AirportItlwm : public IO80211Controller { OSDeclareDefaultStructors(AirportItlwm) #define IOCTL(REQ_TYPE, REQ, DATA_TYPE) \ if (REQ_TYPE == SIOCGA80211) { \ ret = get##REQ(interface, (struct DATA_TYPE* )data); \ } else { \ ret = set##REQ(interface, (struct DATA_TYPE* )data); \ } #define IOCTL_GET(REQ_TYPE, REQ, DATA_TYPE) \ if (REQ_TYPE == SIOCGA80211) { \ ret = get##REQ(interface, (struct DATA_TYPE* )data); \ } #define IOCTL_SET(REQ_TYPE, REQ, DATA_TYPE) \ if (REQ_TYPE == SIOCSA80211) { \ ret = set##REQ(interface, (struct DATA_TYPE* )data); \ } #define FUNC_IOCTL(REQ, DATA_TYPE) \ FUNC_IOCTL_GET(REQ, DATA_TYPE) \ FUNC_IOCTL_SET(REQ, DATA_TYPE) #define FUNC_IOCTL_GET(REQ, DATA_TYPE) \ IOReturn get##REQ(OSObject *object, struct DATA_TYPE *data); #define FUNC_IOCTL_SET(REQ, DATA_TYPE) \ IOReturn set##REQ(OSObject *object, struct DATA_TYPE *data); public: virtual bool init(OSDictionary *properties) override; virtual void free() override; virtual IOService* probe(IOService* provider, SInt32* score) override; virtual bool start(IOService *provider) override; virtual void stop(IOService *provider) override; virtual IOReturn enable(IO80211SkywalkInterface *netif) override; virtual IOReturn disable(IO80211SkywalkInterface *netif) override; virtual IOReturn setHardwareAddress(const void *addr, UInt32 addrBytes) override; virtual IOReturn getHardwareAddress(IOEthernetAddress* addrP) override; virtual IOReturn getPacketFilters(const OSSymbol *group, UInt32 *filters) const override; virtual IOReturn setPromiscuousMode(IOEnetPromiscuousMode mode) override; virtual IOReturn setMulticastMode(IOEnetMulticastMode mode) override; virtual IOReturn setMulticastList(IOEthernetAddress* addr, UInt32 len) override; virtual UInt32 getFeatures() const override; virtual const OSString * newVendorString() const override; virtual const OSString * newModelString() const override; virtual IOReturn selectMedium(const IONetworkMedium *medium) override; virtual bool createWorkQueue() override; virtual IONetworkInterface * createInterface() override; virtual bool configureInterface(IONetworkInterface *netif) override; virtual UInt32 outputPacket(mbuf_t, void * param) override; #ifdef __PRIVATE_SPI__ virtual IOReturn outputStart(IONetworkInterface *interface, IOOptionBits options) override; virtual IOReturn networkInterfaceNotification( IONetworkInterface * interface, uint32_t type, void * argument ) override; #endif virtual bool setLinkStatus( UInt32 status, const IONetworkMedium * activeMedium = 0, UInt64 speed = 0, OSData * data = 0) override; static IOReturn setLinkStateGated(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); static IOReturn tsleepHandler(OSObject* owner, void* arg0 = 0, void* arg1 = 0, void* arg2 = 0, void* arg3 = 0); static void eventHandler(struct ieee80211com *, int, void *); IOReturn enableAdapter(IONetworkInterface *netif); void disableAdapter(IONetworkInterface *netif); bool initCCLogs(); virtual IO80211WorkQueue *getWorkQueue() override; virtual bool requiresExplicitMBufRelease() override { return false; } virtual bool flowIdSupported() override { return false; } virtual SInt32 monitorModeSetEnabled(bool, UInt) override { return kIOReturnSuccess; } virtual IOReturn requestQueueSizeAndTimeout(unsigned short *queue, unsigned short *timeout) override { XYLog("%s\n", __FUNCTION__); return kIOReturnSuccess; } virtual bool getLogPipes(CCPipe**, CCPipe**, CCPipe**) override; virtual void *getFaultReporterFromDriver() override; virtual SInt32 apple80211_ioctl(IO80211SkywalkInterface *,unsigned long,void *, bool, bool) override; virtual SInt32 apple80211SkywalkRequest(UInt,int,IO80211SkywalkInterface *,void *) override; virtual SInt32 apple80211SkywalkRequest(UInt,int,IO80211SkywalkInterface *,void *,void *) override; bool createMediumTables(const IONetworkMedium **primary); void releaseAll(); void watchdogAction(IOTimerEventSource *timer); virtual SInt32 enableFeature(IO80211FeatureCode, void*) override; virtual bool isCommandProhibited(int command) override { // if (!ml_at_interrupt_context()) // XYLog("%s %s\n", __FUNCTION__, convertApple80211IOCTLToString(command)); return false; }; virtual SInt32 handleCardSpecific(IO80211SkywalkInterface *,unsigned long,void *,bool) override { XYLog("%s\n", __FUNCTION__); return 0; }; virtual IOReturn getDRIVER_VERSION(IO80211SkywalkInterface *interface,apple80211_version_data *data) override { XYLog("%s\n", __FUNCTION__); return getDRIVER_VERSION((OSObject *)interface, data); }; virtual IOReturn getHARDWARE_VERSION(IO80211SkywalkInterface *interface,apple80211_version_data *data) override { XYLog("%s\n", __FUNCTION__); return getHARDWARE_VERSION((OSObject *)interface, data); }; virtual IOReturn getCARD_CAPABILITIES(IO80211SkywalkInterface *interface,apple80211_capability_data *data) override { // XYLog("%s\n", __FUNCTION__); return getCARD_CAPABILITIES((OSObject *)interface, data); } virtual IOReturn getPOWER(IO80211SkywalkInterface *interface,apple80211_power_data *data) override { // XYLog("%s\n", __FUNCTION__); return getPOWER((OSObject *)interface, data); } virtual IOReturn setPOWER(IO80211SkywalkInterface *interface,apple80211_power_data *data) override { // XYLog("%s\n", __FUNCTION__); return setPOWER((OSObject *)interface, data); } virtual IOReturn getCOUNTRY_CODE(IO80211SkywalkInterface *interface,apple80211_country_code_data *data) override { // XYLog("%s\n", __FUNCTION__); return getCOUNTRY_CODE((OSObject *)interface, data); } virtual IOReturn setCOUNTRY_CODE(IO80211SkywalkInterface *interface,apple80211_country_code_data *data) override { // XYLog("%s\n", __FUNCTION__); return setCOUNTRY_CODE((OSObject *)interface, data); } virtual IOReturn setGET_DEBUG_INFO(IO80211SkywalkInterface *interface,apple80211_debug_command *data) override { XYLog("%s\n", __FUNCTION__); return kIOReturnSuccess; } //scan static void fakeScanDone(OSObject *owner, IOTimerEventSource *sender); //----------------------------------------------------------------------- // Power management support. //----------------------------------------------------------------------- virtual IOReturn registerWithPolicyMaker( IOService * policyMaker ) override; virtual IOReturn setPowerState( unsigned long powerStateOrdinal, IOService * policyMaker) override; virtual IOReturn setWakeOnMagicPacket( bool active ) override; void setPowerStateOff(void); void setPowerStateOn(void); void unregistPM(); bool initPCIPowerManagment(IOPCIDevice *provider); FUNC_IOCTL_GET(CARD_CAPABILITIES, apple80211_capability_data) FUNC_IOCTL(POWER, apple80211_power_data) FUNC_IOCTL_GET(DRIVER_VERSION, apple80211_version_data) FUNC_IOCTL_GET(HARDWARE_VERSION, apple80211_version_data) FUNC_IOCTL(COUNTRY_CODE, apple80211_country_code_data) public: IOInterruptEventSource* fInterrupt; IOTimerEventSource *watchdogTimer; IOPCIDevice *pciNub; IONetworkStats *fpNetStats; AirportItlwmEthernetInterface *bsdInterface; IO80211SkywalkInterface *fNetIf; IOWorkLoop *fWatchdogWorkLoop; ItlHalService *fHalService; //IO80211 uint8_t power_state; struct ieee80211_node *fNextNodeToSend; bool fScanResultWrapping; IOTimerEventSource *scanSource; u_int32_t current_authtype_lower; u_int32_t current_authtype_upper; UInt64 currentSpeed; UInt32 currentStatus; bool disassocIsVoluntary; char geo_location_cc[3]; //pm thread_call_t powerOnThreadCall; thread_call_t powerOffThreadCall; UInt32 pmPowerState; IOService *pmPolicyMaker; UInt8 pmPCICapPtr; bool magicPacketEnabled; bool magicPacketSupported; //AWDL uint8_t *syncFrameTemplate; uint32_t syncFrameTemplateLength; uint8_t awdlBSSID[6]; uint32_t awdlSyncState; uint32_t awdlElectionId; uint32_t awdlPresenceMode; uint16_t awdlMasterChannel; uint16_t awdlSecondaryMasterChannel; uint8_t *roamProfile; struct apple80211_btc_profiles_data *btcProfile; struct apple80211_btc_config_data btcConfig; uint32_t btcMode; uint32_t btcOptions; bool awdlSyncEnable; CCPipe *driverLogPipe; CCPipe *driverDataPathPipe; CCPipe *driverSnapshotsPipe; CCStream *driverFaultReporter; }; #endif /* AirportItlwmV2_hpp */ ================================================ FILE: AirportItlwm/AirportSTAIOCTL.cpp ================================================ // // AirportSTAIOCTL.cpp // AirportItlwm // // Created by qcwap on 2020/9/4. // Copyright © 2020 钟先耀. All rights reserved. // #include "AirportItlwm.hpp" #include extern IOCommandGate *_fCommandGate; const char* hexdump(uint8_t *buf, size_t len); SInt32 AirportItlwm::apple80211Request(unsigned int request_type, int request_number, IO80211Interface *interface, void *data) { if (request_type != SIOCGA80211 && request_type != SIOCSA80211) return kIOReturnError; IOReturn ret = kIOReturnError; switch (request_number) { case APPLE80211_IOC_SSID: // 1 IOCTL(request_type, SSID, apple80211_ssid_data); break; case APPLE80211_IOC_AUTH_TYPE: // 2 IOCTL(request_type, AUTH_TYPE, apple80211_authtype_data); break; case APPLE80211_IOC_CHANNEL: // 4 IOCTL(request_type, CHANNEL, apple80211_channel_data); break; case APPLE80211_IOC_PROTMODE: IOCTL(request_type, PROTMODE, apple80211_protmode_data); break; case APPLE80211_IOC_TXPOWER: // 7 IOCTL_GET(request_type, TXPOWER, apple80211_txpower_data); break; case APPLE80211_IOC_RATE: // 8 IOCTL_GET(request_type, RATE, apple80211_rate_data); break; case APPLE80211_IOC_BSSID: // 9 IOCTL(request_type, BSSID, apple80211_bssid_data); break; case APPLE80211_IOC_SCAN_REQ: // 10 IOCTL_SET(request_type, SCAN_REQ, apple80211_scan_data); break; case APPLE80211_IOC_SCAN_REQ_MULTIPLE: IOCTL_SET(request_type, SCAN_REQ_MULTIPLE, apple80211_scan_multiple_data); break; case APPLE80211_IOC_SCAN_RESULT: // 11 IOCTL_GET(request_type, SCAN_RESULT, apple80211_scan_result*); break; case APPLE80211_IOC_CARD_CAPABILITIES: // 12 IOCTL_GET(request_type, CARD_CAPABILITIES, apple80211_capability_data); break; case APPLE80211_IOC_STATE: // 13 IOCTL_GET(request_type, STATE, apple80211_state_data); break; case APPLE80211_IOC_PHY_MODE: // 14 IOCTL_GET(request_type, PHY_MODE, apple80211_phymode_data); break; case APPLE80211_IOC_OP_MODE: // 15 IOCTL_GET(request_type, OP_MODE, apple80211_opmode_data); break; case APPLE80211_IOC_RSSI: // 16 IOCTL_GET(request_type, RSSI, apple80211_rssi_data); break; case APPLE80211_IOC_NOISE: // 17 IOCTL_GET(request_type, NOISE, apple80211_noise_data); break; case APPLE80211_IOC_INT_MIT: // 18 IOCTL_GET(request_type, INT_MIT, apple80211_intmit_data); break; case APPLE80211_IOC_POWER: // 19 IOCTL(request_type, POWER, apple80211_power_data); break; case APPLE80211_IOC_ASSOCIATE: // 20 IOCTL_SET(request_type, ASSOCIATE, apple80211_assoc_data); break; case APPLE80211_IOC_ASSOCIATE_RESULT: // 21 IOCTL_GET(request_type, ASSOCIATE_RESULT, apple80211_assoc_result_data); break; case APPLE80211_IOC_DISASSOCIATE: // 22 if (request_type == SIOCSA80211) setDISASSOCIATE(interface); break; case APPLE80211_IOC_RATE_SET: IOCTL_GET(request_type, RATE_SET, apple80211_rate_set_data); break; case APPLE80211_IOC_MCS_INDEX_SET: IOCTL_GET(request_type, MCS_INDEX_SET, apple80211_mcs_index_set_data); break; case APPLE80211_IOC_VHT_MCS_INDEX_SET: IOCTL_GET(request_type, VHT_MCS_INDEX_SET, apple80211_vht_mcs_index_set_data); break; case APPLE80211_IOC_MCS_VHT: IOCTL(request_type, MCS_VHT, apple80211_mcs_vht_data); break; case APPLE80211_IOC_SUPPORTED_CHANNELS: // 27 case APPLE80211_IOC_HW_SUPPORTED_CHANNELS: IOCTL_GET(request_type, SUPPORTED_CHANNELS, apple80211_sup_channel_data); break; case APPLE80211_IOC_LOCALE: // 28 IOCTL_GET(request_type, LOCALE, apple80211_locale_data); break; case APPLE80211_IOC_DEAUTH: IOCTL(request_type, DEAUTH, apple80211_deauth_data); break; case APPLE80211_IOC_TX_ANTENNA: // 37 IOCTL_GET(request_type, TX_ANTENNA, apple80211_antenna_data); break; case APPLE80211_IOC_ANTENNA_DIVERSITY: // 39 IOCTL_GET(request_type, ANTENNA_DIVERSITY, apple80211_antenna_data); break; case APPLE80211_IOC_DRIVER_VERSION: // 43 IOCTL_GET(request_type, DRIVER_VERSION, apple80211_version_data); break; case APPLE80211_IOC_HARDWARE_VERSION: // 44 IOCTL_GET(request_type, HARDWARE_VERSION, apple80211_version_data); break; case APPLE80211_IOC_RSN_IE: // 46 IOCTL(request_type, RSN_IE, apple80211_rsn_ie_data); break; case APPLE80211_IOC_AP_IE_LIST: // 48 if (request_type != SIOCGA80211) return kIOReturnError; IOCTL_GET(request_type, AP_IE_LIST, apple80211_ap_ie_data); break; case APPLE80211_IOC_ASSOCIATION_STATUS: // 50 IOCTL_GET(request_type, ASSOCIATION_STATUS, apple80211_assoc_status_data); break; case APPLE80211_IOC_COUNTRY_CODE: // 51 IOCTL(request_type, COUNTRY_CODE, apple80211_country_code_data); break; case APPLE80211_IOC_RADIO_INFO: IOCTL_GET(request_type, RADIO_INFO, apple80211_radio_info_data); break; case APPLE80211_IOC_MCS: // 57 IOCTL_GET(request_type, MCS, apple80211_mcs_data); break; case APPLE80211_IOC_VIRTUAL_IF_CREATE: // 94 IOCTL_SET(request_type, VIRTUAL_IF_CREATE, apple80211_virt_if_create_data); break; case APPLE80211_IOC_VIRTUAL_IF_DELETE: IOCTL_SET(request_type, VIRTUAL_IF_DELETE, apple80211_virt_if_delete_data); break; case APPLE80211_IOC_ROAM_THRESH: IOCTL_GET(request_type, ROAM_THRESH, apple80211_roam_threshold_data); break; case APPLE80211_IOC_LINK_CHANGED_EVENT_DATA: IOCTL_GET(request_type, LINK_CHANGED_EVENT_DATA, apple80211_link_changed_event_data); break; case APPLE80211_IOC_POWERSAVE: IOCTL_GET(request_type, POWERSAVE, apple80211_powersave_data); break; case APPLE80211_IOC_CIPHER_KEY: IOCTL_SET(request_type, CIPHER_KEY, apple80211_key); break; case APPLE80211_IOC_SCANCACHE_CLEAR: IOCTL_SET(request_type, SCANCACHE_CLEAR, apple80211req); break; case APPLE80211_IOC_TX_NSS: IOCTL(request_type, TX_NSS, apple80211_tx_nss_data); break; case APPLE80211_IOC_NSS: IOCTL_GET(request_type, NSS, apple80211_nss_data); break; case APPLE80211_IOC_ROAM: IOCTL_SET(request_type, ROAM, apple80211_sta_roam_data); break; case APPLE80211_IOC_ROAM_PROFILE: IOCTL(request_type, ROAM_PROFILE, apple80211_roam_profile_band_data); break; case APPLE80211_IOC_WOW_PARAMETERS: IOCTL(request_type, WOW_PARAMETERS, apple80211_wow_parameter_data); break; case APPLE80211_IOC_IE: IOCTL(request_type, IE, apple80211_ie_data); break; case APPLE80211_IOC_P2P_LISTEN: IOCTL_SET(request_type, P2P_LISTEN, apple80211_p2p_listen_data); break; case APPLE80211_IOC_P2P_SCAN: IOCTL_SET(request_type, P2P_SCAN, apple80211_scan_data); break; case APPLE80211_IOC_P2P_GO_CONF: IOCTL_SET(request_type, P2P_GO_CONF, apple80211_p2p_go_conf_data); break; case APPLE80211_IOC_BTCOEX_PROFILES: IOCTL(request_type, BTCOEX_PROFILES, apple80211_btc_profiles_data); break; case APPLE80211_IOC_BTCOEX_CONFIG: IOCTL(request_type, BTCOEX_CONFIG, apple80211_btc_config_data); break; case APPLE80211_IOC_BTCOEX_OPTIONS: IOCTL(request_type, BTCOEX_OPTIONS, apple80211_btc_options_data); break; case APPLE80211_IOC_BTCOEX_MODE: IOCTL(request_type, BTCOEX_MODE, apple80211_btc_mode_data); break; default: unhandled: if (!ml_at_interrupt_context()) { XYLog("%s Unhandled IOCTL %s (%d) %s\n", __FUNCTION__, IOCTL_NAMES[request_number >= ARRAY_SIZE(IOCTL_NAMES) ? 0: request_number], request_number, request_type == SIOCGA80211 ? "get" : (request_type == SIOCSA80211 ? "set" : "other")); } break; } return ret; } IOReturn AirportItlwm:: getSSID(OSObject *object, struct apple80211_ssid_data *sd) { struct ieee80211com * ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(sd, 0, sizeof(*sd)); sd->version = APPLE80211_VERSION; memcpy(sd->ssid_bytes, ic->ic_des_essid, strlen((const char*)ic->ic_des_essid)); sd->ssid_len = (uint32_t)strlen((const char*)ic->ic_des_essid); return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: setSSID(OSObject *object, struct apple80211_ssid_data *sd) { return kIOReturnSuccess; } IOReturn AirportItlwm:: getAUTH_TYPE(OSObject *object, struct apple80211_authtype_data *ad) { ad->version = APPLE80211_VERSION; ad->authtype_lower = current_authtype_lower; ad->authtype_upper = current_authtype_upper; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAUTH_TYPE(OSObject *object, struct apple80211_authtype_data *ad) { current_authtype_lower = ad->authtype_lower; current_authtype_upper = ad->authtype_upper; return kIOReturnSuccess; } IOReturn AirportItlwm:: setCIPHER_KEY(OSObject *object, struct apple80211_key *key) { XYLog("%s\n", __FUNCTION__); const char* keydump = hexdump(key->key, key->key_len); const char* rscdump = hexdump(key->key_rsc, key->key_rsc_len); const char* eadump = hexdump(key->key_ea.octet, APPLE80211_ADDR_LEN); static_assert(__offsetof(struct apple80211_key, key_ea) == 92, "struct corrupted"); static_assert(__offsetof(struct apple80211_key, key_rsc_len) == 80, "struct corrupted"); static_assert(__offsetof(struct apple80211_key, wowl_kck_len) == 100, "struct corrupted"); static_assert(__offsetof(struct apple80211_key, wowl_kek_len) == 120, "struct corrupted"); static_assert(__offsetof(struct apple80211_key, wowl_kck_key) == 104, "struct corrupted"); if (keydump && rscdump && eadump) XYLog("Set key request: len=%d cipher_type=%d flags=%d index=%d key=%s rsc_len=%d rsc=%s ea=%s\n", key->key_len, key->key_cipher_type, key->key_flags, key->key_index, keydump, key->key_rsc_len, rscdump, eadump); else XYLog("Set key request, but failed to allocate memory for hexdump\n"); if (keydump) IOFree((void*)keydump, 3 * key->key_len + 1); if (rscdump) IOFree((void*)rscdump, 3 * key->key_rsc_len + 1); if (eadump) IOFree((void*)eadump, 3 * APPLE80211_ADDR_LEN + 1); switch (key->key_cipher_type) { case APPLE80211_CIPHER_NONE: // clear existing key // XYLog("Setting NONE key is not supported\n"); break; case APPLE80211_CIPHER_WEP_40: case APPLE80211_CIPHER_WEP_104: XYLog("Setting WEP key %d is not supported\n", key->key_index); break; case APPLE80211_CIPHER_TKIP: case APPLE80211_CIPHER_AES_OCB: case APPLE80211_CIPHER_AES_CCM: switch (key->key_flags) { case 4: // PTK setPTK(key->key, key->key_len); getNetworkInterface()->postMessage(APPLE80211_M_RSN_HANDSHAKE_DONE); break; case 0: // GTK setGTK(key->key, key->key_len, key->key_index, key->key_rsc); getNetworkInterface()->postMessage(APPLE80211_M_RSN_HANDSHAKE_DONE); break; } break; case APPLE80211_CIPHER_PMK: XYLog("Setting WPA PMK is not supported\n"); break; case APPLE80211_CIPHER_PMKSA: XYLog("Setting WPA PMKSA is not supported\n"); break; } //fInterface->postMessage(APPLE80211_M_CIPHER_KEY_CHANGED); return kIOReturnSuccess; } // From Ventura, airport/wifiagent seems that they don't like to accept extra channel flags in the scan result list, // if not, the exact behavior is that the wifi list on the control center/menu bar will not refresh after system boot. #if __IO80211_TARGET >= __MAC_13_0 static int ieeeChanFlag2appleScanFlagVentura(int flags) { int ret = 0; if (flags & IEEE80211_CHAN_2GHZ) ret |= APPLE80211_C_FLAG_2GHZ; if (flags & IEEE80211_CHAN_5GHZ) ret |= APPLE80211_C_FLAG_5GHZ; ret |= (APPLE80211_C_FLAG_ACTIVE | APPLE80211_C_FLAG_20MHZ); return ret; } #endif static int ieeeChanFlag2apple(int flags, int bw) { int ret = 0; if (flags & IEEE80211_CHAN_2GHZ) ret |= APPLE80211_C_FLAG_2GHZ; if (flags & IEEE80211_CHAN_5GHZ) ret |= APPLE80211_C_FLAG_5GHZ; if (!(flags & IEEE80211_CHAN_PASSIVE)) ret |= APPLE80211_C_FLAG_ACTIVE; if (flags & IEEE80211_CHAN_DFS) ret |= APPLE80211_C_FLAG_DFS; if (bw == -1) { if (flags & IEEE80211_CHAN_VHT) { if ((flags & IEEE80211_CHAN_VHT160) || (flags & IEEE80211_CHAN_VHT80_80)) ret |= APPLE80211_C_FLAG_160MHZ; if (flags & IEEE80211_CHAN_VHT80) ret |= APPLE80211_C_FLAG_80MHZ; } else if ((flags & IEEE80211_CHAN_HT40) && (flags & IEEE80211_CHAN_HT)) { ret |= APPLE80211_C_FLAG_40MHZ; if (flags & IEEE80211_CHAN_HT40U) ret |= APPLE80211_C_FLAG_EXT_ABV; } else if (flags & IEEE80211_CHAN_HT20) ret |= APPLE80211_C_FLAG_20MHZ; else if ((flags & IEEE80211_CHAN_CCK) || (flags & IEEE80211_CHAN_OFDM)) ret |= APPLE80211_C_FLAG_10MHZ; } else { switch (bw) { case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: ret |= APPLE80211_C_FLAG_160MHZ; break; case IEEE80211_CHAN_WIDTH_80: ret |= APPLE80211_C_FLAG_80MHZ; break; case IEEE80211_CHAN_WIDTH_40: ret |= APPLE80211_C_FLAG_40MHZ; if (flags & IEEE80211_CHAN_HT40U) ret |= APPLE80211_C_FLAG_EXT_ABV; break; case IEEE80211_CHAN_WIDTH_20: ret |= APPLE80211_C_FLAG_20MHZ; break; default: if (flags & IEEE80211_CHAN_HT20) ret |= APPLE80211_C_FLAG_20MHZ; else if ((flags & IEEE80211_CHAN_CCK) || (flags & IEEE80211_CHAN_OFDM)) ret |= APPLE80211_C_FLAG_10MHZ; break; } } return ret; } IOReturn AirportItlwm:: getCHANNEL(OSObject *object, struct apple80211_channel_data *cd) { struct ieee80211com * ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(cd, 0, sizeof(apple80211_channel_data)); cd->version = APPLE80211_VERSION; cd->channel.version = APPLE80211_VERSION; cd->channel.channel = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); cd->channel.flags = ieeeChanFlag2apple(ic->ic_bss->ni_chan->ic_flags, ic->ic_bss->ni_chw); return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: setCHANNEL(OSObject *object, struct apple80211_channel_data *data) { XYLog("%s channel=%d\n", __FUNCTION__, data->channel.channel); return kIOReturnError; } IOReturn AirportItlwm:: getPROTMODE(OSObject *object, struct apple80211_protmode_data *pd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(pd, 0, sizeof(*pd)); pd->version = APPLE80211_VERSION; pd->threshold = 0; pd->protmode = 0; return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: setPROTMODE(OSObject *object, struct apple80211_protmode_data *pd) { return kIOReturnError; } IOReturn AirportItlwm:: getTXPOWER(OSObject *object, struct apple80211_txpower_data *txd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(txd, 0, sizeof(*txd)); txd->version = APPLE80211_VERSION; txd->txpower = ic->ic_txpower; txd->txpower_unit = APPLE80211_UNIT_PERCENT; return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: getTX_NSS(OSObject *object, struct apple80211_tx_nss_data *data) { memset(data, 0, sizeof(*data)); data->version = APPLE80211_VERSION; data->nss = fHalService->getDriverInfo()->getTxNSS(); return kIOReturnSuccess; } IOReturn AirportItlwm:: getNSS(OSObject *object, struct apple80211_nss_data *data) { memset(data, 0, sizeof(*data)); data->version = APPLE80211_VERSION; data->nss = fHalService->getDriverInfo()->getTxNSS(); return kIOReturnSuccess; } IOReturn AirportItlwm:: setTX_NSS(OSObject *object, struct apple80211_tx_nss_data *data) { return kIOReturnError; } IOReturn AirportItlwm:: setROAM(OSObject *object, struct apple80211_sta_roam_data *data) { XYLog("%s rcc_channels=%d unk=%d target_channel=%d target_bssid=%s\n", __FUNCTION__, data->rcc_channels, data->unk1, data->taget_channel, ether_sprintf(data->target_bssid)); return kIOReturnError; } IOReturn AirportItlwm:: getRATE(OSObject *object, struct apple80211_rate_data *rd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_bss == NULL) return 6; int nss; int sgi; int index = 0; if (ic->ic_state == IEEE80211_S_RUN) { memset(rd, 0, sizeof(*rd)); rd->version = APPLE80211_VERSION; rd->num_radios = 1; sgi = ieee80211_node_supports_sgi(ic->ic_bss); if (ic->ic_curmode == IEEE80211_MODE_11AC) { if (sgi) index += 1; nss = fHalService->getDriverInfo()->getTxNSS(); switch (ic->ic_bss->ni_chw) { case IEEE80211_CHAN_WIDTH_40: index += 4; break; case IEEE80211_CHAN_WIDTH_80: index += 8; break; case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: index += 12; break; default: break; } index += 2 * (nss - 1); const struct ieee80211_vht_rateset *rs = &ieee80211_std_ratesets_11ac[index]; rd->rate[0] = rs->rates[ic->ic_bss->ni_txmcs % rs->nrates] / 2; } else if (ic->ic_curmode == IEEE80211_MODE_11N) { int is_40mhz = ic->ic_bss->ni_chw == IEEE80211_CHAN_WIDTH_40; if (sgi) index += 1; if (is_40mhz) index += (IEEE80211_HT_RATESET_MIMO4_SGI + 1); index += (ic->ic_bss->ni_txmcs / 16); nss = ic->ic_bss->ni_txmcs / 8 + 1; index += 2 * (nss - 1); rd->rate[0] = ieee80211_std_ratesets_11n[index].rates[ic->ic_bss->ni_txmcs % 8] / 2; } else rd->rate[0] = ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate]; return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: getROAM_PROFILE(OSObject *object, struct apple80211_roam_profile_band_data *data) { if (roamProfile == NULL) { XYLog("%s no roam profile, return error\n", __FUNCTION__); return kIOReturnError; } memcpy(data, roamProfile, sizeof(struct apple80211_roam_profile_band_data)); return kIOReturnSuccess; } IOReturn AirportItlwm:: setROAM_PROFILE(OSObject *object, struct apple80211_roam_profile_band_data *data) { XYLog("%s cnt=%d flags=%d\n", __FUNCTION__, data->profile_cnt, data->flags); #if 0 for (int i = 0; i < data->profile_cnt; i++) { struct apple80211_roam_profile *bd = &data->profiles[i]; XYLog("%s %d ROAM_PROF_BACKOFF_MULTIPLIER: %d, ROAM_PROF_FULLSCAN_PERIOD: %d, ROAM_PROF_INIT_SCAN_PERIOD: %d, ROAM_PROF_MAX_SCAN_PERIOD: %d, ROAM_PROF_NFSCAN: %d, ROAM_PROF_ROAM_DELTA: %d, ROAM_PROF_ROAM_FLAGS:%d, ROAM_PROF_ROAM_TRIGGER: %d, ROAM_PROF_RSSI_BOOST_DELTA: %d, ROAM_PROF_RSSI_BOOST_THRESH: %d, ROAM_PROF_RSSI_LOWER: %d\n", __FUNCTION__, i, bd->backoff_multiplier, bd->full_scan_period, bd->init_scan_period, bd->max_scan_period, bd->nfscan, bd->delta, bd->flags, bd->trigger, bd->rssi_boost_delta, bd->rssi_boost_thresh, bd->rssi_lower); } #endif if (roamProfile != NULL) IOFree(roamProfile, sizeof(struct apple80211_roam_profile_band_data)); roamProfile = (uint8_t *)IOMalloc(sizeof(struct apple80211_roam_profile_band_data)); memcpy(roamProfile, data, sizeof(struct apple80211_roam_profile_band_data)); return kIOReturnSuccess; } IOReturn AirportItlwm:: getBTCOEX_CONFIG(OSObject *object, struct apple80211_btc_config_data *data) { if (!data) return kIOReturnError; memcpy(data, &btcConfig, sizeof(struct apple80211_btc_config_data)); return kIOReturnSuccess; } IOReturn AirportItlwm:: setBTCOEX_CONFIG(OSObject *object, struct apple80211_btc_config_data *data) { if (!data) return kIOReturnError; XYLog("%s Setting BTCoex Config: enable_2G:%d, profile_2g:%d, enable_5G:%d, profile_5G:%d\n", __FUNCTION__, data->enable_2G, data->profile_2g, data->enable_5G, data->profile_5G); memcpy(&btcConfig, data, sizeof(struct apple80211_btc_config_data)); return kIOReturnSuccess; } IOReturn AirportItlwm:: getBTCOEX_MODE(OSObject *object, struct apple80211_btc_mode_data *data) { if (!data) return kIOReturnError; data->version = APPLE80211_VERSION; data->btc_mode = btcMode; return kIOReturnSuccess; } IOReturn AirportItlwm:: setBTCOEX_MODE(OSObject *object, struct apple80211_btc_mode_data *data) { if (!data) return kIOReturnError; XYLog("%s mode: %d\n", __FUNCTION__, data->btc_mode); btcMode = data->btc_mode; return kIOReturnSuccess; } IOReturn AirportItlwm:: getBTCOEX_OPTIONS(OSObject *object, struct apple80211_btc_options_data *data) { if (!data) return kIOReturnError; data->version = APPLE80211_VERSION; data->btc_options = btcOptions; return kIOReturnSuccess; } IOReturn AirportItlwm:: setBTCOEX_OPTIONS(OSObject *object, struct apple80211_btc_options_data *data) { if (!data) return kIOReturnError; XYLog("%s options: %d\n", __FUNCTION__, data->btc_options); btcOptions = data->btc_options; return kIOReturnSuccess; } IOReturn AirportItlwm:: getBTCOEX_PROFILES(OSObject *object, struct apple80211_btc_profiles_data *data) { if (!data || !btcProfile) return kIOReturnError; memcpy(data, btcProfile, sizeof(struct apple80211_btc_profiles_data)); return kIOReturnSuccess; } IOReturn AirportItlwm:: setBTCOEX_PROFILES(OSObject *object, struct apple80211_btc_profiles_data *data) { if (!data) return kIOReturnError; XYLog("%s profiles: %d\n", __FUNCTION__, data->profile_cnt); if (btcProfile) IOFree(btcProfile, sizeof(struct apple80211_btc_profiles_data)); btcProfile = (struct apple80211_btc_profiles_data *)IOMalloc(sizeof(struct apple80211_btc_profiles_data)); memcpy(btcProfile, data, sizeof(struct apple80211_btc_profiles_data)); return kIOReturnSuccess; } IOReturn AirportItlwm:: getWOW_PARAMETERS(OSObject *object, struct apple80211_wow_parameter_data *data) { return kIOReturnError; } IOReturn AirportItlwm:: setWOW_PARAMETERS(OSObject *object, struct apple80211_wow_parameter_data *data) { XYLog("%s pattern_count=%d\n", __FUNCTION__, data->pattern_count); return kIOReturnError; } IOReturn AirportItlwm:: getBSSID(OSObject *object, struct apple80211_bssid_data *bd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(bd, 0, sizeof(*bd)); bd->version = APPLE80211_VERSION; memcpy(bd->bssid.octet, ic->ic_bss->ni_bssid, APPLE80211_ADDR_LEN); return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: setBSSID(OSObject *object, struct apple80211_bssid_data *data) { XYLog("%s bssid=%s\n", __FUNCTION__, ether_sprintf(data->bssid.octet)); return kIOReturnSuccess; } IOReturn AirportItlwm:: getCARD_CAPABILITIES(OSObject *object, struct apple80211_capability_data *cd) { uint32_t caps = fHalService->get80211Controller()->ic_caps; memset(cd, 0, sizeof(struct apple80211_capability_data)); if (caps & IEEE80211_C_WEP) cd->capabilities[0] |= 1 << APPLE80211_CAP_WEP; if (caps & IEEE80211_C_RSN) cd->capabilities[0] |= 1 << APPLE80211_CAP_TKIP | 1 << APPLE80211_CAP_AES_CCM; // Disable not implemented capabilities // if (caps & IEEE80211_C_PMGT) // cd->capabilities[0] |= 1 << APPLE80211_CAP_PMGT; // if (caps & IEEE80211_C_IBSS) // cd->capabilities[0] |= 1 << APPLE80211_CAP_IBSS; // if (caps & IEEE80211_C_HOSTAP) // cd->capabilities[0] |= 1 << APPLE80211_CAP_HOSTAP; // AES not enabled, like on Apple cards if (caps & IEEE80211_C_SHSLOT) cd->capabilities[1] |= 1 << (APPLE80211_CAP_SHSLOT - 8); if (caps & IEEE80211_C_SHPREAMBLE) cd->capabilities[1] |= 1 << (APPLE80211_CAP_SHPREAMBLE - 8); if (caps & IEEE80211_C_RSN) cd->capabilities[1] |= 1 << (APPLE80211_CAP_WPA1 - 8) | 1 << (APPLE80211_CAP_WPA2 - 8) | 1 << (APPLE80211_CAP_TKIPMIC - 8); // Disable not implemented capabilities // if (caps & IEEE80211_C_TXPMGT) // cd->capabilities[1] |= 1 << (APPLE80211_CAP_TXPMGT - 8); // if (caps & IEEE80211_C_MONITOR) // cd->capabilities[1] |= 1 << (APPLE80211_CAP_MONITOR - 8); // WPA not enabled, like on Apple cards cd->version = APPLE80211_VERSION; cd->capabilities[2] = 0xFF; // BURST, WME, SHORT_GI_40MHZ, SHORT_GI_20MHZ, WOW, TSN, ?, ? cd->capabilities[3] = 0x2B; cd->capabilities[4] = 0xAD; cd->capabilities[5] = 0x80;//isCntryDefaultSupported cd->capabilities[5] |= 0x0C; cd->capabilities[6] = ( // 1 | //MFP capable 0x8 | 0x4 | 0x80 ); cd->capabilities[7] = 0x84; // This byte contains Apple Watch unlock //cd->capabilities[8] = 0x40; //cd->capabilities[8] |= 8;//dfs white list //cd->capabilities[9] = 0x28; return kIOReturnSuccess; } IOReturn AirportItlwm:: getSTATE(OSObject *object, struct apple80211_state_data *sd) { memset(sd, 0, sizeof(*sd)); sd->version = APPLE80211_VERSION; sd->state = fHalService->get80211Controller()->ic_state; return kIOReturnSuccess; } IOReturn AirportItlwm:: getMCS_INDEX_SET(OSObject *object, struct apple80211_mcs_index_set_data *ad) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(ad, 0, sizeof(*ad)); ad->version = APPLE80211_VERSION; size_t size = min(ARRAY_SIZE(ic->ic_bss->ni_rxmcs), ARRAY_SIZE(ad->mcs_set_map)); for (int i = 0; i < size; i++) ad->mcs_set_map[i] = ic->ic_bss->ni_rxmcs[i]; return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: getVHT_MCS_INDEX_SET(OSObject *object, struct apple80211_vht_mcs_index_set_data *data) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_bss == NULL || ic->ic_curmode < IEEE80211_MODE_11AC) { return kIOReturnError; } memset(data, 0, sizeof(struct apple80211_vht_mcs_index_set_data)); data->version = APPLE80211_VERSION; data->mcs_map = ic->ic_bss->ni_vht_mcsinfo.tx_mcs_map; return kIOReturnSuccess; } IOReturn AirportItlwm:: getMCS_VHT(OSObject *object, struct apple80211_mcs_vht_data *data) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_bss == NULL || ic->ic_curmode < IEEE80211_MODE_11AC) { return kIOReturnError; } memset(data, 0, sizeof(struct apple80211_mcs_vht_data)); data->version = APPLE80211_VERSION; data->guard_interval = (ieee80211_node_supports_vht_sgi80(ic->ic_bss) || ieee80211_node_supports_vht_sgi160(ic->ic_bss)) ? APPLE80211_GI_SHORT : APPLE80211_GI_LONG; data->index = ic->ic_bss->ni_txmcs; data->nss = fHalService->getDriverInfo()->getTxNSS(); switch (ic->ic_bss->ni_chw) { case IEEE80211_CHAN_WIDTH_40: data->bw = 40; break; case IEEE80211_CHAN_WIDTH_80: data->bw = 80; break; case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: data->bw = 160; break; default: data->bw = 20; break; } return kIOReturnSuccess; } IOReturn AirportItlwm:: setMCS_VHT(OSObject *object, struct apple80211_mcs_vht_data *data) { XYLog("%s gi=%d index=%d nss=%d bw=%d\n", __FUNCTION__, data->guard_interval, data->index, data->nss, data->bw); return kIOReturnError; } IOReturn AirportItlwm:: getRATE_SET(OSObject *object, struct apple80211_rate_set_data *ad) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(ad, 0, sizeof(*ad)); ad->version = APPLE80211_VERSION; ad->num_rates = ic->ic_bss->ni_rates.rs_nrates; size_t size = min(ic->ic_bss->ni_rates.rs_nrates, ARRAY_SIZE(ad->rates)); for (int i=0; i < size; i++) { struct apple80211_rate apple_rate = ad->rates[i]; apple_rate.version = APPLE80211_VERSION; apple_rate.rate = ic->ic_bss->ni_rates.rs_rates[i]; apple_rate.flags = 0; } return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: getPHY_MODE(OSObject *object, struct apple80211_phymode_data *pd) { struct ieee80211com *ic = fHalService->get80211Controller(); pd->version = APPLE80211_VERSION; pd->phy_mode = APPLE80211_MODE_11A | APPLE80211_MODE_11B | APPLE80211_MODE_11G | APPLE80211_MODE_11N; if (ic->ic_flags & IEEE80211_F_VHTON) pd->phy_mode |= APPLE80211_MODE_11AC; if (ic->ic_flags & IEEE80211_F_HEON) pd->phy_mode |= APPLE80211_MODE_11AX; switch (fHalService->get80211Controller()->ic_curmode) { case IEEE80211_MODE_AUTO: pd->active_phy_mode = APPLE80211_MODE_AUTO; break; case IEEE80211_MODE_11A: pd->active_phy_mode = APPLE80211_MODE_11A; break; case IEEE80211_MODE_11B: pd->active_phy_mode = APPLE80211_MODE_11B; break; case IEEE80211_MODE_11G: pd->active_phy_mode = APPLE80211_MODE_11G; break; case IEEE80211_MODE_11N: pd->active_phy_mode = APPLE80211_MODE_11N; break; case IEEE80211_MODE_11AC: pd->active_phy_mode = APPLE80211_MODE_11AC; break; case IEEE80211_MODE_11AX: pd->active_phy_mode = APPLE80211_MODE_11AX; break; default: pd->active_phy_mode = APPLE80211_MODE_AUTO; break; } return kIOReturnSuccess; } IOReturn AirportItlwm:: getOP_MODE(OSObject *object, struct apple80211_opmode_data *od) { od->version = APPLE80211_VERSION; od->op_mode = APPLE80211_M_STA; return kIOReturnSuccess; } IOReturn AirportItlwm:: getRSSI(OSObject *object, struct apple80211_rssi_data *rd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(rd, 0, sizeof(*rd)); rd->num_radios = 1; rd->rssi_unit = APPLE80211_UNIT_DBM; rd->rssi[0] = rd->aggregate_rssi = rd->rssi_ext[0] = rd->aggregate_rssi_ext = -(0 - IWM_MIN_DBM - ic->ic_bss->ni_rssi); return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: getRSN_IE(OSObject *object, struct apple80211_rsn_ie_data *data) { #ifdef USE_APPLE_SUPPLICANT struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_bss == NULL || ic->ic_bss->ni_rsnie == NULL) { return kIOReturnError; } data->version = APPLE80211_VERSION; if (ic->ic_rsn_ie_override[1] > 0) { data->len = 2 + ic->ic_rsn_ie_override[1]; memcpy(data->ie, ic->ic_rsn_ie_override, data->len); } else { data->len = 2 + ic->ic_bss->ni_rsnie[1]; memcpy(data->ie, ic->ic_bss->ni_rsnie, data->len); } return kIOReturnSuccess; #else return kIOReturnUnsupported; #endif } IOReturn AirportItlwm:: setRSN_IE(OSObject *object, struct apple80211_rsn_ie_data *data) { #ifdef USE_APPLE_SUPPLICANT struct ieee80211com *ic = fHalService->get80211Controller(); if (!data) return kIOReturnError; static_assert(sizeof(ic->ic_rsn_ie_override) == APPLE80211_MAX_RSN_IE_LEN, "Max RSN IE length mismatch"); memcpy(ic->ic_rsn_ie_override, data->ie, APPLE80211_MAX_RSN_IE_LEN); if (ic->ic_state == IEEE80211_S_RUN && ic->ic_bss != nullptr) ieee80211_save_ie(data->ie, &ic->ic_bss->ni_rsnie); return kIOReturnSuccess; #else return kIOReturnUnsupported; #endif } IOReturn AirportItlwm:: getAP_IE_LIST(OSObject *object, struct apple80211_ap_ie_data *data) { #ifdef USE_APPLE_SUPPLICANT struct ieee80211com *ic = fHalService->get80211Controller(); if (!data) return kIOReturnError; if (ic->ic_bss == NULL || ic->ic_bss->ni_rsnie_tlv == NULL || ic->ic_bss->ni_rsnie_tlv_len == 0 || ic->ic_bss->ni_rsnie_tlv_len > data->len || ic->ic_bss->ni_rsnie_tlv_len > 1024) return kIOReturnError; data->version = APPLE80211_VERSION; data->len = ic->ic_bss->ni_rsnie_tlv_len; memcpy(data->ie_data, ic->ic_bss->ni_rsnie_tlv, data->len); return kIOReturnSuccess; #else return kIOReturnUnsupported; #endif } IOReturn AirportItlwm:: getNOISE(OSObject *object, struct apple80211_noise_data *nd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state == IEEE80211_S_RUN) { memset(nd, 0, sizeof(*nd)); nd->version = APPLE80211_VERSION; nd->num_radios = 1; nd->noise[0] = nd->aggregate_noise = -fHalService->getDriverInfo()->getBSSNoise(); nd->noise_unit = APPLE80211_UNIT_DBM; return kIOReturnSuccess; } return 6; } IOReturn AirportItlwm:: getINT_MIT(OSObject *object, struct apple80211_intmit_data *imd) { if (!imd) return kIOReturnError; imd->version = APPLE80211_VERSION; imd->int_mit = APPLE80211_INT_MIT_AUTO; return kIOReturnSuccess; } IOReturn AirportItlwm:: getPOWER(OSObject *object, struct apple80211_power_data *pd) { if (!pd) return kIOReturnError; pd->version = APPLE80211_VERSION; pd->num_radios = 4; pd->power_state[0] = power_state; pd->power_state[1] = power_state; pd->power_state[2] = power_state; pd->power_state[3] = power_state; return kIOReturnSuccess; } IOReturn AirportItlwm:: getPOWERSAVE(OSObject *object, struct apple80211_powersave_data *pd) { pd->version = APPLE80211_VERSION; pd->powersave_level = APPLE80211_POWERSAVE_MODE_DISABLED; return kIOReturnSuccess; } IOReturn AirportItlwm:: setPOWER(OSObject *object, struct apple80211_power_data *pd) { if (!pd) return kIOReturnError; IOLog("itlwm: setPOWER: num_radios[%d] power_state(0:%u 1:%u 2:%u 3:%u)\n", pd->num_radios, pd->power_state[0], pd->power_state[1], pd->power_state[2], pd->power_state[3]); if (pd->num_radios > 0) { bool isRunning = (fHalService->get80211Controller()->ic_ac.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) != 0; if (pd->power_state[0] == 0) { changePowerStateToPriv(1); if (isRunning) { net80211_ifstats(fHalService->get80211Controller()); disableAdapter(fNetIf); } } else { changePowerStateToPriv(2); if (!isRunning) enableAdapter(fNetIf); } power_state = (pd->power_state[0]); } return kIOReturnSuccess; } IOReturn AirportItlwm:: setASSOCIATE(OSObject *object, struct apple80211_assoc_data *ad) { XYLog("%s [%s] mode=%d ad_auth_lower=%d ad_auth_upper=%d rsn_ie_len=%d%s%s%s%s%s%s%s\n", __FUNCTION__, ad->ad_ssid, ad->ad_mode, ad->ad_auth_lower, ad->ad_auth_upper, ad->ad_rsn_ie_len, (ad->ad_flags & 2) ? ", Instant Hotspot" : "", (ad->ad_flags & 4) ? ", Auto Instant Hotspot" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 1) ? ", don't disassociate" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 2) ? ", don't blacklist" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 4) ? ", closed Network" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 8) ? ", 802.1X" : "", (ad->ad_rsn_ie[APPLE80211_MAX_RSN_IE_LEN] & 0x20) ? ", force BSSID" : ""); struct apple80211_rsn_ie_data rsn_ie_data; struct apple80211_authtype_data auth_type_data; struct ieee80211com *ic = fHalService->get80211Controller(); if (!ad) return kIOReturnError; if (ic->ic_state < IEEE80211_S_SCAN) return kIOReturnSuccess; if (ic->ic_state == IEEE80211_S_ASSOC || ic->ic_state == IEEE80211_S_AUTH) return kIOReturnSuccess; if (ad->ad_mode != APPLE80211_AP_MODE_IBSS) { disassocIsVoluntary = false; auth_type_data.version = APPLE80211_VERSION; auth_type_data.authtype_upper = ad->ad_auth_upper; auth_type_data.authtype_lower = ad->ad_auth_lower; setAUTH_TYPE(object, &auth_type_data); rsn_ie_data.version = APPLE80211_VERSION; rsn_ie_data.len = ad->ad_rsn_ie[1] + 2; memcpy(rsn_ie_data.ie, ad->ad_rsn_ie, rsn_ie_data.len); setRSN_IE(object, &rsn_ie_data); associateSSID(ad->ad_ssid, ad->ad_ssid_len, ad->ad_bssid, ad->ad_auth_lower, ad->ad_auth_upper, ad->ad_key.key, ad->ad_key.key_len, ad->ad_key.key_index); } return kIOReturnSuccess; } IOReturn AirportItlwm:: getASSOCIATE_RESULT(OSObject *object, struct apple80211_assoc_result_data *ad) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = fHalService->get80211Controller(); if (ad && ic->ic_state == IEEE80211_S_RUN) { memset(ad, 0, sizeof(struct apple80211_assoc_result_data)); ad->version = APPLE80211_VERSION; ad->result = APPLE80211_RESULT_SUCCESS; return kIOReturnSuccess; } return kIOReturnError; } IOReturn AirportItlwm::setDISASSOCIATE(OSObject *object) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state < IEEE80211_S_SCAN) return kIOReturnSuccess; if (ic->ic_state > IEEE80211_S_AUTH && ic->ic_bss != NULL) IEEE80211_SEND_MGMT(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); if (ic->ic_state == IEEE80211_S_ASSOC || ic->ic_state == IEEE80211_S_AUTH) return kIOReturnSuccess; disassocIsVoluntary = true; ieee80211_del_ess(ic, nullptr, 0, 1); ieee80211_deselect_ess(ic); #ifdef USE_APPLE_SUPPLICANT ic->ic_rsn_ie_override[1] = 0; #endif ic->ic_assoc_status = APPLE80211_STATUS_UNAVAILABLE; ic->ic_deauth_reason = APPLE80211_REASON_ASSOC_LEAVING; ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return kIOReturnSuccess; } IOReturn AirportItlwm:: getSUPPORTED_CHANNELS(OSObject *object, struct apple80211_sup_channel_data *ad) { if (!ad) return kIOReturnError; ad->version = APPLE80211_VERSION; ad->num_channels = 0; struct ieee80211com *ic = fHalService->get80211Controller(); for (int i = 0; i < IEEE80211_CHAN_MAX; i++) { if (ic->ic_channels[i].ic_freq != 0) { ad->supported_channels[ad->num_channels].channel = ieee80211_chan2ieee(ic, &ic->ic_channels[i]); #if __IO80211_TARGET < __MAC_13_0 ad->supported_channels[ad->num_channels].flags = ieeeChanFlag2apple(ic->ic_channels[i].ic_flags, -1); #else ad->supported_channels[ad->num_channels].flags = ieeeChanFlag2appleScanFlagVentura(ic->ic_channels[i].ic_flags); #endif ad->num_channels++; } } return kIOReturnSuccess; } IOReturn AirportItlwm:: getLOCALE(OSObject *object, struct apple80211_locale_data *ld) { if (!ld) return kIOReturnError; ld->version = APPLE80211_VERSION; ld->locale = APPLE80211_LOCALE_FCC; return kIOReturnSuccess; } IOReturn AirportItlwm:: getDEAUTH(OSObject *object, struct apple80211_deauth_data *da) { if (!da) return kIOReturnError; da->version = APPLE80211_VERSION; struct ieee80211com *ic = fHalService->get80211Controller(); da->deauth_reason = ic->ic_deauth_reason; // XYLog("%s, %d\n", __FUNCTION__, da->deauth_reason); return kIOReturnSuccess; } IOReturn AirportItlwm:: getASSOCIATION_STATUS(OSObject *object, struct apple80211_assoc_status_data *hv) { struct ieee80211com *ic = fHalService->get80211Controller(); if (!hv) return kIOReturnError; memset(hv, 0, sizeof(*hv)); hv->version = APPLE80211_VERSION; if (ic->ic_state == IEEE80211_S_RUN) hv->status = APPLE80211_STATUS_SUCCESS; else hv->status = APPLE80211_STATUS_UNAVAILABLE; // XYLog("%s, %d\n", __FUNCTION__, hv->status); return kIOReturnSuccess; } IOReturn AirportItlwm:: setSCANCACHE_CLEAR(OSObject *object, struct apple80211req *req) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = fHalService->get80211Controller(); //if doing background or active scan, don't free nodes. if ((ic->ic_flags & IEEE80211_F_BGSCAN) || (ic->ic_flags & IEEE80211_F_ASCAN)) return kIOReturnSuccess; ieee80211_free_allnodes(ic, 0); return kIOReturnSuccess; } IOReturn AirportItlwm:: setDEAUTH(OSObject *object, struct apple80211_deauth_data *da) { XYLog("%s\n", __FUNCTION__); return kIOReturnSuccess; } void AirportItlwm:: eventHandler(struct ieee80211com *ic, int msgCode, void *data) { IO80211Interface *interface = OSDynamicCast(IO80211Interface, ic->ic_ac.ac_if.iface); if (!interface) return; switch (msgCode) { case IEEE80211_EVT_COUNTRY_CODE_UPDATE: interface->postMessage(APPLE80211_M_COUNTRY_CODE_CHANGED); break; case IEEE80211_EVT_STA_ASSOC_DONE: interface->postMessage(APPLE80211_M_ASSOC_DONE); break; case IEEE80211_EVT_STA_DEAUTH: interface->postMessage(APPLE80211_M_DEAUTH_RECEIVED); break; #if 0 case IEEE80211_EVT_SCAN_DONE: interface->postMessage(APPLE80211_M_SCAN_DONE); break; #endif default: break; } } IOReturn AirportItlwm:: getTX_ANTENNA(OSObject *object, apple80211_antenna_data *ad) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state != IEEE80211_S_RUN || ic->ic_bss == NULL || !ad) return kIOReturnError; ad->version = APPLE80211_VERSION; ad->num_radios = 1; ad->antenna_index[0] = 1; return kIOReturnSuccess; } IOReturn AirportItlwm:: getANTENNA_DIVERSITY(OSObject *object, apple80211_antenna_data *ad) { if (!ad) return kIOReturnError; ad->version = APPLE80211_VERSION; ad->num_radios = 1; ad->antenna_index[0] = 1; return kIOReturnSuccess; } IOReturn AirportItlwm:: getDRIVER_VERSION(OSObject *object, struct apple80211_version_data *hv) { if (!hv) return kIOReturnError; hv->version = APPLE80211_VERSION; snprintf(hv->string, sizeof(hv->string), "itlwm: %s%s fw: %s", ITLWM_VERSION, GIT_COMMIT, fHalService->getDriverInfo()->getFirmwareVersion()); hv->string_len = strlen(hv->string); return kIOReturnSuccess; } IOReturn AirportItlwm:: getHARDWARE_VERSION(OSObject *object, struct apple80211_version_data *hv) { if (!hv) return kIOReturnError; hv->version = APPLE80211_VERSION; strncpy(hv->string, fHalService->getDriverInfo()->getFirmwareVersion(), sizeof(hv->string)); hv->string_len = strlen(fHalService->getDriverInfo()->getFirmwareVersion()); return kIOReturnSuccess; } IOReturn AirportItlwm:: getCOUNTRY_CODE(OSObject *object, struct apple80211_country_code_data *cd) { char user_override_cc[3]; const char *cc_fw = fHalService->getDriverInfo()->getFirmwareCountryCode(); if (!cd) return kIOReturnError; cd->version = APPLE80211_VERSION; memset(user_override_cc, 0, sizeof(user_override_cc)); PE_parse_boot_argn("itlwm_cc", user_override_cc, 3); /* user_override_cc > firmware_cc > geo_location_cc */ strncpy((char*)cd->cc, user_override_cc[0] ? user_override_cc : ((cc_fw[0] == 'Z' && cc_fw[1] == 'Z' && geo_location_cc[0]) ? geo_location_cc : cc_fw), sizeof(cd->cc)); return kIOReturnSuccess; } IOReturn AirportItlwm:: setCOUNTRY_CODE(OSObject *object, struct apple80211_country_code_data *data) { XYLog("%s cc=%s\n", __FUNCTION__, data->cc); if (data && data->cc[0] != 120 && data->cc[0] != 88) { memcpy(geo_location_cc, data->cc, sizeof(geo_location_cc)); fNetIf->postMessage(APPLE80211_M_COUNTRY_CODE_CHANGED); } return kIOReturnSuccess; } IOReturn AirportItlwm:: getMCS(OSObject *object, struct apple80211_mcs_data* md) { struct ieee80211com *ic = fHalService->get80211Controller(); if (ic->ic_state != IEEE80211_S_RUN || ic->ic_bss == NULL || !md) return 6; md->version = APPLE80211_VERSION; md->index = ic->ic_bss->ni_txmcs; return kIOReturnSuccess; } IOReturn AirportItlwm:: getROAM_THRESH(OSObject *object, struct apple80211_roam_threshold_data* md) { if (!md) return kIOReturnError; md->threshold = 100; md->count = 0; return kIOReturnSuccess; } IOReturn AirportItlwm:: getRADIO_INFO(OSObject *object, struct apple80211_radio_info_data* md) { if (!md) return kIOReturnError; md->version = APPLE80211_VERSION; md->count = 1; return kIOReturnSuccess; } IOReturn AirportItlwm:: setSCAN_REQ(OSObject *object, struct apple80211_scan_data *sd) { struct ieee80211com *ic = fHalService->get80211Controller(); #if 0 XYLog("%s Type: %u BSS Type: %u PHY Mode: %u Dwell time: %u Rest time: %u Num channels: %u SSID: %s BSSID: %s\n", __FUNCTION__, sd->scan_type, sd->bss_type, sd->phy_mode, sd->dwell_time, sd->rest_time, sd->num_channels, sd->ssid, ether_sprintf(sd->bssid.octet)); #endif if (fScanResultWrapping) return 22; if (ic->ic_state <= IEEE80211_S_INIT) return 22; if (sd->scan_type == APPLE80211_SCAN_TYPE_FAST || sd->scan_type == APPLE80211_SCAN_TYPE_PASSIVE) { if (scanSource) { scanSource->setTimeoutMS(100); scanSource->enable(); } return kIOReturnSuccess; } ieee80211_begin_cache_bgscan(&ic->ic_ac.ac_if); if (scanSource) { scanSource->setTimeoutMS(100); scanSource->enable(); } return kIOReturnSuccess; } IOReturn AirportItlwm:: setSCAN_REQ_MULTIPLE(OSObject *object, struct apple80211_scan_multiple_data *sd) { struct ieee80211com *ic = fHalService->get80211Controller(); #if 0 int i; XYLog("%s Type: %u SSID Count: %u BSSID Count: %u PHY Mode: %u Dwell time: %u Rest time: %u Num channels: %u Unk: %u\n", __FUNCTION__, sd->scan_type, sd->ssid_count, sd->bssid_count, sd->phy_mode, sd->dwell_time, sd->rest_time, sd->num_channels, sd->unk_2); for (i = 0; i < sd->ssid_count; i++) XYLog("%s index=%d ssid=%s ssid_len=%d\n", __FUNCTION__, i, sd->ssids[i].ssid_bytes, sd->ssids[i].ssid_len); #endif if (fScanResultWrapping) return 22; if (ic->ic_state <= IEEE80211_S_INIT) return 22; ieee80211_begin_cache_bgscan(&ic->ic_ac.ac_if); if (scanSource) { scanSource->setTimeoutMS(100); scanSource->enable(); } return kIOReturnSuccess; } IOReturn AirportItlwm:: getSCAN_RESULT(OSObject *object, struct apple80211_scan_result **sr) { struct ieee80211com *ic = fHalService->get80211Controller(); if (fNextNodeToSend == NULL) { if (fScanResultWrapping) { fScanResultWrapping = false; return 5; } else { fNextNodeToSend = RB_MIN(ieee80211_tree, &ic->ic_tree); if (fNextNodeToSend == NULL) return 12; } } // XYLog("%s ni_bssid=%s ni_essid=%s channel=%d flags=%d asr_cap=%d asr_nrates=%d asr_ssid_len=%d asr_ie_len=%d asr_rssi=%d\n", __FUNCTION__, ether_sprintf(fNextNodeToSend->ni_bssid), fNextNodeToSend->ni_essid, ieee80211_chan2ieee(ic, fNextNodeToSend->ni_chan), ieeeChanFlag2apple(fNextNodeToSend->ni_chan->ic_flags), fNextNodeToSend->ni_capinfo, fNextNodeToSend->ni_rates.rs_nrates, fNextNodeToSend->ni_esslen, fNextNodeToSend->ni_rsnie_tlv == NULL ? 0 : fNextNodeToSend->ni_rsnie_tlv_len, fNextNodeToSend->ni_rssi); apple80211_scan_result* result = (apple80211_scan_result* )fNextNodeToSend->verb; bzero(result, sizeof(*result)); result->version = APPLE80211_VERSION; if (fNextNodeToSend->ni_rsnie_tlv && fNextNodeToSend->ni_rsnie_tlv_len > 0) { result->asr_ie_len = fNextNodeToSend->ni_rsnie_tlv_len; #if __IO80211_TARGET < __MAC_12_0 result->asr_ie_data = fNextNodeToSend->ni_rsnie_tlv; #else memcpy(result->asr_ie_data, fNextNodeToSend->ni_rsnie_tlv, MIN(result->asr_ie_len, sizeof(result->asr_ie_data))); #endif } else { result->asr_ie_len = 0; #if __IO80211_TARGET < __MAC_12_0 result->asr_ie_data = NULL; #endif } result->asr_beacon_int = fNextNodeToSend->ni_intval; for (int i = 0; i < result->asr_nrates; i++ ) result->asr_rates[i] = fNextNodeToSend->ni_rates.rs_rates[i]; result->asr_nrates = fNextNodeToSend->ni_rates.rs_nrates; result->asr_age = (uint32_t)(airport_up_time() - fNextNodeToSend->ni_age_ts); result->asr_cap = fNextNodeToSend->ni_capinfo; result->asr_channel.version = APPLE80211_VERSION; result->asr_channel.channel = ieee80211_chan2ieee(ic, fNextNodeToSend->ni_chan); #if __IO80211_TARGET < __MAC_13_0 result->asr_channel.flags = ieeeChanFlag2apple(fNextNodeToSend->ni_chan->ic_flags, -1); #else result->asr_channel.flags = ieeeChanFlag2appleScanFlagVentura(fNextNodeToSend->ni_chan->ic_flags); #endif result->asr_noise = -fHalService->getDriverInfo()->getBSSNoise(); result->asr_rssi = -(0 - IWM_MIN_DBM - fNextNodeToSend->ni_rssi); memcpy(result->asr_bssid, fNextNodeToSend->ni_bssid, IEEE80211_ADDR_LEN); result->asr_ssid_len = fNextNodeToSend->ni_esslen; if (result->asr_ssid_len != 0) memcpy(&result->asr_ssid, fNextNodeToSend->ni_essid, result->asr_ssid_len); *sr = result; fNextNodeToSend = RB_NEXT(ieee80211_tree, &ic->ic_tree, fNextNodeToSend); if (fNextNodeToSend == NULL) fScanResultWrapping = true; return kIOReturnSuccess; } IOReturn AirportItlwm:: setVIRTUAL_IF_CREATE(OSObject *object, struct apple80211_virt_if_create_data* data) { // From Ventura, the virtual interface sequence has channged, now temporary disabled the virtual interface creation because it is no functionality. This fix the issue of delaying start time of associating to AP. #if __IO80211_TARGET >= __MAC_13_0 return kIOReturnUnsupported; #else struct ether_addr addr; struct apple80211_channel chann; XYLog("%s role=%d, bsd_name=%s, mac=%s, unk1=%d\n", __FUNCTION__, data->role, data->bsd_name, ether_sprintf(data->mac), data->unk1); if (data->role == APPLE80211_VIF_P2P_DEVICE) { IO80211P2PInterface *inf = new IO80211P2PInterface; if (inf == NULL) return kIOReturnError; memcpy(addr.octet, data->mac, 6); inf->init(this, &addr, data->role, "p2p"); fP2PDISCInterface = inf; } else if (data->role == APPLE80211_VIF_P2P_GO) { IO80211P2PInterface *inf = new IO80211P2PInterface; if (inf == NULL) return kIOReturnError; memcpy(addr.octet, data->mac, 6); inf->init(this, &addr, data->role, "p2p"); fP2PGOInterface = inf; } else if (data->role == APPLE80211_VIF_AWDL) { if (fAWDLInterface != NULL && strncmp((const char *)data->bsd_name, "awdl", 4) == 0) { XYLog("%s awdl interface already exists!\n", __FUNCTION__); return kIOReturnSuccess; } IO80211P2PInterface *inf = new IO80211P2PInterface; if (inf == NULL) return kIOReturnError; memcpy(addr.octet, data->mac, 6); inf->init(this, &addr, data->role, "awdl"); chann.channel = 149; chann.version = 1; chann.flags = APPLE80211_C_FLAG_5GHZ | APPLE80211_C_FLAG_ACTIVE | APPLE80211_C_FLAG_80MHZ; setInfraChannel(&chann); fAWDLInterface = inf; } else { XYLog("%s unhandled virtual interface role type: %d\n", __FUNCTION__, data->role); return kIOReturnError; } return kIOReturnSuccess; #endif } IOReturn AirportItlwm:: setVIRTUAL_IF_DELETE(OSObject *object, struct apple80211_virt_if_delete_data *data) { XYLog("%s bsd_name=%s\n", __FUNCTION__, data->bsd_name); //TODO find vif according to the bsd_name IO80211VirtualInterface *vif = OSDynamicCast(IO80211VirtualInterface, object); if (vif == NULL) return kIOReturnError; detachVirtualInterface(vif, false); vif->release(); return kIOReturnSuccess; } IOReturn AirportItlwm:: getLINK_CHANGED_EVENT_DATA(OSObject *object, struct apple80211_link_changed_event_data *ed) { if (ed == nullptr) return 16; struct ieee80211com *ic = fHalService->get80211Controller(); bzero(ed, sizeof(apple80211_link_changed_event_data)); ed->isLinkDown = !(currentStatus & kIONetworkLinkActive); if (ed->isLinkDown) { ed->voluntary = disassocIsVoluntary; ed->reason = APPLE80211_LINK_DOWN_REASON_DEAUTH; } else ed->rssi = -(0 - IWM_MIN_DBM - ic->ic_bss->ni_rssi); XYLog("Link %s, reason: %d, voluntary: %d\n", ed->isLinkDown ? "down" : "up", ed->reason, ed->voluntary); return kIOReturnSuccess; } ================================================ FILE: AirportItlwm/AirportVirtualIOCTL.cpp ================================================ // // AirportVirtualIOCTL.cpp // AirportItlwm // // Created by qcwap on 2020/9/4. // Copyright © 2020 钟先耀. All rights reserved. // #include "AirportItlwm.hpp" SInt32 AirportItlwm:: apple80211VirtualRequest(UInt request_type, int request_number, IO80211VirtualInterface *interface, void *data) { if (request_type != SIOCGA80211 && request_type != SIOCSA80211) return kIOReturnError; IOReturn ret = kIOReturnError; switch (request_number) { case APPLE80211_IOC_CARD_CAPABILITIES: IOCTL_GET(request_type, CARD_CAPABILITIES, apple80211_capability_data); break; case APPLE80211_IOC_POWER: IOCTL_GET(request_type, POWER, apple80211_power_data); break; case APPLE80211_IOC_SUPPORTED_CHANNELS: IOCTL_GET(request_type, SUPPORTED_CHANNELS, apple80211_sup_channel_data); break; case APPLE80211_IOC_DRIVER_VERSION: IOCTL_GET(request_type, DRIVER_VERSION, apple80211_version_data); break; case APPLE80211_IOC_OP_MODE: IOCTL_GET(request_type, OP_MODE, apple80211_opmode_data); break; case APPLE80211_IOC_PHY_MODE: IOCTL_GET(request_type, PHY_MODE, apple80211_phymode_data); break; case APPLE80211_IOC_RSSI: IOCTL_GET(request_type, RSSI, apple80211_rssi_data); break; case APPLE80211_IOC_STATE: IOCTL_GET(request_type, STATE, apple80211_state_data); break; case APPLE80211_IOC_BSSID: IOCTL(request_type, BSSID, apple80211_bssid_data); break; case APPLE80211_IOC_RATE: IOCTL_GET(request_type, RATE, apple80211_rate_data); break; case APPLE80211_IOC_CHANNEL: IOCTL(request_type, CHANNEL, apple80211_channel_data); break; case APPLE80211_IOC_AUTH_TYPE: IOCTL(request_type, AUTH_TYPE, apple80211_authtype_data); break; case APPLE80211_IOC_ROAM_PROFILE: IOCTL(request_type, ROAM_PROFILE, apple80211_roam_profile_band_data); break; case APPLE80211_IOC_SSID: IOCTL(request_type, SSID, apple80211_ssid_data); break; case APPLE80211_IOC_AWDL_PEER_TRAFFIC_REGISTRATION: IOCTL(request_type, AWDL_PEER_TRAFFIC_REGISTRATION, apple80211_awdl_peer_traffic_registration); break; case APPLE80211_IOC_AWDL_SYNC_ENABLED: IOCTL(request_type, SYNC_ENABLED, apple80211_awdl_sync_enabled); break; case APPLE80211_IOC_AWDL_SYNC_FRAME_TEMPLATE: IOCTL(request_type, SYNC_FRAME_TEMPLATE, apple80211_awdl_sync_frame_template); break; case APPLE80211_IOC_HT_CAPABILITY: IOCTL_GET(request_type, AWDL_HT_CAPABILITY, apple80211_ht_capability); break; case APPLE80211_IOC_VHT_CAPABILITY: IOCTL_GET(request_type, AWDL_VHT_CAPABILITY, apple80211_vht_capability); break; case APPLE80211_IOC_AWDL_ELECTION_METRIC: IOCTL(request_type, AWDL_ELECTION_METRIC, apple80211_awdl_election_metric); break; case APPLE80211_IOC_AWDL_BSSID: IOCTL(request_type, AWDL_BSSID, apple80211_awdl_bssid); break; case APPLE80211_IOC_CHANNELS_INFO: IOCTL_GET(request_type, CHANNELS_INFO, apple80211_channels_info); break; case APPLE80211_IOC_PEER_CACHE_MAXIMUM_SIZE: IOCTL(request_type, PEER_CACHE_MAXIMUM_SIZE, apple80211_peer_cache_maximum_size); break; case APPLE80211_IOC_AWDL_ELECTION_ID: IOCTL(request_type, AWDL_ELECTION_ID, apple80211_awdl_election_id); break; case APPLE80211_IOC_AWDL_MASTER_CHANNEL: IOCTL(request_type, AWDL_MASTER_CHANNEL, apple80211_awdl_master_channel); break; case APPLE80211_IOC_AWDL_SECONDARY_MASTER_CHANNEL: IOCTL(request_type, AWDL_SECONDARY_MASTER_CHANNEL, apple80211_awdl_secondary_master_channel); break; case APPLE80211_IOC_AWDL_MIN_RATE: IOCTL(request_type, AWDL_MIN_RATE, apple80211_awdl_min_rate); break; case APPLE80211_IOC_AWDL_ELECTION_RSSI_THRESHOLDS: IOCTL(request_type, AWDL_ELECTION_RSSI_THRESHOLDS, apple80211_awdl_election_rssi_thresholds); break; case APPLE80211_IOC_AWDL_SYNCHRONIZATION_CHANNEL_SEQUENCE: IOCTL(request_type, AWDL_SYNCHRONIZATION_CHANNEL_SEQUENCE, apple80211_awdl_sync_channel_sequence); break; case APPLE80211_IOC_AWDL_PRESENCE_MODE: IOCTL(request_type, AWDL_PRESENCE_MODE, apple80211_awdl_presence_mode); break; case APPLE80211_IOC_AWDL_EXTENSION_STATE_MACHINE_PARAMETERS: IOCTL(request_type, AWDL_EXTENSION_STATE_MACHINE_PARAMETERS, apple80211_awdl_extension_state_machine_parameter); break; case APPLE80211_IOC_AWDL_SYNC_STATE: IOCTL(request_type, AWDL_SYNC_STATE, apple80211_awdl_sync_state); break; case APPLE80211_IOC_AWDL_SYNC_PARAMS: IOCTL(request_type, AWDL_SYNC_PARAMS, apple80211_awdl_sync_params); break; case APPLE80211_IOC_AWDL_CAPABILITIES: IOCTL_GET(request_type, AWDL_CAPABILITIES, apple80211_awdl_cap); break; case APPLE80211_IOC_AWDL_AF_TX_MODE: IOCTL(request_type, AWDL_AF_TX_MODE, apple80211_awdl_af_tx_mode); break; case APPLE80211_IOC_AWDL_OOB_AUTO_REQUEST: IOCTL_SET(request_type, AWDL_OOB_AUTO_REQUEST, apple80211_awdl_oob_request); break; case APPLE80211_IOC_IE: IOCTL(request_type, IE, apple80211_ie_data); break; case APPLE80211_IOC_P2P_LISTEN: IOCTL_SET(request_type, P2P_LISTEN, apple80211_p2p_listen_data); break; case APPLE80211_IOC_P2P_SCAN: IOCTL_SET(request_type, P2P_SCAN, apple80211_scan_data); break; case APPLE80211_IOC_P2P_GO_CONF: IOCTL_SET(request_type, P2P_GO_CONF, apple80211_p2p_go_conf_data); break; default: unhandled: if (!ml_at_interrupt_context()) XYLog("%s Unhandled IOCTL %s (%d) %s\n", __FUNCTION__, IOCTL_NAMES[request_number >= ARRAY_SIZE(IOCTL_NAMES) ? 0: request_number], request_number, request_type == SIOCGA80211 ? "get" : (request_type == SIOCSA80211 ? "set" : "other")); break; } return ret; } IOReturn AirportItlwm:: setAWDL_PEER_TRAFFIC_REGISTRATION(OSObject *object, struct apple80211_awdl_peer_traffic_registration *data) { char name[255]; if (data->name_len > 0 && data->name_len < 255) { bzero(name, 255); memcpy(name, data->name, data->name_len); } XYLog("%s name=%s, name_len=%d, active=%d\n", __FUNCTION__, name, data->name_len, data->active); if (!strncmp(data->name, "wifid-assisted-discovery", data->name_len)) { if (data->active) { } else { } } else if (!strncmp(data->name, "sidecar", data->name_len)) { } return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_PEER_TRAFFIC_REGISTRATION(OSObject *object, struct apple80211_awdl_peer_traffic_registration *) { XYLog("%s\n", __FUNCTION__); if (fAWDLInterface) return 45; return 22; } IOReturn AirportItlwm:: setAWDL_ELECTION_METRIC(OSObject *object, struct apple80211_awdl_election_metric *data) { XYLog("%s metric=%d\n", __FUNCTION__, data->metric); return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_ELECTION_METRIC(OSObject *object, struct apple80211_awdl_election_metric *data) { XYLog("%s\n", __FUNCTION__); return kIOReturnError; } IOReturn AirportItlwm:: getSYNC_ENABLED(OSObject *object, struct apple80211_awdl_sync_enabled *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; data->enabled = this->awdlSyncEnable; data->unk1 = 0; return kIOReturnSuccess; } IOReturn AirportItlwm:: setSYNC_ENABLED(OSObject *object, struct apple80211_awdl_sync_enabled *data) { XYLog("%s sync_enabled=%d\n", __FUNCTION__, data->enabled); this->awdlSyncEnable = data->enabled; return kIOReturnSuccess; } IOReturn AirportItlwm:: getSYNC_FRAME_TEMPLATE(OSObject *object, struct apple80211_awdl_sync_frame_template *data) { XYLog("%s\n", __FUNCTION__); if (syncFrameTemplate == NULL || syncFrameTemplateLength == 0) return kIOReturnError; data->version = APPLE80211_VERSION; data->payload_len = syncFrameTemplateLength; memcpy(data->payload, syncFrameTemplate, syncFrameTemplateLength); return kIOReturnSuccess; } IOReturn AirportItlwm:: setSYNC_FRAME_TEMPLATE(OSObject *object, struct apple80211_awdl_sync_frame_template *data) { XYLog("%s payload_len=%d\n", __FUNCTION__, data->payload_len); if (data->payload_len <= 0) return kIOReturnError; if (syncFrameTemplate != NULL && syncFrameTemplateLength > 0) { IOFree(syncFrameTemplate, syncFrameTemplateLength); syncFrameTemplateLength = 0; syncFrameTemplate = NULL; } syncFrameTemplate = (uint8_t *)IOMalloc(data->payload_len); syncFrameTemplateLength = data->payload_len; memset(syncFrameTemplate, 0, data->payload_len); memcpy(syncFrameTemplate, data->payload, data->payload_len); return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_HT_CAPABILITY(OSObject *object, struct apple80211_ht_capability *data) { memset(data, 0, sizeof(*data)); data->version = APPLE80211_VERSION; data->hc_id = IEEE80211_ELEMID_HTCAPS; data->hc_cap = (IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_CBW20_40 | IEEE80211_HTCAP_SGI40); return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_VHT_CAPABILITY(OSObject *object, struct apple80211_vht_capability *data) { memset(data, 0, sizeof(*data)); data->version = APPLE80211_VERSION; data->cap = 3263; return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_BSSID(OSObject *object, struct apple80211_awdl_bssid *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; memcpy(data->bssid, awdlBSSID, 6); return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_BSSID(OSObject *object, struct apple80211_awdl_bssid *data) { XYLog("%s bssid=%s unk_mac=%s\n", __FUNCTION__, ether_sprintf(data->bssid), ether_sprintf(data->unk_mac)); memcpy(awdlBSSID, data->bssid, 6); return kIOReturnSuccess; } IOReturn AirportItlwm:: getCHANNELS_INFO(OSObject *object, struct apple80211_channels_info *data) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = fHalService->get80211Controller(); memset(data, 0, sizeof(*data)); data->version = APPLE80211_VERSION; for (int i = 0; i < IEEE80211_CHAN_MAX; i++) { struct ieee80211_channel *channel = &ic->ic_channels[i]; if (channel->ic_freq != 0) { int chanNum = ieee80211_chan2ieee(ic, channel); data->chan_num[data->num_chan_specs] = chanNum; data->support_80Mhz[data->num_chan_specs] = IEEE80211_IS_CHAN_VHT80(channel); data->support_40Mhz[data->num_chan_specs] = IEEE80211_IS_CHAN_HT40(channel) || IEEE80211_IS_CHAN_VHT40(channel); data->num_chan_specs++; if (data->num_chan_specs >= APPLE80211_MAX_CHANNELS) break; } } return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_ELECTION_ID(OSObject *object, struct apple80211_awdl_election_id *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; data->election_id = awdlElectionId; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_ELECTION_ID(OSObject *object, struct apple80211_awdl_election_id *data) { XYLog("%s election_id=%d\n", __FUNCTION__, data->election_id); awdlElectionId = data->election_id; return kIOReturnSuccess; } IOReturn AirportItlwm:: getPEER_CACHE_MAXIMUM_SIZE(OSObject *object, struct apple80211_peer_cache_maximum_size *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; data->max_peers = 255; return kIOReturnSuccess; } IOReturn AirportItlwm:: setPEER_CACHE_MAXIMUM_SIZE(OSObject *object, struct apple80211_peer_cache_maximum_size *data) { XYLog("%s max_peers=%d\n", __FUNCTION__, data->max_peers); return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_MASTER_CHANNEL(OSObject *object, struct apple80211_awdl_master_channel *data) { data->version = APPLE80211_VERSION; data->master_channel = awdlMasterChannel; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_MASTER_CHANNEL(OSObject *object, struct apple80211_awdl_master_channel *data) { XYLog("%s master_channel=%d\n", __FUNCTION__, data->master_channel); awdlMasterChannel = data->master_channel; return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_SECONDARY_MASTER_CHANNEL(OSObject *object, struct apple80211_awdl_secondary_master_channel *data) { XYLog("%s temporary return channel 0\n", __FUNCTION__); data->version = APPLE80211_VERSION; data->secondary_master_channel = awdlSecondaryMasterChannel; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_SECONDARY_MASTER_CHANNEL(OSObject *object, struct apple80211_awdl_secondary_master_channel *data) { XYLog("%s secondary_master_channel=%d\n", __FUNCTION__, data->secondary_master_channel); awdlSecondaryMasterChannel = data->secondary_master_channel; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_MIN_RATE(OSObject *object, struct apple80211_awdl_min_rate *data) { XYLog("%s min_rate=%d plus=%d\n", __FUNCTION__, data->min_rate, 2 *data->min_rate); return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_MIN_RATE(OSObject *object, struct apple80211_awdl_min_rate *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_ELECTION_RSSI_THRESHOLDS(OSObject *object, struct apple80211_awdl_election_rssi_thresholds *data) { XYLog("%s\n", __FUNCTION__); return kIOReturnError; } IOReturn AirportItlwm:: setAWDL_ELECTION_RSSI_THRESHOLDS(OSObject *object, struct apple80211_awdl_election_rssi_thresholds *data) { XYLog("%s unk1=%d unk2=%d unk3=%d\n", __FUNCTION__, data->unk1, data->unk2, data->unk3); return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_SYNCHRONIZATION_CHANNEL_SEQUENCE(OSObject *object, struct apple80211_awdl_sync_channel_sequence *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; return kIOReturnSuccess; } #if 0 static void dumpAWDLChannelSeqs(struct apple80211_awdl_sync_channel_sequence *data) { if (data == nullptr) return; XYLog("%s length %u step count %u duplicate %u fill %d encoding %u\n", __FUNCTION__, data->length, data->step_count, data->duplicate_count, data->fill_channel, data->encoding); for (int i = 0; i < data->length; i++) { struct apple80211_channel_sequence seq = data->seqs[i]; uint16_t band = seq.flags & 0xC00; uint16_t channel = seq.flags & 0x300; XYLog("%s %d 0x%04x=%d%s%s%s\n", __FUNCTION__, i, seq.flags, (uint8_t)seq.flags, band != 0x800 ? (band == 0xC00 ? ",20MHz" : ",unknown") : ",20MHz", channel != 0x200 ? (channel == 0x100 ? ",-1" : ",none") : ",1", (seq.flags & 0xF000) == 4096 ? ",5GHz" : ",unknown"); } } #endif IOReturn AirportItlwm:: setAWDL_SYNCHRONIZATION_CHANNEL_SEQUENCE(OSObject *object, struct apple80211_awdl_sync_channel_sequence *data) { XYLog("%s\n", __FUNCTION__); #if 0 dumpAWDLChannelSeqs(data); #endif return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_PRESENCE_MODE(OSObject *object, struct apple80211_awdl_presence_mode *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; data->mode = awdlPresenceMode; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_PRESENCE_MODE(OSObject *object, struct apple80211_awdl_presence_mode *data) { XYLog("%s mode=%d\n", __FUNCTION__, data->mode); awdlPresenceMode = data->mode; return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_EXTENSION_STATE_MACHINE_PARAMETERS(OSObject *object, struct apple80211_awdl_extension_state_machine_parameter *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_EXTENSION_STATE_MACHINE_PARAMETERS(OSObject *object, struct apple80211_awdl_extension_state_machine_parameter *data) { XYLog("%s unk1=%d unk2=%d unk3=%d unk4=%d\n", __FUNCTION__, data->unk1, data->unk2, data->unk3, data->unk4); return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_SYNC_STATE(OSObject *object, struct apple80211_awdl_sync_state *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; data->state = awdlSyncState; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_SYNC_STATE(OSObject *object, struct apple80211_awdl_sync_state *data) { XYLog("%s state=%d\n", __FUNCTION__, data->state); awdlSyncState = data->state; return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_SYNC_PARAMS(OSObject *object, struct apple80211_awdl_sync_params *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_SYNC_PARAMS(OSObject *object, struct apple80211_awdl_sync_params *data) { XYLog("%s availability_window_length=%d availability_window_period=%d extension_length=%d synchronization_frame_period=%d\n", __FUNCTION__, data->availability_window_length, data->availability_window_period, data->extension_length, data->synchronization_frame_period); return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_CAPABILITIES(OSObject *object, struct apple80211_awdl_cap *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; data->cap = APPLE80211_AWDL_CAP_CCA_STATS; return kIOReturnSuccess; } IOReturn AirportItlwm:: getAWDL_AF_TX_MODE(OSObject *object, struct apple80211_awdl_af_tx_mode *data) { XYLog("%s\n", __FUNCTION__); data->version = APPLE80211_VERSION; return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_AF_TX_MODE(OSObject *object, struct apple80211_awdl_af_tx_mode *data) { XYLog("%s mode=%llu\n", __FUNCTION__, data->mode); return kIOReturnSuccess; } IOReturn AirportItlwm:: setAWDL_OOB_AUTO_REQUEST(OSObject *object, struct apple80211_awdl_oob_request *data) { XYLog("%s data_len=%d unk1=%d unk2=%d unk3=%d unk4=%d unk5=%d unk6=%d unk7=%d unk9=%d\n", __FUNCTION__, data->data_len, data->unk1, data->unk2, data->unk3, data->unk4, data->unk5, data->unk6, data->unk7, data->unk9); return kIOReturnSuccess; } ================================================ FILE: AirportItlwm/IOPCIEDeviceWrapper.cpp ================================================ // // IOPCIEDeviceWrapper.cpp // AirportItlwm-Sonoma // // Created by qcwap on 2023/6/27. // Copyright © 2023 钟先耀. All rights reserved. // #include "IOPCIEDeviceWrapper.hpp" #include "Apple80211.h" #include "ItlIwm.hpp" #include "ItlIwx.hpp" #include "ItlIwn.hpp" #define super IOService OSDefineMetaClassAndStructors(IOPCIEDeviceWrapper, IOService); #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 IOPMPowerState powerStateArray[2] = { {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, kIOPMDeviceUsable, kIOPMPowerOn, kIOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0} }; static void pciMsiSetEnable(IOPCIDevice *device, UInt8 msiCap, int enable) { UInt16 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) { UInt16 ctrl; ctrl = device->configRead16(msixCap + PCI_MSIX_FLAGS); ctrl &= ~clear; ctrl |= set; device->configWrite16(msixCap + PCI_MSIX_FLAGS, ctrl); } extern IOWorkLoop *_fWorkloop; IOWorkLoop *IOPCIEDeviceWrapper::getWorkLoop() const { return _fWorkloop; } IOService* IOPCIEDeviceWrapper:: probe(IOService *provider, SInt32 *score) { XYLog("%s\n", __PRETTY_FUNCTION__); bool isMatch = false; 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) { XYLog("%s Found\n", __FUNCTION__); 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; } this->pciNub = device; return this; } return NULL; } bool IOPCIEDeviceWrapper:: start(IOService *provider) { XYLog("%s\n", __PRETTY_FUNCTION__); _fWorkloop = IO80211WorkQueue::workQueue(); if (!super::start(provider)) { return false; } IOLog("%s::super start succeed\n", getName()); UInt8 builtIn = 0; setProperty("built-in", OSData::withBytes(&builtIn, sizeof(builtIn))); PMinit(); registerPowerDriver(this, powerStateArray, 2); provider->joinPMtree(this); registerService(); return true; } void IOPCIEDeviceWrapper:: stop(IOService *provider) { XYLog("%s\n", __PRETTY_FUNCTION__); PMstop(); super::stop(provider); } IOReturn IOPCIEDeviceWrapper:: setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice) { return IOPMAckImplied; } ================================================ FILE: AirportItlwm/IOPCIEDeviceWrapper.hpp ================================================ // // IOPCIEDeviceWrapper.hpp // AirportItlwm-Sonoma // // Created by qcwap on 2023/6/27. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef IOPCIEDeviceWrapper_hpp #define IOPCIEDeviceWrapper_hpp #include #include #include #include #include class IOPCIEDeviceWrapper : public IOService { OSDeclareDefaultStructors(IOPCIEDeviceWrapper) public: virtual IOService* probe(IOService* provider, SInt32* score) override; virtual bool start(IOService *provider) override; virtual void stop(IOService *provider) override; virtual IOWorkLoop* getWorkLoop() const override; virtual IOReturn setPowerState( unsigned long powerStateOrdinal, IOService * whatDevice ) override; public: ItlHalService *fHalService; IOPCIDevice *pciNub; }; #endif /* IOPCIEDeviceWrapper_hpp */ ================================================ FILE: AirportItlwm/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString $(MODULE_VERSION) CFBundleVersion $(MODULE_VERSION) IOKitPersonalities itlwm CFBundleIdentifier com.zxystd.AirportItlwm IOClass AirportItlwm IOMatchCategory IODefaultMatchCategory IOPCIMatch 0x27238086 0x43F08086 0xA0F08086 0x34F08086 0x4DF08086 0x02F08086 0x3DF08086 0x06F08086 0x27208086 0x08b18086 0x08b28086 0x08b38086 0x08b48086 0x095a8086 0x095b8086 0x31658086 0x31668086 0x24f38086 0x24f48086 0x24f58086 0x24f68086 0x24fb8086 0x24fd8086 0x25268086 0x9df08086 0xa3708086 0x31DC8086 0x30DC8086 0x271C8086 0x271B8086 0x42a48086 0x00a08086 0x00a48086 0x02a08086 0x40a48086 0x00608086 0x00648086 0x02608086 0x02648086 0x42298086 0x422b8086 0x422c8086 0x42308086 0x42328086 0x42358086 0x42368086 0x42378086 0x42388086 0x42398086 0x423a8086 0x423b8086 0x423c8086 0x423d8086 0x00828086 0x00838086 0x00848086 0x00858086 0x00878086 0x00898086 0x008a8086 0x008b8086 0x00908086 0x00918086 0x08928086 0x08938086 0x08948086 0x08958086 0x08968086 0x08978086 0x08ae8086 0x08af8086 0x088e8086 0x088f8086 0x08908086 0x08918086 0x08878086 0x08888086 0x27258086 0x27268086 0x7A708086 0x7AF08086 0x51F08086 0x54F08086 0x27298086 0x7E408086 0x7F708086 0x51F18086 IOProbeScore 2000 IOProviderClass IOPCIDevice NSHumanReadableCopyright Copyright © 2020 钟先耀. All rights reserved. OSBundleLibraries com.apple.iokit.IO80211Family 1200.12.2b1 com.apple.iokit.IONetworkingFamily 3.2 com.apple.iokit.IOPCIFamily 2.9 com.apple.kpi.bsd 16.7 com.apple.kpi.iokit 16.7 com.apple.kpi.libkern 16.7 com.apple.kpi.mach 16.7 OSBundleRequired Network-Root ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: README.md ================================================ # itlwm **An Intel Wi-Fi Adapter Kernel Extension for macOS, based on the OpenBSD Project.** ## Documentation We highly recommend exploring our documentation before using this Kernel Extension: - [Intro](https://OpenIntelWireless.github.io/itlwm) - [Compatibility](https://openintelwireless.github.io/itlwm/Compat) - [FAQ](https://openintelwireless.github.io/itlwm/FAQ) ## Download [![Download from https://github.com/OpenIntelWireless/itlwm/releases](https://img.shields.io/github/v/release/OpenIntelWireless/itlwm?label=Download)](https://github.com/OpenIntelWireless/itlwm/releases) ## Questions and Issues Check out our [FAQ Page](https://openintelwireless.github.io/itlwm/FAQ) for more info. If you have other questions or feedback, feel free to [![Join the chat at https://gitter.im/OpenIntelWireless/itlwm](https://badges.gitter.im/OpenIntelWireless/itlwm.svg)](https://gitter.im/OpenIntelWireless/itlwm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge). We only accept bug reports in GitHub Issues, before opening an issue, you're recommended to reconfirm it with us on [Gitter](https://gitter.im/OpenIntelWireless/itlwm); once it's confirmed, please use the provided issue template. ## Credits - [Acidanthera](https://github.com/acidanthera) for [MacKernelSDK](https://github.com/acidanthera/MacKernelSDK) - [Apple](https://www.apple.com) for [macOS](https://www.apple.com/macos) - [AppleIntelWiFi](https://github.com/AppleIntelWiFi) for [Black80211-Catalina](https://github.com/AppleIntelWiFi/Black80211-Catalina) - [ErrorErrorError](https://github.com/ErrorErrorError) for UserClient bug fixes - [Intel](https://www.intel.com) for [Wireless Adapter Firmwares](https://www.intel.com/content/www/us/en/support/articles/000005511/network-and-io/wireless.html) and [iwlwifi](https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi) - [Linux](https://www.kernel.org) for [iwlwifi](https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi) - [mercurysquad](https://github.com/mercurysquad) for [Voodoo80211](https://github.com/mercurysquad/Voodoo80211) - [OpenBSD](https://openbsd.org) for [net80211, iwn, iwm, and iwx](https://github.com/openbsd/src) - [pigworlds](https://github.com/OpenIntelWireless/itlwm/commits?author=pigworlds) for DVM devices support, MIRA bug fixes, and Tx aggregation for MVM Gen 1 devices - [rpeshkov](https://github.com/rpeshkov) for [black80211](https://github.com/rpeshkov/black80211) - [usr-sse2](https://github.com/usr-sse2) for implementing the usage of Apple RSN Supplicant and bug fixes - [zxystd](https://github.com/zxystd) for developing [itlwm](https://github.com/OpenIntelWireless/itlwm) ## Acknowledgements - [@penghubingzhou](https://github.com/startpenghubingzhou) - [@Bat.bat](https://github.com/williambj1) - [@iStarForever](https://github.com/XStar-Dev) - [@stevezhengshiqi](https://github.com/stevezhengshiqi) - [@DogAndPot](https://github.com/DogAndPot) for providing resources and help for system configuration - [@Daliansky](https://github.com/Daliansky) for providing Wi-Fi cards ================================================ FILE: include/Airport/Apple80211.h ================================================ // // Apple80211.h // itlwm // // Created by qcwap on 2020/9/4. // Copyright © 2020 钟先耀. All rights reserved. // #ifndef Apple80211_h #define Apple80211_h #include "apple_private_spi.h" #include "debug.h" #include "IO80211WorkLoop.h" #ifdef IO80211FAMILY_V2 #include "IO80211WorkQueue.h" #include "IO80211ControllerV2.h" #include "IO80211InfraInterface.h" #include "IO80211InfraProtocol.h" #include "IOSkywalkPacketBufferPool.h" #include "IOSkywalkLegacyEthernetInterface.h" #include "IO80211SkywalkInterface.h" #else #include "IO80211Controller.h" #include "IO80211Interface.h" #include "IO80211VirtualInterface.h" #include "IO80211P2PInterface.h" #endif /* IO80211FAMILY_V2 */ #endif /* Apple80211_h */ ================================================ FILE: include/Airport/CCDataPipe.h ================================================ // // CCDataPipe.h // itlwm // // Created by qcwap on 2023/6/14. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef CCDataPipe_h #define CCDataPipe_h #include "CCPipe.h" #include class CCDataPipeBlob; class CCDataPipe : public CCPipe { OSDeclareDefaultStructors(CCDataPipe) public: virtual void free() APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual bool start( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual void stop( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual void detach( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual IOReturn newUserClient( task_t owningTask, void * securityID, UInt32 type, OSDictionary * properties, LIBKERN_RETURNS_RETAINED IOUserClient ** handler ) APPLE_KEXT_OVERRIDE; virtual bool clientClose(void) APPLE_KEXT_OVERRIDE; virtual void *getCoreCapturePipeReporter(void) APPLE_KEXT_OVERRIDE; virtual bool isClientConnected(void) APPLE_KEXT_OVERRIDE; virtual bool startPipe(void) APPLE_KEXT_OVERRIDE; virtual void stopPipe(void) APPLE_KEXT_OVERRIDE; virtual UInt generateStreamId(void) APPLE_KEXT_OVERRIDE; virtual bool addInitCapture(void) APPLE_KEXT_OVERRIDE; virtual void removeInitCapture(void) APPLE_KEXT_OVERRIDE; virtual void removeCapture(void) APPLE_KEXT_OVERRIDE; virtual bool profileLoaded(void) APPLE_KEXT_OVERRIDE; virtual bool profileRemoved(void) APPLE_KEXT_OVERRIDE; virtual bool capture(CCTimestamp *,char const*) APPLE_KEXT_OVERRIDE; virtual bool capture(CCTimestamp,char const*) APPLE_KEXT_OVERRIDE; virtual bool hasPrivilege(void) APPLE_KEXT_OVERRIDE; virtual bool hasPrivilegeAdministrator(task_t) APPLE_KEXT_OVERRIDE; virtual bool initWithOwnerNameCapacity(IOService *,char const*,char const*,CCPipeOptions const*) APPLE_KEXT_OVERRIDE; virtual OSString *getClassName(void) APPLE_KEXT_OVERRIDE; virtual void setCCaptureInRegistry(void) APPLE_KEXT_OVERRIDE; virtual unsigned long getPipeSize(void) APPLE_KEXT_OVERRIDE; virtual void setPipeSize(unsigned long) APPLE_KEXT_OVERRIDE; virtual void freeCCCaptureObject(void) APPLE_KEXT_OVERRIDE; virtual void *getPipeCallbacks(void) APPLE_KEXT_OVERRIDE; virtual IOService *getProvider(void) APPLE_KEXT_OVERRIDE; virtual void *getCurrentOptions(void) APPLE_KEXT_OVERRIDE; virtual void *getDriverOptions(void) APPLE_KEXT_OVERRIDE; virtual UInt getLoggingFlags(void) APPLE_KEXT_OVERRIDE; virtual unsigned long getRingEntryMaxTimeMs(void) APPLE_KEXT_OVERRIDE; virtual unsigned long getRingEntrySleepTimeMs(void) APPLE_KEXT_OVERRIDE; virtual CCPipeStatistics *getStatistics(void) APPLE_KEXT_OVERRIDE; virtual void setStatistics(CCPipeStatistics *) APPLE_KEXT_OVERRIDE; virtual void publishStatistics(void) APPLE_KEXT_OVERRIDE; virtual void updateStatistics(bool) APPLE_KEXT_OVERRIDE; virtual IOReturn configureAllReports(void) APPLE_KEXT_OVERRIDE; virtual IOReturn updateAllReports(void) APPLE_KEXT_OVERRIDE; virtual void *createReportSet(void) APPLE_KEXT_OVERRIDE; virtual IOReturn enqueueBlob(CCDataPipeBlob *); virtual bool dequeueBlob(CCDataPipeBlob **); virtual void freeResources(void); virtual void notifyTimeout(IOTimerEventSource *); public: uint8_t filter[0x98]; }; #endif /* CCDataPipe_h */ ================================================ FILE: include/Airport/CCLogPipe.h ================================================ // // CCLogPipe.h // itlwm // // Created by qcwap on 2023/6/14. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef CCLogPipe_h #define CCLogPipe_h #include "CCPipe.h" #include "CCLogStream.h" #include typedef int CCLogPolicy; typedef int CCLogState; class CCLogMetadata; class CCLogPipe : public CCPipe { OSDeclareDefaultStructors(CCLogPipe) public: virtual void free() APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual bool start( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual void stop( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual void detach( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual IOReturn newUserClient( task_t owningTask, void * securityID, UInt32 type, OSDictionary * properties, LIBKERN_RETURNS_RETAINED IOUserClient ** handler ) APPLE_KEXT_OVERRIDE; virtual bool clientClose(void) APPLE_KEXT_OVERRIDE; virtual void *getCoreCapturePipeReporter(void) APPLE_KEXT_OVERRIDE; virtual bool isClientConnected(void) APPLE_KEXT_OVERRIDE; virtual bool startPipe(void) APPLE_KEXT_OVERRIDE; virtual void stopPipe(void) APPLE_KEXT_OVERRIDE; virtual UInt generateStreamId(void) APPLE_KEXT_OVERRIDE; virtual bool addInitCapture(void) APPLE_KEXT_OVERRIDE; virtual void removeInitCapture(void) APPLE_KEXT_OVERRIDE; virtual void removeCapture(void) APPLE_KEXT_OVERRIDE; virtual bool profileLoaded(void) APPLE_KEXT_OVERRIDE; virtual bool profileRemoved(void) APPLE_KEXT_OVERRIDE; virtual bool capture(CCTimestamp *,char const*) APPLE_KEXT_OVERRIDE; virtual bool capture(CCTimestamp,char const*) APPLE_KEXT_OVERRIDE; virtual bool hasPrivilege(void) APPLE_KEXT_OVERRIDE; virtual bool hasPrivilegeAdministrator(task_t) APPLE_KEXT_OVERRIDE; virtual bool initWithOwnerNameCapacity(IOService *,char const*,char const*,CCPipeOptions const*) APPLE_KEXT_OVERRIDE; virtual OSString *getClassName(void) APPLE_KEXT_OVERRIDE; virtual void setCCaptureInRegistry(void) APPLE_KEXT_OVERRIDE; virtual unsigned long getPipeSize(void) APPLE_KEXT_OVERRIDE; virtual void setPipeSize(unsigned long) APPLE_KEXT_OVERRIDE; virtual void freeCCCaptureObject(void) APPLE_KEXT_OVERRIDE; virtual void *getPipeCallbacks(void) APPLE_KEXT_OVERRIDE; virtual IOService *getProvider(void) APPLE_KEXT_OVERRIDE; virtual void *getCurrentOptions(void) APPLE_KEXT_OVERRIDE; virtual void *getDriverOptions(void) APPLE_KEXT_OVERRIDE; virtual UInt getLoggingFlags(void) APPLE_KEXT_OVERRIDE; virtual unsigned long getRingEntryMaxTimeMs(void) APPLE_KEXT_OVERRIDE; virtual unsigned long getRingEntrySleepTimeMs(void) APPLE_KEXT_OVERRIDE; virtual CCPipeStatistics *getStatistics(void) APPLE_KEXT_OVERRIDE; virtual void setStatistics(CCPipeStatistics *) APPLE_KEXT_OVERRIDE; virtual void publishStatistics(void) APPLE_KEXT_OVERRIDE; virtual void updateStatistics(bool) APPLE_KEXT_OVERRIDE; virtual IOReturn configureAllReports(void) APPLE_KEXT_OVERRIDE; virtual IOReturn updateAllReports(void) APPLE_KEXT_OVERRIDE; virtual void *createReportSet(void) APPLE_KEXT_OVERRIDE; virtual void log(uint,CCStreamLogLevel,char const*,unsigned long long,bool,bool); virtual void log(uint,char const*,unsigned long long,unsigned long long,unsigned long long); virtual void log(uint,char const*,unsigned long long); virtual bool unmapPipe(void); virtual void setNotifyTimeout(uint); virtual void setWatermarkLevelToNotify(unsigned long); virtual bool getPolicy(CCLogPolicy *); virtual void setPolicy(CCLogPolicy); virtual void setStreamLogFlags(char const*,unsigned long long); virtual void updateStreamLogFlags(char const*,char const*,uint); virtual void setStreamLogLevel(char const*,CCStreamLogLevel); virtual void setStreamConsoleLogFlags(char const*,unsigned long long); virtual void setStreamConsoleLogLevel(char const*,CCStreamLogLevel); virtual void updateStreamConsoleLogFlags(char const*,char const*,uint); virtual IOReturn getUserSpaceNotificationPort(unsigned long long *); virtual void notifyUserSpace(void); virtual bool willDropMessage(uint); virtual char *getScratchBuffer(unsigned long,unsigned long *,uint); virtual void putScratchBuffer(char *,int); virtual void resizeScratchBuffer(char *,unsigned long,unsigned long *); virtual bool reserveRingEntry(unsigned long long,uint,int *); virtual UInt getLogIdentifier(void); virtual void freeResources(void); virtual void notifyTimeout(IOTimerEventSource *); virtual void log(CCStreamLogLevel,char const*,unsigned long long,unsigned long long,CCLogState); virtual bool isValidCCLogMetaData(CCLogMetadata volatile*); virtual bool isValidStreamLogLevel(CCStreamLogLevel); virtual bool isPtrInRing(void *); virtual void addOffset(uint volatile&,unsigned long,unsigned long); virtual UInt calculateFreeBufferLength(uint,uint); virtual void incrementRingPtr(unsigned char volatile*&,unsigned long); virtual void decrementRingPtr(unsigned char volatile*&,unsigned long); virtual void freeLogBuffer(unsigned long); virtual const char *getLogLevelShortName(CCStreamLogLevel); virtual CCLogStream *findStream(char const*); virtual void releaseStream(CCLogStream *); virtual void *findStreamEntry(char const*); virtual bool initScratchBuffers(unsigned long,unsigned long); virtual void freeScratchBuffers(void); public: uint8_t filter[0x98]; }; #endif /* CCLogPipe_h */ ================================================ FILE: include/Airport/CCLogStream.h ================================================ // // CCLogStream.h // itlwm // // Created by qcwap on 2023/6/14. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef CCLogStream_h #define CCLogStream_h #include #include "CCStream.h" enum CCStreamLogLevel { LEVEL_1, }; class CCLogStream : public CCStream { OSDeclareDefaultStructors(CCLogStream) public: virtual void free() APPLE_KEXT_OVERRIDE; virtual bool init(OSDictionary *) APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual bool start(IOService *) APPLE_KEXT_OVERRIDE; virtual void stop(IOService *) APPLE_KEXT_OVERRIDE; virtual bool attach( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual void detach( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual bool profileLoaded(void) APPLE_KEXT_OVERRIDE; virtual bool profileRemoved(void) APPLE_KEXT_OVERRIDE; virtual CCLogStream const *initWithPipeAndName(CCPipe *,char const*,CCStreamOptions const*) APPLE_KEXT_OVERRIDE; virtual void setLevel(CCStreamLogLevel); virtual CCStreamLogLevel getLevel(void); virtual void setFlags(unsigned long long); virtual unsigned long long getFlags(void); virtual void setLogFlag(unsigned long long); virtual void clearLogFlag(unsigned long long); virtual void setConsoleLevel(CCStreamLogLevel); virtual void setConsoleFlags(unsigned long long); virtual unsigned long long getConsoleFlags(void); virtual void setConsoleLogFlag(unsigned long long); virtual void clearConsoleLogFlag(unsigned long long); public: uint8_t filter[0x98]; }; #endif /* CCLogStream_h */ ================================================ FILE: include/Airport/CCPipe.h ================================================ // // CCPipe.h // itlwm // // Created by qcwap on 2023/6/14. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef CCPipe_h #define CCPipe_h #include class CCTimestamp; class CCPipeStatistics; struct CCPipeOptions { uint64_t pipe_type; // 0x0 uint64_t log_data_type; // 0x8 uint64_t pipe_size; // 0x10 uint64_t min_log_size_notify; // 0x18 uint32_t notify_threshold; // 0x20 char file_name[0x100]; // 0x24 char name[0xF0]; // 0x124 char pad8[0x10]; // 0x214 uint32_t pad9; // 0x224 uint32_t pad10; // 0x228 uint64_t file_options; // 0x230 uint64_t log_policy; // 0x238 uint32_t pad13; char directory_name[0x100]; // 0x244 uint8_t pad[0xC]; }; static_assert(offsetof(CCPipeOptions, pipe_size) == 0x10, "Invalid offset"); static_assert(offsetof(CCPipeOptions, file_name) == 0x24, "Invalid offset"); static_assert(offsetof(CCPipeOptions, name) == 0x124, "Invalid offset"); static_assert(offsetof(CCPipeOptions, pad9) == 0x224, "Invalid offset"); static_assert(offsetof(CCPipeOptions, pad10) == 0x228, "Invalid offset"); static_assert(offsetof(CCPipeOptions, file_options) == 0x230, "Invalid offset"); static_assert(offsetof(CCPipeOptions, log_policy) == 0x238, "Invalid offset"); static_assert(offsetof(CCPipeOptions, directory_name) == 0x244, "Invalid offset"); static_assert(sizeof(CCPipeOptions) == 0x350, "Invalid offset"); class CCPipe : public IOService { OSDeclareAbstractStructors(CCPipe) public: virtual void free() APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual void detach( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual IOReturn newUserClient( task_t owningTask, void * securityID, UInt32 type, OSDictionary * properties, LIBKERN_RETURNS_RETAINED IOUserClient ** handler ) = 0; virtual bool clientClose(void) = 0; virtual void *getCoreCapturePipeReporter(void); virtual bool isClientConnected(void) = 0; virtual bool startPipe(void); virtual void stopPipe(void); virtual UInt generateStreamId(void); virtual bool addInitCapture(void); virtual void removeInitCapture(void); virtual void removeCapture(void); virtual bool profileLoaded(void); virtual bool profileRemoved(void); virtual bool capture(CCTimestamp *,char const*) = 0; virtual bool capture(CCTimestamp,char const*) = 0; virtual bool hasPrivilege(void); virtual bool hasPrivilegeAdministrator(task_t); virtual bool initWithOwnerNameCapacity(IOService *,char const*,char const*,CCPipeOptions const*); virtual OSString *getClassName(void); virtual void setCCaptureInRegistry(void); virtual unsigned long getPipeSize(void); virtual void setPipeSize(unsigned long); virtual void freeCCCaptureObject(void); virtual void *getPipeCallbacks(void); virtual IOService *getProvider(void); virtual void *getCurrentOptions(void); virtual void *getDriverOptions(void); virtual UInt getLoggingFlags(void); virtual unsigned long getRingEntryMaxTimeMs(void); virtual unsigned long getRingEntrySleepTimeMs(void); virtual CCPipeStatistics *getStatistics(void); virtual void setStatistics(CCPipeStatistics *); virtual void publishStatistics(void); virtual void updateStatistics(bool); virtual IOReturn configureAllReports(void); virtual IOReturn updateAllReports(void); virtual void *createReportSet(void); public: static CCPipe *withOwnerNameCapacity(IOService *,char const*,char const*,CCPipeOptions const*); public: uint8_t filter[0x90]; }; #endif /* CCPipe_h */ ================================================ FILE: include/Airport/CCStream.h ================================================ // // CCStream.h // itlwm // // Created by qcwap on 2023/6/14. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef CCStream_h #define CCStream_h #include #include "CCPipe.h" struct CCStreamOptions { uint64_t stream_type; uint64_t console_level; char pad[0x348]; }; class CCStream : public IOService { OSDeclareAbstractStructors(CCStream) public: virtual void free() APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual bool attach( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual void detach( IOService * provider ) APPLE_KEXT_OVERRIDE; virtual bool profileLoaded(void); virtual bool profileRemoved(void); virtual CCStream const *initWithPipeAndName(CCPipe *,char const*,CCStreamOptions const*); public: static CCStream *withPipeAndName(CCPipe *,char const*,CCStreamOptions const*); CCPipe *getPipe() const; public: uint8_t filter[0x90]; }; #endif /* CCStream_h */ ================================================ FILE: include/Airport/IO80211Controller.h ================================================ // // IO80211Controller.h // IO80211Family // #ifndef _IO80211CONTROLLER_H #define _IO80211CONTROLLER_H #if defined(KERNEL) && defined(__cplusplus) #include #include // This is necessary, because even the latest Xcode does not support properly targeting 11.0. #ifndef __IO80211_TARGET #error "Please define __IO80211_TARGET to the requested version" #endif #if VERSION_MAJOR > 8 #define _MODERN_BPF #endif #include #include #include #include #include "apple80211_ioctl.h" #include "IO80211WorkLoop.h" #define AUTH_TIMEOUT 15 // seconds /*! @enum LinkSpeed. @abstract ???. @discussion ???. @constant LINK_SPEED_80211A 54 Mbps @constant LINK_SPEED_80211B 11 Mbps. @constant LINK_SPEED_80211G 54 Mbps. */ enum { LINK_SPEED_80211A = 54000000ul, // 54 Mbps LINK_SPEED_80211B = 11000000ul, // 11 Mbps LINK_SPEED_80211G = 54000000ul, // 54 Mbps LINK_SPEED_80211N = 300000000ul, // 300 Mbps (MCS index 15, 400ns GI, 40 MHz channel) }; enum IO80211CountryCodeOp { kIO80211CountryCodeReset, // Reset country code to world wide default, and start // searching for 802.11d beacon }; typedef enum IO80211CountryCodeOp IO80211CountryCodeOp; enum IO80211SystemPowerState { kIO80211SystemPowerStateUnknown, kIO80211SystemPowerStateAwake, kIO80211SystemPowerStateSleeping, }; typedef enum IO80211SystemPowerState IO80211SystemPowerState; enum IO80211FeatureCode { kIO80211Feature80211n = 1, }; typedef enum IO80211FeatureCode IO80211FeatureCode; class IOSkywalkInterface; class IO80211ScanManager; enum CCStreamLogLevel { LEVEL_1, }; enum scanSource { SOURCE_1, }; enum joinStatus { STATUS_1, }; class IO80211SkywalkInterface; class IO80211Controller; class IO80211Interface; class IO82110WorkLoop; class IO80211VirtualInterface; class IO80211ControllerMonitor; class CCLogPipe; class CCIOReporterLogStream; class CCLogStream; class IO80211VirtualInterface; class IO80211RangingManager; class IO80211FlowQueue; class IO80211FlowQueueLegacy; class FlowIdMetadata; class IOReporter; #if __IO80211_TARGET >= __MAC_11_0 class IO80211InfraInterface; #endif extern void IO80211VirtualInterfaceNamerRetain(); struct apple80211_hostap_state; struct apple80211_awdl_sync_channel_sequence; struct ieee80211_ht_capability_ie; struct apple80211_channel_switch_announcement; struct apple80211_beacon_period_data; struct apple80211_power_debug_sub_info; struct apple80211_stat_report; struct apple80211_frame_counters; struct apple80211_leaky_ap_event; struct apple80211_chip_stats; struct apple80211_extended_stats; struct apple80211_ampdu_stat_report; struct apple80211_btCoex_report; struct apple80211_cca_report; class CCPipe; struct apple80211_lteCoex_report; //typedef int scanSource; //typedef int joinStatus; //typedef int CCStreamLogLevel; typedef IOReturn (*IOCTL_FUNC)(IO80211Controller*, IO80211Interface*, IO80211VirtualInterface*, apple80211req*, bool); extern IOCTL_FUNC gGetHandlerTable[]; extern IOCTL_FUNC gSetHandlerTable[]; class IO80211Controller : public IOEthernetController { OSDeclareAbstractStructors(IO80211Controller) public: virtual void free() APPLE_KEXT_OVERRIDE; #if __IO80211_TARGET <= __MAC_10_15 virtual bool terminate(unsigned int) APPLE_KEXT_OVERRIDE; #endif virtual bool init(OSDictionary *) APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual bool start(IOService *) APPLE_KEXT_OVERRIDE; virtual void stop(IOService *) APPLE_KEXT_OVERRIDE; virtual IOService* getProvider(void) const APPLE_KEXT_OVERRIDE; virtual IOWorkLoop* getWorkLoop(void) const APPLE_KEXT_OVERRIDE; virtual const char* stringFromReturn(int) APPLE_KEXT_OVERRIDE; virtual int errnoFromReturn(int) APPLE_KEXT_OVERRIDE; virtual IOOutputQueue* getOutputQueue(void) const APPLE_KEXT_OVERRIDE; virtual bool createWorkLoop(void) APPLE_KEXT_OVERRIDE; virtual IOReturn enable(IONetworkInterface *) APPLE_KEXT_OVERRIDE; virtual IOReturn disable(IONetworkInterface *) APPLE_KEXT_OVERRIDE; virtual bool attachInterface(IONetworkInterface **, bool attach = true) APPLE_KEXT_OVERRIDE; #if __IO80211_TARGET >= __MAC_10_15 virtual void detachInterface(IONetworkInterface *, bool sync = false) APPLE_KEXT_OVERRIDE; #endif virtual IONetworkInterface* createInterface(void) APPLE_KEXT_OVERRIDE; virtual bool configureInterface(IONetworkInterface *) APPLE_KEXT_OVERRIDE; #ifdef __PRIVATE_SPI__ virtual IOReturn outputStart(IONetworkInterface *,UInt) APPLE_KEXT_OVERRIDE; #endif virtual IOReturn getHardwareAddress(IOEthernetAddress *) APPLE_KEXT_OVERRIDE; virtual void requestPacketTx(void*, UInt); virtual IOReturn getHardwareAddressForInterface(IO80211Interface *,IOEthernetAddress *); virtual void inputMonitorPacket(mbuf_t,UInt,void *,unsigned long); virtual int outputRaw80211Packet(IO80211Interface *,mbuf_t); virtual int outputActionFrame(IO80211Interface *,mbuf_t); virtual int bpfOutputPacket(OSObject *,UInt,mbuf_t m); virtual SInt32 monitorModeSetEnabled(IO80211Interface*, bool, UInt); virtual IO80211Interface* getNetworkInterface(void); #if __IO80211_TARGET >= __MAC_10_15 virtual IO80211SkywalkInterface* getPrimarySkywalkInterface(void); #endif virtual SInt32 apple80211_ioctl(IO80211Interface *, IO80211VirtualInterface*, ifnet_t,unsigned long,void *); #if __IO80211_TARGET >= __MAC_10_15 virtual SInt32 apple80211_ioctl(IO80211SkywalkInterface *,unsigned long,void *); #endif virtual SInt32 apple80211_ioctl(IO80211Interface *interface, ifnet_t net,unsigned long id,void *data) { return apple80211_ioctl(interface, NULL, net, id, data); } virtual SInt32 apple80211Request(unsigned int, int, IO80211Interface*, void*) = 0; virtual SInt32 apple80211VirtualRequest(UInt,int,IO80211VirtualInterface *,void *); #if __IO80211_TARGET >= __MAC_10_15 virtual SInt32 apple80211SkywalkRequest(UInt,int,IO80211SkywalkInterface *,void *); #endif virtual SInt32 stopDMA() = 0; virtual UInt32 hardwareOutputQueueDepth(IO80211Interface*) = 0; virtual SInt32 performCountryCodeOperation(IO80211Interface*, IO80211CountryCodeOp) = 0; virtual bool useAppleRSNSupplicant(IO80211Interface *); virtual bool useAppleRSNSupplicant(IO80211VirtualInterface *); virtual void dataLinkLayerAttachComplete(IO80211Interface *); virtual SInt32 enableFeature(IO80211FeatureCode, void*) = 0; virtual SInt32 setVirtualHardwareAddress(IO80211VirtualInterface *,ether_addr *); virtual SInt32 enableVirtualInterface(IO80211VirtualInterface *); virtual SInt32 disableVirtualInterface(IO80211VirtualInterface *); virtual bool requiresExplicitMBufRelease() { return false; } virtual bool flowIdSupported() { return false; } virtual IO80211FlowQueueLegacy* requestFlowQueue(FlowIdMetadata const*); virtual void releaseFlowQueue(IO80211FlowQueue *); #if __IO80211_TARGET >= __MAC_10_15 virtual void getLogPipes(CCPipe**, CCPipe**, CCPipe**) {}; #endif virtual IOReturn enablePacketTimestamping(void) { return kIOReturnUnsupported; } virtual IOReturn disablePacketTimestamping(void) { return kIOReturnUnsupported; } virtual UInt32 selfDiagnosticsReport(int,char const*,UInt); virtual UInt32 getDataQueueDepth(OSObject *); #if __IO80211_TARGET >= __MAC_11_0 virtual bool isAssociatedToMovingNetwork(void) { return false; } #endif virtual mbuf_flags_t inputPacket(mbuf_t); virtual SInt32 apple80211_ioctl_get(IO80211Interface *,IO80211VirtualInterface *,ifnet_t,void *); #if __IO80211_TARGET >= __MAC_10_15 virtual SInt32 apple80211_ioctl_get(IO80211SkywalkInterface *,void *); virtual SInt32 apple80211_ioctl_set(IO80211Interface *,IO80211VirtualInterface *,IO80211SkywalkInterface *,void *); virtual SInt32 apple80211_ioctl_set(IO80211SkywalkInterface *,void*); virtual bool attachInterface(IOSkywalkInterface *,IOService *); #else virtual SInt32 apple80211_ioctl_set(IO80211Interface *,IO80211VirtualInterface *,ifnet_t,void *); #endif #if __IO80211_TARGET >= __MAC_11_0 virtual bool detachInterface(IOSkywalkInterface *, bool); #endif virtual IO80211VirtualInterface* createVirtualInterface(ether_addr *,UInt); virtual bool attachVirtualInterface(IO80211VirtualInterface **,ether_addr *,UInt,bool); virtual bool detachVirtualInterface(IO80211VirtualInterface *,bool); #if __IO80211_TARGET >= __MAC_10_15 virtual IOReturn enable(IO80211SkywalkInterface *); virtual IOReturn disable(IO80211SkywalkInterface *); #endif public: #if __IO80211_TARGET >= __MAC_11_0 void setDisplayState(bool); void resetIO80211ReporterHistory(void); bool markInterfaceUnitUnused(char const*,UInt); bool markInterfaceUnitUsed(char const*,UInt); bool assignUnitNumber(char const*); #endif #if __IO80211_TARGET >= __MAC_10_15 IO80211SkywalkInterface* getInfraInterface(void); IO80211ScanManager* getPrimaryInterfaceScanManager(void); IO80211ControllerMonitor* getInterfaceMonitor(void); #endif IOReturn addReporterLegend(IOService *,IOReporter *,char const*,char const*); IOReturn removeReporterFromLegend(IOService *,IOReporter *,char const*,char const*); IOReturn unlockIOReporterLegend(void); void lockIOReporterLegend(void);// Suspected return type - int IOReturn logIOReportLogStreamSubscription(unsigned long long); IOReturn addIOReportLogStreamForProvider(IOService *,unsigned long long *); IOReturn addSubscriptionForThisReporterFetchedOnTimer(IOReporter *,char const*,char const*,IOService *) ; IOReturn addSubscriptionForProviderFetchedOnTimer(IOService *); void handleIOReporterTimer(IOTimerEventSource *); void setIOReportersStreamFlags(unsigned long long); void updateIOReportersStreamFrequency(void); // Suspected return type - int void setIOReportersStreamLevel(CCStreamLogLevel); void powerChangeGated(OSObject *,void *,void *,void *,void *); int copyOut(void const*,unsigned long long,unsigned long); #if __IO80211_TARGET >= __MAC_11_0 SInt32 getASSOCIATE_EXTENDED_RESULT(IO80211Interface *,IO80211VirtualInterface *,IO80211InfraInterface *,apple80211_assoc_result_data *); #endif SInt32 getASSOCIATE_RESULT(IO80211Interface *,IO80211VirtualInterface *,IO80211SkywalkInterface *,apple80211_assoc_result_data *); IOReturn copyIn(unsigned long long,void *,unsigned long); void logIOCTL(apple80211req *); bool isIOCTLLoggingRestricted(apple80211req *); IOReturn setChanNoiseFloorLTE(apple80211_stat_report *,int); IOReturn setChanNoiseFloor(apple80211_stat_report *,int); IOReturn setChanCCA(apple80211_stat_report *,int); IOReturn setChanExtendedCCA(apple80211_stat_report *,apple80211_cca_report *); bool setLTECoexstat(apple80211_stat_report *,apple80211_lteCoex_report *); bool setBTCoexstat(apple80211_stat_report *,apple80211_btCoex_report *); bool setAMPDUstat(apple80211_stat_report *,apple80211_ampdu_stat_report *,apple80211_channel *); UInt32 getCountryCode(apple80211_country_code_data *); IOReturn setCountryCode(apple80211_country_code_data *); bool getInfraExtendedStats(apple80211_extended_stats *); bool getChipCounterStats(apple80211_chip_stats *); #if __IO80211_TARGET >= __MAC_10_15 bool setExtendedChipCounterStats(apple80211_stat_report *,void *); #endif bool setChipCounterStats(apple80211_stat_report *,apple80211_chip_stats *,apple80211_channel *); bool setLeakyAPStats(apple80211_leaky_ap_event *); bool setFrameStats(apple80211_stat_report *,apple80211_frame_counters *,apple80211_channel *); bool setPowerStats(apple80211_stat_report *,apple80211_power_debug_sub_info *); bool getBeaconPeriod(apple80211_beacon_period_data *); SInt32 apple80211VirtualRequestIoctl(unsigned int,int,IO80211VirtualInterface *,void *); bool getBSSIDData(OSObject *,apple80211_bssid_data *); bool getSSIDData(apple80211_ssid_data *); bool inputInfraPacket(mbuf_t); #if __IO80211_TARGET >= __MAC_10_15 void notifyHostapState(apple80211_hostap_state *); #endif bool isAwdlAssistedDiscoveryEnabled(void); void joinDone(scanSource,joinStatus); void joinStarted(scanSource,joinStatus); void handleChannelSwitchAnnouncement(apple80211_channel_switch_announcement *); void scanDone(scanSource,int); void scanStarted(scanSource,apple80211_scan_data *); void printChannels(void); #if __IO80211_TARGET >= __MAC_10_15 void updateInterfaceCoexRiskPct(unsigned long long); #endif SInt32 getInfraChannel(apple80211_channel_data *); void calculateInterfacesAvaiability(void); // Suspected return type - int void setChannelSequenceList(apple80211_awdl_sync_channel_sequence *); // Suspected return type - int #if __IO80211_TARGET >= __MAC_10_15 void setPrimaryInterfaceDatapathState(bool); UInt32 getPrimaryInterfaceLinkState(void); #endif void setCurrentChannel(apple80211_channel *); // Suspected return type - int void setHtCapability(ieee80211_ht_capability_ie *); UInt32 getHtCapability(void); UInt32 getHtCapabilityLength(void); bool io80211isDebuggable(bool* enable); void logDebug(unsigned long long,char const*,...); // Suspected return type - int void vlogDebug(unsigned long long,char const*,va_list); // Suspected return type - char void logDebug(char const*,...); // Suspected return type - int bool calculateInterfacesCoex(void); void setInfraChannel(apple80211_channel *); #if __IO80211_TARGET >= __MAC_10_15 void configureAntennae(void); #endif SInt32 apple80211RequestIoctl(unsigned int,int,IO80211Interface *,void *); UInt32 radioCountForInterface(IO80211Interface *); void releaseIOReporters(void); #if __IO80211_TARGET >= __MAC_10_15 bool findAndAttachToFaultReporter(void); #endif UInt32 setupControlPathLogging(void); IOReturn createIOReporters(IOService *); IOReturn powerChangeHandler(void *,void *,unsigned int,IOService *,void *,unsigned long); OSMetaClassDeclareReservedUnused( IO80211Controller, 0); OSMetaClassDeclareReservedUnused( IO80211Controller, 1); OSMetaClassDeclareReservedUnused( IO80211Controller, 2); OSMetaClassDeclareReservedUnused( IO80211Controller, 3); OSMetaClassDeclareReservedUnused( IO80211Controller, 4); OSMetaClassDeclareReservedUnused( IO80211Controller, 5); OSMetaClassDeclareReservedUnused( IO80211Controller, 6); OSMetaClassDeclareReservedUnused( IO80211Controller, 7); OSMetaClassDeclareReservedUnused( IO80211Controller, 8); OSMetaClassDeclareReservedUnused( IO80211Controller, 9); OSMetaClassDeclareReservedUnused( IO80211Controller, 10); OSMetaClassDeclareReservedUnused( IO80211Controller, 11); OSMetaClassDeclareReservedUnused( IO80211Controller, 12); OSMetaClassDeclareReservedUnused( IO80211Controller, 13); OSMetaClassDeclareReservedUnused( IO80211Controller, 14); OSMetaClassDeclareReservedUnused( IO80211Controller, 15); protected: uint8_t filler[0x500]; }; // 0x215: 1 byte, length of channel sequence, should be 16 // 0x21c: channel sequence, should contain 16 elements of length 12, possibly apple80211_channel (but why 16?) // struct of three ints, last looks like flags, first unused /* void __thiscall setChannelSequenceList(IO80211Controller *this,apple80211_awdl_sync_channel_sequence *param_1) { _memcpy(this + 0x210,param_1,400); calculateInterfacesAvaiability(this); return; } */ #endif /* defined(KERNEL) && defined(__cplusplus) */ #endif /* !_IO80211CONTROLLER_H */ ================================================ FILE: include/Airport/IO80211ControllerV2.h ================================================ // // IOSkywalkInterface.h // itlwm // // Created by qcwap on 2023/6/7. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef _IO80211CONTROLLER_H #define _IO80211CONTROLLER_H #if defined(KERNEL) && defined(__cplusplus) #include #include // This is necessary, because even the latest Xcode does not support properly targeting 11.0. #ifndef __IO80211_TARGET #error "Please define __IO80211_TARGET to the requested version" #endif #if VERSION_MAJOR > 8 #define _MODERN_BPF #endif #include #include #include #include #include "apple80211_ioctl.h" #include "IO80211SkywalkInterface.h" #include "IO80211WorkLoop.h" #include "IO80211WorkQueue.h" #include "CCStream.h" #include "CCDataPipe.h" #include "CCLogPipe.h" #include "CCLogStream.h" #define AUTH_TIMEOUT 15 // seconds /*! @enum LinkSpeed. @abstract ???. @discussion ???. @constant LINK_SPEED_80211A 54 Mbps @constant LINK_SPEED_80211B 11 Mbps. @constant LINK_SPEED_80211G 54 Mbps. */ enum { LINK_SPEED_80211A = 54000000ul, // 54 Mbps LINK_SPEED_80211B = 11000000ul, // 11 Mbps LINK_SPEED_80211G = 54000000ul, // 54 Mbps LINK_SPEED_80211N = 300000000ul, // 300 Mbps (MCS index 15, 400ns GI, 40 MHz channel) }; enum IO80211CountryCodeOp { kIO80211CountryCodeReset, // Reset country code to world wide default, and start // searching for 802.11d beacon }; typedef enum IO80211CountryCodeOp IO80211CountryCodeOp; enum IO80211SystemPowerState { kIO80211SystemPowerStateUnknown, kIO80211SystemPowerStateAwake, kIO80211SystemPowerStateSleeping, }; typedef enum IO80211SystemPowerState IO80211SystemPowerState; enum IO80211FeatureCode { kIO80211Feature80211n = 1, }; typedef enum IO80211FeatureCode IO80211FeatureCode; class IOSkywalkInterface; class IO80211ScanManager; enum scanSource { SOURCE_1, }; enum joinStatus { STATUS_1, }; class IO80211Controller; class IO80211Interface; class IO82110WorkLoop; class IO80211VirtualInterface; class IO80211ControllerMonitor; class CCLogPipe; class CCIOReporterLogStream; class CCLogStream; class IO80211VirtualInterface; class IO80211RangingManager; class IO80211FlowQueue; class IO80211FlowQueueLegacy; class FlowIdMetadata; class IOReporter; class IO80211InfraInterface; extern void IO80211VirtualInterfaceNamerRetain(); struct apple80211_hostap_state; struct apple80211_awdl_sync_channel_sequence; struct ieee80211_ht_capability_ie; struct apple80211_channel_switch_announcement; struct apple80211_beacon_period_data; struct apple80211_power_debug_sub_info; struct apple80211_stat_report; struct apple80211_frame_counters; struct apple80211_leaky_ap_event; struct apple80211_chip_stats; struct apple80211_extended_stats; struct apple80211_ampdu_stat_report; struct apple80211_btCoex_report; struct apple80211_cca_report; class CCPipe; struct apple80211_lteCoex_report; //typedef int scanSource; //typedef int joinStatus; //typedef int CCStreamLogLevel; typedef IOReturn (*IOCTL_FUNC)(IO80211Controller*, IO80211Interface*, IO80211VirtualInterface*, apple80211req*, bool); extern IOCTL_FUNC gGetHandlerTable[]; extern IOCTL_FUNC gSetHandlerTable[]; class IO80211InterfaceAVCAdvisory; class IO80211Controller : public IOEthernetController { OSDeclareAbstractStructors(IO80211Controller) public: virtual void free() APPLE_KEXT_OVERRIDE; virtual bool init(OSDictionary *) APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual bool start(IOService *) APPLE_KEXT_OVERRIDE; virtual void stop(IOService *) APPLE_KEXT_OVERRIDE; virtual IOWorkLoop* getWorkLoop(void) const APPLE_KEXT_OVERRIDE; virtual const char* stringFromReturn(int) APPLE_KEXT_OVERRIDE; virtual int errnoFromReturn(int) APPLE_KEXT_OVERRIDE; virtual UInt32 getFeatures() const APPLE_KEXT_OVERRIDE; virtual const OSString * newVendorString() const APPLE_KEXT_OVERRIDE; virtual const OSString * newModelString() const APPLE_KEXT_OVERRIDE; virtual bool createWorkLoop() APPLE_KEXT_OVERRIDE; virtual IOReturn getHardwareAddress(IOEthernetAddress *) APPLE_KEXT_OVERRIDE; virtual IOReturn setHardwareAddress(const IOEthernetAddress * addrP) APPLE_KEXT_OVERRIDE; virtual IOReturn setMulticastMode(bool active) APPLE_KEXT_OVERRIDE; virtual IOReturn setPromiscuousMode(bool active) APPLE_KEXT_OVERRIDE; virtual bool isCommandProhibited(int) = 0; virtual bool createWorkQueue(); virtual IO80211WorkQueue *getWorkQueue(); virtual void requestPacketTx(void*, UInt); virtual IOCommandGate *getIO80211CommandGate(); virtual IOReturn getHardwareAddressForInterface(IOEthernetAddress *); virtual bool useAppleRSNSupplicant(IO80211VirtualInterface *); virtual IO80211SkywalkInterface* getPrimarySkywalkInterface(void); virtual int bpfOutputPacket(OSObject *,UInt,mbuf_t m); virtual SInt32 monitorModeSetEnabled(bool, UInt); virtual SInt32 apple80211_ioctl(IO80211SkywalkInterface *,unsigned long,void *, bool, bool); virtual SInt32 apple80211VirtualRequest(UInt,int,IO80211VirtualInterface *,void *); virtual SInt32 apple80211SkywalkRequest(UInt,int,IO80211SkywalkInterface *,void *); virtual SInt32 apple80211SkywalkRequest(UInt,int,IO80211SkywalkInterface *,void *,void *); virtual SInt32 handleCardSpecific(IO80211SkywalkInterface *,unsigned long,void *,bool) = 0; virtual UInt32 hardwareOutputQueueDepth(); virtual SInt32 performCountryCodeOperation(IO80211CountryCodeOp); virtual void dataLinkLayerAttachComplete(); virtual SInt32 enableFeature(IO80211FeatureCode, void*) = 0; virtual IOReturn getDRIVER_VERSION(IO80211SkywalkInterface *,apple80211_version_data *) = 0; virtual IOReturn getHARDWARE_VERSION(IO80211SkywalkInterface *,apple80211_version_data *) = 0; virtual IOReturn getCARD_CAPABILITIES(IO80211SkywalkInterface *,apple80211_capability_data *) = 0; virtual IOReturn getPOWER(IO80211SkywalkInterface *,apple80211_power_data *) = 0; virtual IOReturn setPOWER(IO80211SkywalkInterface *,apple80211_power_data *) = 0; virtual IOReturn getCOUNTRY_CODE(IO80211SkywalkInterface *,apple80211_country_code_data *) = 0; virtual IOReturn setCOUNTRY_CODE(IO80211SkywalkInterface *,apple80211_country_code_data *) = 0; virtual IOReturn setGET_DEBUG_INFO(IO80211SkywalkInterface *,apple80211_debug_command *) = 0; virtual SInt32 setVirtualHardwareAddress(IO80211VirtualInterface *,ether_addr *); virtual SInt32 enableVirtualInterface(IO80211VirtualInterface *); virtual SInt32 disableVirtualInterface(IO80211VirtualInterface *); virtual bool requiresExplicitMBufRelease(); virtual bool flowIdSupported() { return false; } virtual IO80211FlowQueueLegacy* requestFlowQueue(FlowIdMetadata const*); virtual void releaseFlowQueue(IO80211FlowQueue *); virtual bool getLogPipes(CCPipe**, CCPipe**, CCPipe**); virtual void enableFeatureForLoggingFlags(unsigned long long) {}; virtual IOReturn requestQueueSizeAndTimeout(unsigned short *, unsigned short *) { return kIOReturnIOError; }; virtual IOReturn enablePacketTimestamping(void) { return kIOReturnUnsupported; } virtual IOReturn disablePacketTimestamping(void) { return kIOReturnUnsupported; } virtual UInt getPacketTSCounter(); virtual void *getDriverTextLog(); virtual UInt32 selfDiagnosticsReport(int,char const*,UInt); virtual void *getFaultReporterFromDriver(); virtual UInt32 getDataQueueDepth(OSObject *); virtual bool isAssociatedToMovingNetwork(void) { return false; } virtual bool wasDynSARInFailSafeMode(void) { return false; } virtual void updateAdvisoryScoresIfNeed(void); virtual UInt64 getAVCAdvisoryInfo(IO80211InterfaceAVCAdvisory *); virtual SInt32 apple80211_ioctl_get(IO80211SkywalkInterface *,void *, bool, bool); virtual SInt32 apple80211_ioctl_set(IO80211SkywalkInterface *,void *, bool, bool); virtual bool attachInterface(OSObject *,IOService *); virtual SInt32 apple80211_ioctl_get(IO80211VirtualInterface *,void *,bool,bool); virtual SInt32 apple80211_ioctl_set(IO80211VirtualInterface *,void *,bool,bool); virtual void detachInterface(OSObject *,bool); virtual IO80211VirtualInterface* createVirtualInterface(ether_addr *,UInt); virtual bool attachVirtualInterface(IO80211VirtualInterface **,ether_addr *,UInt,bool); virtual bool detachVirtualInterface(IO80211VirtualInterface *,bool); virtual IOReturn enable(IO80211SkywalkInterface *); virtual IOReturn disable(IO80211SkywalkInterface *); OSMetaClassDeclareReservedUnused( IO80211Controller, 0); OSMetaClassDeclareReservedUnused( IO80211Controller, 1); OSMetaClassDeclareReservedUnused( IO80211Controller, 2); OSMetaClassDeclareReservedUnused( IO80211Controller, 3); OSMetaClassDeclareReservedUnused( IO80211Controller, 4); OSMetaClassDeclareReservedUnused( IO80211Controller, 5); OSMetaClassDeclareReservedUnused( IO80211Controller, 6); OSMetaClassDeclareReservedUnused( IO80211Controller, 7); OSMetaClassDeclareReservedUnused( IO80211Controller, 8); OSMetaClassDeclareReservedUnused( IO80211Controller, 9); OSMetaClassDeclareReservedUnused( IO80211Controller, 10); OSMetaClassDeclareReservedUnused( IO80211Controller, 11); OSMetaClassDeclareReservedUnused( IO80211Controller, 12); OSMetaClassDeclareReservedUnused( IO80211Controller, 13); OSMetaClassDeclareReservedUnused( IO80211Controller, 14); OSMetaClassDeclareReservedUnused( IO80211Controller, 15); virtual void postMessage(UInt,void *,unsigned long,UInt,void *); virtual IOReturn setMulticastList(ether_addr const*, UInt); protected: uint8_t filler[0x128]; }; #endif /* defined(KERNEL) && defined(__cplusplus) */ #endif /* !_IO80211CONTROLLER_H */ ================================================ FILE: include/Airport/IO80211InfraInterface.h ================================================ // // IO80211InfraInterface.h // itlwm // // Created by qcwap on 2023/6/12. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef IO80211InfraInterface_h #define IO80211InfraInterface_h struct apple80211_wcl_advisory_info; struct apple80211_wcl_tx_rx_latency; class IO80211InfraInterface : public IO80211SkywalkInterface { OSDeclareAbstractStructors(IO80211InfraInterface) public: virtual bool init() APPLE_KEXT_OVERRIDE; virtual void free() APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual bool start(IOService *) APPLE_KEXT_OVERRIDE; virtual SInt32 initBSDInterfaceParameters(ifnet_init_eparams *,sockaddr_dl **) APPLE_KEXT_OVERRIDE; virtual bool prepareBSDInterface(ifnet_t, UInt) APPLE_KEXT_OVERRIDE; virtual IOReturn processBSDCommand(ifnet_t, UInt, void *) APPLE_KEXT_OVERRIDE; virtual SInt32 setInterfaceEnable(bool) APPLE_KEXT_OVERRIDE; virtual UInt getHardwareAssists(void) APPLE_KEXT_OVERRIDE; virtual bool bpfTap(UInt,UInt) APPLE_KEXT_OVERRIDE; virtual void getHardwareAddress(ether_addr *) APPLE_KEXT_OVERRIDE; virtual void setHardwareAddress(ether_addr *) APPLE_KEXT_OVERRIDE; virtual void postMessage(UInt,void *,unsigned long,bool) APPLE_KEXT_OVERRIDE; virtual IOReturn recordOutputPackets(TxSubmissionDequeueStats *,TxSubmissionDequeueStats *) APPLE_KEXT_OVERRIDE; virtual void logTxPacket(IO80211NetworkPacket *,PacketSkywalkScratch *,apple80211_wme_ac,bool) APPLE_KEXT_OVERRIDE; virtual void logTxCompletionPacket(IO80211NetworkPacket *,PacketSkywalkScratch *,unsigned char *,apple80211_wme_ac,int,UInt,bool) APPLE_KEXT_OVERRIDE; virtual IOReturn recordCompletionPackets(TxCompletionEnqueueStats *,TxCompletionEnqueueStats *) APPLE_KEXT_OVERRIDE; virtual IOReturn inputPacket(IO80211NetworkPacket *,packet_info_tag *,ether_header *,bool *) APPLE_KEXT_OVERRIDE; virtual SInt64 pendingPackets(unsigned char) APPLE_KEXT_OVERRIDE; virtual SInt64 packetSpace(unsigned char) APPLE_KEXT_OVERRIDE; virtual bool isDebounceOnGoing(void) APPLE_KEXT_OVERRIDE; virtual bool setLinkState(IO80211LinkState,UInt,bool debounceTimeout = 30,UInt code = 0) APPLE_KEXT_OVERRIDE; virtual IO80211LinkState linkState(void) APPLE_KEXT_OVERRIDE; virtual void setScanningState(UInt,bool,apple80211_scan_data *,int) APPLE_KEXT_OVERRIDE; virtual void setDataPathState(bool) APPLE_KEXT_OVERRIDE; virtual void *getScanManager(void) APPLE_KEXT_OVERRIDE; virtual void updateLinkParameters(apple80211_interface_availability *) APPLE_KEXT_OVERRIDE; virtual void updateInterfaceCoexRiskPct(unsigned long long) APPLE_KEXT_OVERRIDE; virtual void setLQM(unsigned long long) APPLE_KEXT_OVERRIDE; virtual void updateLinkStatus(void) APPLE_KEXT_OVERRIDE; virtual void updateLinkStatusGated(void) APPLE_KEXT_OVERRIDE; virtual void setInterfaceExtendedCCA(apple80211_channel,apple80211_cca_report *) APPLE_KEXT_OVERRIDE; virtual void setInterfaceCCA(apple80211_channel,int) APPLE_KEXT_OVERRIDE; virtual void setInterfaceNF(apple80211_channel,long long) APPLE_KEXT_OVERRIDE; virtual void setInterfaceOFDMDesense(apple80211_channel,long long) APPLE_KEXT_OVERRIDE; virtual void setDebugFlags(unsigned long long,UInt) APPLE_KEXT_OVERRIDE; virtual SInt64 debugFlags(void) APPLE_KEXT_OVERRIDE; virtual void setInterfaceChipCounters(apple80211_stat_report *,apple80211_chip_counters_tx *,apple80211_chip_error_counters_tx *,apple80211_chip_counters_rx *) APPLE_KEXT_OVERRIDE; virtual void setInterfaceMIBdot11(apple80211_stat_report *,apple80211_ManagementInformationBasedot11_counters *) APPLE_KEXT_OVERRIDE; virtual void setFrameStats(apple80211_stat_report *,apple80211_frame_counters *) APPLE_KEXT_OVERRIDE; #if __IO80211_TARGET >= __MAC_14_4 virtual void setInfraSpecificFrameStats(apple80211_stat_report *,apple80211_infra_specific_stats *) APPLE_KEXT_OVERRIDE; #endif virtual SInt64 getWmeTxCounters(unsigned long long *) APPLE_KEXT_OVERRIDE; virtual void setEnabledBySystem(bool) APPLE_KEXT_OVERRIDE; virtual bool enabledBySystem(void) APPLE_KEXT_OVERRIDE; virtual bool willRoam(ether_addr *,UInt) APPLE_KEXT_OVERRIDE; virtual void setPeerManagerLogFlag(UInt,UInt,UInt) APPLE_KEXT_OVERRIDE; virtual void setWoWEnabled(bool) APPLE_KEXT_OVERRIDE; virtual bool wowEnabled(void) APPLE_KEXT_OVERRIDE; virtual UInt64 createLinkQualityMonitor(IO80211Peer *,IOService *) APPLE_KEXT_OVERRIDE; virtual void releaseLinkQualityMonitor(IO80211Peer *) APPLE_KEXT_OVERRIDE; virtual int getAssocState(void) APPLE_KEXT_OVERRIDE; virtual void *getLQMSummary(apple80211_lqm_summary *) APPLE_KEXT_OVERRIDE; virtual IOReturn setLinkStateInternal(IO80211LinkState,uint,bool,uint,apple80211_link_changed_event_data &); virtual void setPoweredOnByUser(bool); virtual void setCurrentBssid(ether_addr *); virtual void setWCL_ADVISORTY_INFO(apple80211_wcl_advisory_info *); virtual void *getWCL_TX_RX_LATENCY(apple80211_wcl_tx_rx_latency *); public: char _data[0x120]; }; #endif /* IO80211InfraInterface_h */ ================================================ FILE: include/Airport/IO80211InfraProtocol.h ================================================ // // IO80211InfraProtocol.h // itlwm // // Created by qcwap on 2023/6/14. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef IO80211InfraProtocol_h #define IO80211InfraProtocol_h #include #include #include struct apple80211_sta_ie_data; struct apple80211_sta_stats_data; struct apple80211_rssi_bounds_data; struct apple80211_rate_set_data; struct apple80211_power_debug_info; struct apple80211_bgscan_cached_network_data_list; struct apple80211_private_mac_data; struct apple80211_dbg_guard_time_params; struct apple80211_ranging_enable_request_t; struct apple80211_gas_result_t; struct apple80211_ranging_start_request_t; struct apple80211_leaky_ap_setting; struct apple80211_rsdb_capability; struct apple80211_tko_params; struct apple80211_tko_dump; struct apple80211_thermal_index_t; struct apple80211_btcoex_max_nss_for_ap_data; struct apple80211_btcoex_2g_chain_disable; struct apple80211_power_budget_t; struct apple80211_ranging_capabilities_t; struct apple80211_suppress_scans_t; struct apple80211_host_ap_mode_hidden_t; struct apple80211_lqm_config_t; struct apple80211_trap_mini_dump_data; struct apple80211_beacon_info_t; struct apple80211_softap_params; struct apple80211_chip_power_limit; struct apple80211_softap_stats; struct apple80211_nss_data; struct apple80211_hw_mac_address; struct apple80211_he_mcs_index_set_data; struct appl80211_chip_diags_data; struct apple80211_hp2p_ctrl; struct apple80211_assoc_ready; struct apple80211_txrx_chain_info; struct apple80211_mimo_status; struct apple80211_dynsar_detail; struct apple80211_mac_randomisation_status; struct apple80211_colocated_network_scope_id { uint32_t version; uint32_t id1; uint32_t id2; }; struct apple80211_slow_wifi_feature_enabled; struct apple80211_interface_cca_data; struct apple80211_timesync_info; struct apple80211_sensing_data_t; struct apple80211_country_band_support; struct apple80211_fw_hot_channels; struct apple80211_low_latency_info; struct apple80211_beacon_msg; struct apple80211_wcl_traffic_counters; struct apple80211_ssid_transition_feature_enabled; typedef enum { } p2pStatusForScan; struct apple80211ChannelInfo; struct apple80211_p2p_steering_metrics;; struct apple80211_rsn_xe_data; struct apple80211_sib_coex_status; struct apple80211_extended_bss_info; struct apple80211_wcl_low_latency_stats; struct apple80211_noise_per_ant_t; struct apple80211_blocked_bands; struct apple80211_disassoc_data; struct apple80211_bgscan_data; struct apple80211_sta_authorize_data; struct apple80211_sta_disassoc_data; struct apple80211_rsn_conf_data; struct apple80211_country_channel_data; struct apple80211_awdl_forced_roam_config; struct apple80211_offload_arp_data; struct apple80211_offload_ndp_data; struct apple80211_offload_scan_data; struct apple80211_gas_query_t; struct apple80211_gas_peer_t; struct apple80211_btcoex_profile; struct apple80211_btcoex_profile_active_data; struct apple80211_trap_info_data; struct apple80211_he_capability; struct apple80211_pmk; struct apple80211_wow_test_data; struct apple80211_reset_command; struct apple80211_crash_command; struct apple80211_ranging_authenticate_request_t; struct apple80211_softap_csa_params; struct apple80211_softap_wifi_network_info; struct apple80211_scan_control_params; struct apple80211_usb_host_notification_data; struct apple80211_set_mac_address; struct apple80211_abort_scan; struct apple80211_set_property_unserialized_data; struct apple80211_roam_cache_data; struct apple80211_pm_mode; struct apple80211_wifi_assertion_data; struct apple80211_capture_debug_info_t; struct apple80211_linkdown_debounce_status; struct apple80211_softap_extended_capabilities_info; struct apple80211_sensing_enable_t; struct apple80211_sensing_disable_t; struct apple80211_nan_link_association_info; struct apple80211_6G_mode; struct apple80211_leave_network; struct apple80211_reassoc; struct apple80211_set_roam_lock; struct apple80211_roam_profile_config; struct apple80211_roam_profile_configV1; struct apple80211_user_roam_cache; struct apple80211_set_multi_ap_env; struct apple80211_wcl_real_time_mode; struct apple80211_wcl_garp_mode; struct triggerCC; struct apple80211ScanRequest; struct apple80211_assoc_candidates; struct apple80211_wcl_protect_ip_mode; struct scanHomeAndAwayTime; struct apple80211_wcl_voluntary_network_disconnect; struct apple80211_wcl_update_link_state; struct apple80211_wcl_ulofdma_state; struct apple80211_wcl_action_frame; struct apple80211_wcl_real_time_policy; struct apple80211_feature_flags; struct apple80211_dhcp_renewal_data; struct apple80211_network_flags; struct apple80211_battery_ps_config; struct apple80211_mimo_config; struct apple80211_bg_motion_profile; struct apple80211_bg_network; struct apple80211_bg_scan; struct apple80211_bg_params; typedef UInt apple80211_offload_tcpka_enable_t; class IO80211InfraProtocol : public IO80211InfraInterface { OSDeclareAbstractStructors(IO80211InfraProtocol) public: virtual IOReturn getSSID(apple80211_ssid_data *) = 0; virtual IOReturn getAUTH_TYPE(apple80211_authtype_data *) = 0; virtual IOReturn getCHANNEL(apple80211_channel_data *) = 0; virtual IOReturn getPOWERSAVE(apple80211_powersave_data *) = 0; virtual IOReturn getTXPOWER(apple80211_txpower_data *) = 0; virtual IOReturn getRATE(apple80211_rate_data *) = 0; virtual IOReturn getBSSID(apple80211_bssid_data *) = 0; virtual IOReturn getSCAN_RESULT(apple80211_scan_result *) = 0; virtual IOReturn getSTATE(apple80211_state_data *) = 0; virtual IOReturn getPHY_MODE(apple80211_phymode_data *) = 0; virtual IOReturn getOP_MODE(apple80211_opmode_data *) = 0; virtual IOReturn getRSSI(apple80211_rssi_data *) = 0; virtual IOReturn getNOISE(apple80211_noise_data *) = 0; virtual IOReturn getSUPPORTED_CHANNELS(apple80211_sup_channel_data *) = 0; virtual IOReturn getLOCALE(apple80211_locale_data *) = 0; virtual IOReturn getDEAUTH(apple80211_deauth_data *) = 0; virtual IOReturn getRATE_SET(apple80211_rate_set_data *) = 0; virtual IOReturn getDTIM_INT(apple80211_dtim_int_data *) = 0; virtual IOReturn getSTATION_LIST(apple80211_sta_data *) = 0; virtual IOReturn getRSN_IE(apple80211_rsn_ie_data *) = 0; virtual IOReturn getAP_IE_LIST(apple80211_ap_ie_data *) = 0; virtual IOReturn getSTATS(apple80211_stats_data *) = 0; virtual IOReturn getASSOCIATION_STATUS(apple80211_assoc_status_data *) = 0; virtual IOReturn getGUARD_INTERVAL(apple80211_guard_interval_data *) = 0; virtual IOReturn getMCS(apple80211_mcs_data *) = 0; virtual IOReturn getMCS_INDEX_SET(apple80211_mcs_index_set_data *) = 0; virtual IOReturn getWOW_PARAMETERS(apple80211_wow_parameter_data *) = 0; virtual IOReturn getWOW_ENABLED(apple80211_state_data *) = 0; virtual IOReturn getPID_LOCK(apple80211_state_data *) = 0; virtual IOReturn getSTA_IE_LIST(apple80211_sta_ie_data *) = 0; virtual IOReturn getSTA_STATS(apple80211_sta_stats_data *) = 0; virtual IOReturn getBT_COEX_FLAGS(apple80211_state_data *) = 0; virtual IOReturn getCURRENT_NETWORK(apple80211_scan_result *) = 0; virtual IOReturn getRSSI_BOUNDS(apple80211_rssi_bounds_data *) = 0; virtual IOReturn getPOWER_DEBUG_INFO(apple80211_power_debug_info *) = 0; virtual IOReturn getHT_CAPABILITY(apple80211_ht_capability *) = 0; virtual IOReturn getLINK_CHANGED_EVENT_DATA(apple80211_link_changed_event_data *) = 0; virtual IOReturn getEXTENDED_STATS(apple80211_extended_stats *) = 0; virtual IOReturn getBEACON_PERIOD(apple80211_beacon_period_data *) = 0; virtual IOReturn getVHT_MCS_INDEX_SET(apple80211_vht_mcs_index_set_data *) = 0; virtual IOReturn getMCS_VHT(apple80211_mcs_vht_data *) = 0; virtual IOReturn getGAS_RESULTS(apple80211_gas_result_t *) = 0; virtual IOReturn getCHANNELS_INFO(apple80211_channels_info *) = 0; virtual IOReturn getVHT_CAPABILITY(apple80211_vht_capability *) = 0; virtual IOReturn getBGSCAN_CACHE_RESULTS(apple80211_bgscan_cached_network_data_list *) = 0; virtual IOReturn getROAM_PROFILE(apple80211_roam_profile_band_data *) = 0; virtual IOReturn getCHIP_COUNTER_STATS(apple80211_chip_stats *) = 0; virtual IOReturn getDBG_GUARD_TIME_PARAMS(apple80211_dbg_guard_time_params *) = 0; virtual IOReturn getLEAKY_AP_STATS_MODE(apple80211_leaky_ap_setting *) = 0; virtual IOReturn getCOUNTRY_CHANNELS(apple80211_country_channel_data *) = 0; virtual IOReturn getPRIVATE_MAC(apple80211_private_mac_data *) = 0; virtual IOReturn getRANGING_ENABLE(apple80211_ranging_enable_request_t *) = 0; virtual IOReturn getRANGING_START(apple80211_ranging_start_request_t *) = 0; virtual IOReturn getAWDL_RSDB_CAPS(apple80211_rsdb_capability *) = 0; virtual IOReturn getTKO_PARAMS(apple80211_tko_params *) = 0; virtual IOReturn getTKO_DUMP(apple80211_tko_dump *) = 0; virtual IOReturn getHW_SUPPORTED_CHANNELS(apple80211_sup_channel_data *) = 0; virtual IOReturn getBTCOEX_PROFILE(apple80211_btcoex_profile *) = 0; virtual IOReturn getBTCOEX_PROFILE_ACTIVE(apple80211_btcoex_profile_active_data *) = 0; virtual IOReturn getTRAP_INFO(apple80211_trap_info_data *) = 0; virtual IOReturn getTHERMAL_INDEX(apple80211_thermal_index_t *) = 0; virtual IOReturn getMAX_NSS_FOR_AP(apple80211_btcoex_max_nss_for_ap_data *) = 0; virtual IOReturn getBTCOEX_2G_CHAIN_DISABLE(apple80211_btcoex_2g_chain_disable *) = 0; virtual IOReturn getPOWER_BUDGET(apple80211_power_budget_t *) = 0; virtual IOReturn getOFFLOAD_TCPKA_ENABLE(apple80211_offload_tcpka_enable_t *) = 0; virtual IOReturn getRANGING_CAPS(apple80211_ranging_capabilities_t *) = 0; virtual IOReturn getSUPPRESS_SCANS(apple80211_suppress_scans_t *) = 0; virtual IOReturn getHOST_AP_MODE_HIDDEN(apple80211_host_ap_mode_hidden_t *) = 0; virtual IOReturn getLQM_CONFIG(apple80211_lqm_config_t *) = 0; virtual IOReturn getTRAP_CRASHTRACER_MINI_DUMP(apple80211_trap_mini_dump_data *) = 0; virtual IOReturn getHE_CAPABILITY(apple80211_he_capability *) = 0; virtual IOReturn getBEACON_INFO(apple80211_beacon_info_t *) = 0; virtual IOReturn getSOFTAP_PARAMS(apple80211_softap_params *) = 0; virtual IOReturn getCHIP_POWER_RANGE(apple80211_chip_power_limit *) = 0; virtual IOReturn getSOFTAP_STATS(apple80211_softap_stats *) = 0; virtual IOReturn getNSS(apple80211_nss_data *) = 0; virtual IOReturn getHW_ADDR(apple80211_hw_mac_address *) = 0; virtual IOReturn getHE_MCS_INDEX_SET(apple80211_he_mcs_index_set_data *) = 0; virtual IOReturn getCHIP_DIAGS(appl80211_chip_diags_data *) = 0; virtual IOReturn getHP2P_CTRL(apple80211_hp2p_ctrl *) = 0; virtual IOReturn getREQUEST_BSS_BLACKLIST(void *) = 0; virtual IOReturn getASSOC_READY_STATUS(apple80211_assoc_ready *) = 0; virtual IOReturn getTXRX_CHAIN_INFO(apple80211_txrx_chain_info *) = 0; virtual IOReturn getMIMO_STATUS(apple80211_mimo_status *) = 0; virtual IOReturn getCUR_PMK(apple80211_pmk *) = 0; virtual IOReturn getDYNSAR_DETAIL(apple80211_dynsar_detail *) = 0; virtual IOReturn getRANDOMISATION_STATUS(apple80211_mac_randomisation_status *) = 0; virtual IOReturn getCOUNTRY_CHANNELS_INFO(apple80211_channels_info *) = 0; virtual IOReturn getLQM_SUMMARY(apple80211_lqm_summary *) = 0; virtual IOReturn getCOLOCATED_NETWORK_SCOPE_ID(apple80211_colocated_network_scope_id *) = 0; virtual IOReturn getBEACON_SCAN_CACHE_REQ(apple80211_scan_result *) = 0; virtual IOReturn getSLOW_WIFI_FEATURE_ENABLED(apple80211_slow_wifi_feature_enabled *) = 0; virtual IOReturn getCCA(apple80211_interface_cca_data *) = 0; virtual IOReturn getRX_RATE(apple80211_rate_data *) = 0; virtual IOReturn getTIMESYNC_INFO(apple80211_timesync_info *) = 0; virtual IOReturn getSENSING_DATA(apple80211_sensing_data_t *) = 0; virtual IOReturn getCOUNTRY_BAND_SUPPORT(apple80211_country_band_support *) = 0; virtual IOReturn getWCL_FW_HOT_CHANNELS(apple80211_fw_hot_channels *) = 0; virtual IOReturn getWCL_LOW_LATENCY_INFO(apple80211_low_latency_info *) = 0; virtual IOReturn getWCL_BSS_INFO(apple80211_beacon_msg *) = 0; virtual IOReturn getWCL_TRAFFIC_COUNTERS(apple80211_wcl_traffic_counters *) = 0; virtual IOReturn getWCL_GET_TX_BLANKING_STATUS(uint *) = 0; virtual IOReturn getSSID_TRANSITION_SUPPORT(apple80211_ssid_transition_feature_enabled *) = 0; virtual IOReturn getWCL_VALID_CHANNEL_COUNT(unsigned long *) = 0; virtual IOReturn getWCL_P2P_STATUS_FOR_SCAN(p2pStatusForScan *) = 0; virtual IOReturn getWCL_CHANNELS_INFO(apple80211ChannelInfo *) = 0; virtual IOReturn getP2P_STEERING_METRIC(apple80211_p2p_steering_metrics *) = 0; virtual IOReturn getRSN_XE(apple80211_rsn_xe_data *) = 0; virtual IOReturn getSIB_COEX_STATUS(apple80211_sib_coex_status *) = 0; virtual IOReturn getWCL_EXTENDED_BSS_INFO(apple80211_extended_bss_info *) = 0; virtual IOReturn getWCL_LOW_LATENCY_INFO_STATS(apple80211_wcl_low_latency_stats *) = 0; virtual IOReturn getWCL_BGSCAN_CACHE_RESULT(apple80211_bgscan_cached_network_data_list *) = 0; virtual IOReturn getWIFI_NOISE_PER_ANT(apple80211_noise_per_ant_t *) = 0; virtual IOReturn getBLOCKED_BANDS(apple80211_blocked_bands *) = 0; virtual IOReturn setSSID(apple80211_ssid_data *) = 0; virtual IOReturn setAUTH_TYPE(apple80211_authtype_data *) = 0; virtual IOReturn setCIPHER_KEY(apple80211_key *) = 0; virtual IOReturn setCHANNEL(apple80211_channel_data *) = 0; virtual IOReturn setPOWERSAVE(apple80211_powersave_data *) = 0; virtual IOReturn setTXPOWER(apple80211_txpower_data *) = 0; virtual IOReturn setRATE(apple80211_rate_data *) = 0; virtual IOReturn setSCAN_REQ(apple80211_scan_data *) = 0; virtual IOReturn setASSOCIATE(apple80211_assoc_data *) = 0; virtual IOReturn setDISASSOCIATE(apple80211_disassoc_data *) = 0; virtual IOReturn setIBSS_MODE(apple80211_network_data *) = 0; virtual IOReturn setHOST_AP_MODE(apple80211_network_data *) = 0; virtual IOReturn setAP_MODE(apple80211_apmode_data *) = 0; virtual IOReturn setDEAUTH(apple80211_deauth_data *) = 0; virtual IOReturn setTX_ANTENNA(void *) = 0; virtual IOReturn setANTENNA_DIVERSITY(void *) = 0; virtual IOReturn setRSN_IE(apple80211_rsn_ie_data *) = 0; virtual IOReturn setBACKGROUND_SCAN(apple80211_bgscan_data *) = 0; virtual IOReturn setWOW_PARAMETERS(apple80211_wow_parameter_data *) = 0; virtual IOReturn setWOW_ENABLED(apple80211_state_data *) = 0; virtual IOReturn setPID_LOCK(apple80211_state_data *) = 0; virtual IOReturn setSTA_AUTHORIZE(apple80211_sta_authorize_data *) = 0; virtual IOReturn setSTA_DISASSOCIATE(apple80211_sta_disassoc_data *) = 0; virtual IOReturn setSTA_DEAUTH(apple80211_sta_disassoc_data *) = 0; virtual IOReturn setRSN_CONF(apple80211_rsn_conf_data *) = 0; virtual IOReturn setIE(apple80211_ie_data *) = 0; virtual IOReturn setWOW_TEST(apple80211_wow_test_data *) = 0; virtual IOReturn setSCANCACHE_CLEAR(void *) = 0; virtual IOReturn setVIRTUAL_IF_CREATE(apple80211_virt_if_create_data *) = 0; virtual IOReturn setBT_COEX_FLAGS(apple80211_state_data *) = 0; virtual IOReturn setROAM(apple80211_sta_roam_data *) = 0; virtual IOReturn setHT_CAPABILITY(apple80211_ht_capability *) = 0; virtual IOReturn setAWDL_FORCED_ROAM_CONFIG(apple80211_awdl_forced_roam_config *) = 0; virtual IOReturn setOFFLOAD_ARP(apple80211_offload_arp_data *) = 0; virtual IOReturn setOFFLOAD_NDP(apple80211_offload_ndp_data *) = 0; virtual IOReturn setOFFLOAD_SCAN(apple80211_offload_scan_data *) = 0; virtual IOReturn setGAS_REQ(apple80211_gas_query_t *) = 0; virtual IOReturn setGAS_START(apple80211_gas_query_t *) = 0; virtual IOReturn setGAS_SET_PEER(apple80211_gas_peer_t *) = 0; virtual IOReturn setVHT_CAPABILITY(apple80211_vht_capability *) = 0; virtual IOReturn setROAM_PROFILE(apple80211_roam_profile_band_data *) = 0; virtual IOReturn setAWDL_ENABLE_ROAMING(void *) = 0; virtual IOReturn setDBG_GUARD_TIME_PARAMS(apple80211_dbg_guard_time_params *) = 0; virtual IOReturn setLEAKY_AP_STATS_MODE(apple80211_leaky_ap_setting *) = 0; virtual IOReturn setPRIVATE_MAC(apple80211_private_mac_data *) = 0; virtual IOReturn setRESET_CHIP(apple80211_reset_command *) = 0; virtual IOReturn setCRASH(apple80211_crash_command *) = 0; virtual IOReturn setRANGING_ENABLE(apple80211_ranging_enable_request_t *) = 0; virtual IOReturn setRANGING_START(apple80211_ranging_start_request_t *) = 0; virtual IOReturn setRANGING_AUTHENTICATE(apple80211_ranging_authenticate_request_t *) = 0; virtual IOReturn setTKO_PARAMS(apple80211_tko_params *) = 0; virtual IOReturn setBTCOEX_PROFILE(apple80211_btcoex_profile *) = 0; virtual IOReturn setBTCOEX_PROFILE_ACTIVE(apple80211_btcoex_profile_active_data *) = 0; virtual IOReturn setTHERMAL_INDEX(apple80211_thermal_index_t *) = 0; virtual IOReturn setBTCOEX_2G_CHAIN_DISABLE(apple80211_btcoex_2g_chain_disable *) = 0; virtual IOReturn setPOWER_BUDGET(apple80211_power_budget_t *) = 0; virtual IOReturn setOFFLOAD_TCPKA_ENABLE(apple80211_offload_tcpka_enable_t *) = 0; virtual IOReturn setSUPPRESS_SCANS(apple80211_suppress_scans_t *) = 0; virtual IOReturn setHOST_AP_MODE_HIDDEN(apple80211_host_ap_mode_hidden_t *) = 0; virtual IOReturn setLQM_CONFIG(apple80211_lqm_config_t *) = 0; virtual IOReturn setSOFTAP_PARAMS(apple80211_softap_params *) = 0; virtual IOReturn setSOFTAP_TRIGGER_CSA(apple80211_softap_csa_params *) = 0; virtual IOReturn setSOFTAP_WIFI_NETWORK_INFO_IE(apple80211_softap_wifi_network_info *) = 0; virtual IOReturn setBTCOEX_DISABLE_ULOFDMA(uint *) = 0; virtual IOReturn setSCAN_CONTROL(apple80211_scan_control_params *) = 0; virtual IOReturn setUSB_HOST_NOTIFICATION(apple80211_usb_host_notification_data *) = 0; virtual IOReturn setSET_MAC_ADDRESS(apple80211_set_mac_address *) = 0; virtual IOReturn setHP2P_CTRL(apple80211_hp2p_ctrl *) = 0; virtual IOReturn setABORT_SCAN(apple80211_abort_scan *) = 0; virtual IOReturn setSET_PROPERTY(apple80211_set_property_unserialized_data *) = 0; virtual IOReturn setROAM_CACHE_UPDATE(apple80211_roam_cache_data *) = 0; virtual IOReturn setPM_MODE(apple80211_pm_mode *) = 0; virtual IOReturn setSET_WIFI_ASSERTION_STATE(apple80211_wifi_assertion_data *) = 0; virtual IOReturn setREASSOCIATE_WITH_CORECAPTURE(apple80211_capture_debug_info_t *) = 0; virtual IOReturn setLINKDOWN_DEBOUNCE_STATUS(apple80211_linkdown_debounce_status *) = 0; virtual IOReturn setSOFTAP_EXTENDED_CAPABILITIES_IE(apple80211_softap_extended_capabilities_info *) = 0; virtual IOReturn setREALTIME_QOS_MSCS(apple80211_state_data *) = 0; virtual IOReturn setSENSING_ENABLE(apple80211_sensing_enable_t *) = 0; virtual IOReturn setSENSING_DISABLE(apple80211_sensing_disable_t *) = 0; virtual IOReturn setNANPHS_ASSOCIATION(apple80211_nan_link_association_info *) = 0; virtual IOReturn setNANPHS_TERMINATED(apple80211_nan_link_association_info *) = 0; virtual IOReturn set6G_MODE(apple80211_6G_mode *) = 0; virtual IOReturn setWCL_LEAVE_NETWORK(apple80211_leave_network *) = 0; virtual IOReturn setWCL_REASSOC(apple80211_reassoc *) = 0; virtual IOReturn setWCL_SET_ROAM_LOCK(apple80211_set_roam_lock *) = 0; virtual IOReturn setWCL_ROAM_PROFILE_CONFIG(apple80211_roam_profile_config *) = 0; virtual IOReturn setWCL_ROAM_PROFILE_CONFIGV1(apple80211_roam_profile_configV1 *) = 0; virtual IOReturn setWCL_ROAM_USER_CACHE(apple80211_user_roam_cache *) = 0; virtual IOReturn setWCL_SET_MULTI_AP_ENV(apple80211_set_multi_ap_env *) = 0; virtual IOReturn setWCL_SCAN_ABORT(void *) = 0; virtual IOReturn setWCL_REAL_TIME_MODE(apple80211_wcl_real_time_mode *) = 0; virtual IOReturn setWCL_GARP_MODE(apple80211_wcl_garp_mode *) = 0; virtual IOReturn setWCL_JOIN_ABORT(void *) = 0; virtual IOReturn setWCL_TRIGGER_CC(triggerCC *) = 0; virtual IOReturn setWCL_SCAN_REQ(apple80211ScanRequest *) = 0; virtual IOReturn setWCL_ASSOCIATE(apple80211_assoc_candidates *) = 0; virtual IOReturn setWCL_PROTECT_IP(apple80211_wcl_protect_ip_mode *) = 0; virtual IOReturn setWCL_LINK_UP_DONE(void *) = 0; virtual IOReturn setWCL_SET_SCAN_HOME_AWAY_TIME(scanHomeAndAwayTime *) = 0; virtual IOReturn setWCL_VOLUNTARY_NETWORK_DISCONNECT(apple80211_wcl_voluntary_network_disconnect *) = 0; virtual IOReturn setWCL_LINK_STATE_UPDATE(apple80211_wcl_update_link_state *) = 0; virtual IOReturn setSLOW_WIFI_RECOVERY(void *) = 0; virtual IOReturn setRSN_XE(apple80211_rsn_xe_data *) = 0; virtual IOReturn setWCL_ULOFDMA_STATE(apple80211_wcl_ulofdma_state *) = 0; virtual IOReturn setWCL_ACTION_FRAME(apple80211_wcl_action_frame *) = 0; virtual IOReturn setWCL_REAL_TIME_POLICY(apple80211_wcl_real_time_policy *) = 0; virtual IOReturn setGAS_ABORT(void *) = 0; virtual IOReturn setOS_FEATURE_FLAGS(apple80211_feature_flags *) = 0; virtual IOReturn setDHCP_RENEWAL_DATA(apple80211_dhcp_renewal_data *) = 0; virtual IOReturn setMOVING_NETWORK(apple80211_network_flags *) = 0; virtual IOReturn setBATTERY_POWERSAVE_CONFIG(apple80211_battery_ps_config *) = 0; virtual IOReturn setMIMO_CONFIG(apple80211_mimo_config *) = 0; virtual IOReturn setWCL_CONFIG_BG_MOTIONPROFILE(apple80211_bg_motion_profile *) = 0; virtual IOReturn setWCL_CONFIG_BG_NETWORK(apple80211_bg_network *) = 0; virtual IOReturn setWCL_CONFIG_BGSCAN(apple80211_bg_scan *) = 0; virtual IOReturn setWCL_CONFIG_BG_PARAMS(apple80211_bg_params *) = 0; virtual IOReturn setBLOCKED_BANDS(apple80211_blocked_bands *) = 0; public: uint8_t filter[0x120]; }; #endif /* IO80211InfraProtocol_h */ ================================================ FILE: include/Airport/IO80211Interface.h ================================================ #ifndef _IO80211INTERFACE_H #define _IO80211INTERFACE_H /* * Kernel */ #if defined(KERNEL) && defined(__cplusplus) #include #include // This is necessary, because even the latest Xcode does not support properly targeting 11.0. #ifndef __IO80211_TARGET #error "Please define __IO80211_TARGET to the requested version" #endif #if VERSION_MAJOR > 8 #define _MODERN_BPF #endif #include #include #include typedef UInt kIO80211InterfaceType; /*! @defined kIO80211InterfaceClass @abstract The name of the IO80211Interface class. */ #define kIO80211InterfaceClass "IO80211Interface" typedef UInt64 IO80211FlowQueueHash; class RSNSupplicant; class IOTimerEventSource; class IOGatedOutputQueue; class IO80211Controller; class IO80211Workloop; class IO80211ScanManager; class IO80211PeerManager; class IO80211FlowQueueDatabase; class IO80211InterfaceMonitor; class IO80211AssociationJoinSnapshot; struct apple80211_debug_command; struct apple80211_txstats; struct apple80211_chip_counters_tx; struct apple80211_chip_error_counters_tx; struct apple80211_chip_counters_rx; struct apple80211_ManagementInformationBasedot11_counters; struct apple80211_leaky_ap_stats; struct apple80211_leaky_ap_ssid_metrics; struct apple80211_interface_availability; struct apple80211_pmk_cache_data; struct apple80211_ap_cmp_data; struct TxPacketRequest { uint16_t unk1; // 0 uint16_t t; // 2 uint16_t mU; // 4 uint16_t mM; // 6 uint16_t pkt_cnt; uint16_t unk2; uint16_t unk3; uint16_t unk4; uint32_t pad; mbuf_t bufs[8]; // 18 uint32_t reqTx; }; static_assert(sizeof(struct TxPacketRequest) == 0x60, "TxPacketRequest size error"); struct AWSRequest; struct packet_info_tx; struct userPrintCtx; typedef int apple80211_postMessage_tlv_types; class IO80211Interface : public IOEthernetInterface { OSDeclareDefaultStructors( IO80211Interface ); public: virtual void free() APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,uint,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,uint,void *,void *) APPLE_KEXT_OVERRIDE; virtual bool terminate(unsigned int) APPLE_KEXT_OVERRIDE; virtual bool attach(IOService*) APPLE_KEXT_OVERRIDE; virtual void detach(IOService*) APPLE_KEXT_OVERRIDE; #if __IO80211_TARGET >= __MAC_10_15 virtual IOReturn newUserClient(task_t, void*, UInt32 type, OSDictionary*, IOUserClient**) APPLE_KEXT_OVERRIDE; #endif virtual const char* stringFromReturn(int) APPLE_KEXT_OVERRIDE; virtual int errnoFromReturn(int) APPLE_KEXT_OVERRIDE; virtual bool init(IONetworkController*) APPLE_KEXT_OVERRIDE; virtual UInt32 inputPacket(mbuf_t packet, UInt32 length = 0, IOOptionBits options = 0, void * param = 0) APPLE_KEXT_OVERRIDE; virtual bool inputEvent(unsigned int, void*) APPLE_KEXT_OVERRIDE; virtual SInt32 performCommand(IONetworkController*, unsigned long, void*, void*) APPLE_KEXT_OVERRIDE; virtual IOReturn attachToDataLinkLayer(IOOptionBits, void*) APPLE_KEXT_OVERRIDE; virtual void detachFromDataLinkLayer(unsigned int, void*) APPLE_KEXT_OVERRIDE; virtual void setPoweredOnByUser(bool); virtual void setEnabledBySystem(bool); virtual bool setLinkState(IO80211LinkState, unsigned int); virtual bool setLinkState(IO80211LinkState, int, unsigned int); virtual UInt32 outputPacket(mbuf_t, void*); virtual bool setLinkQualityMetric(int); virtual void handleDebugCmd(apple80211_debug_command*); OSMetaClassDeclareReservedUnused( IO80211Interface, 0); OSMetaClassDeclareReservedUnused( IO80211Interface, 1); OSMetaClassDeclareReservedUnused( IO80211Interface, 2); OSMetaClassDeclareReservedUnused( IO80211Interface, 3); OSMetaClassDeclareReservedUnused( IO80211Interface, 4); OSMetaClassDeclareReservedUnused( IO80211Interface, 5); OSMetaClassDeclareReservedUnused( IO80211Interface, 6); OSMetaClassDeclareReservedUnused( IO80211Interface, 7); OSMetaClassDeclareReservedUnused( IO80211Interface, 8); OSMetaClassDeclareReservedUnused( IO80211Interface, 9); OSMetaClassDeclareReservedUnused( IO80211Interface, 10); OSMetaClassDeclareReservedUnused( IO80211Interface, 11); OSMetaClassDeclareReservedUnused( IO80211Interface, 12); OSMetaClassDeclareReservedUnused( IO80211Interface, 13); OSMetaClassDeclareReservedUnused( IO80211Interface, 14); OSMetaClassDeclareReservedUnused( IO80211Interface, 15); public: IOReturn IO80211InterfacePostMessage(UInt,void *,unsigned long); struct apple80211_ap_cmp_data *apCompare(apple80211_ap_cmp_data *,apple80211_ap_cmp_data *); void associateForNetBoot(IOService *); IOReturn associateForNetBootGated(OSObject *,void *,void *,void *,void *); bool authTimeout(void); UInt32 awsRespond(mbuf_t,AWSRequest *,unsigned long,unsigned short); IOReturn bpfAttach(UInt,UInt); IOReturn bpfAttach(UInt,UInt,OSObject *,UInt (OSObject::*)(mbuf_t,void *),int (OSObject::*)(UInt,UInt),IOWorkLoop *); IOReturn bpfOutput(UInt,mbuf_t); UInt32 bpfOutputPacket(mbuf_t,void *); void bpfTap(UInt,UInt); UInt32 bpfTapInput(mbuf_t,UInt,void *,unsigned long); UInt32 cachePMKSA(unsigned char *,unsigned long,ether_addr *); UInt32 cachePMKSA(unsigned char *,unsigned long,ether_addr *,unsigned char *); void clearAssocHistory(void); void configureAntennae(void); void configureBpfOutputQueues(bool); IOReturn createAssocHistory(void); UInt64 createIOReporters(IOService *); UInt64 debugFlags(void); mbuf_t dequeueTxPackets(TxPacketRequest *); mbuf_t dequeueTxPackets(UInt,UInt); void dropTxPacket(mbuf_t); bool efiNVRAMPublished(void *,void *,IOService *,IONotifier *); bool enabledBySystem(void); IO80211FlowQueue *findExistingFlowQueue(IO80211FlowQueueHash); IO80211FlowQueue *findOrCreateFlowQueue(IO80211FlowQueueHash); void finishAttachToDataLinkLayer(void); IOReturn finishAttachToDataLinkLayerGated(OSObject *,void *,void *,void *,void *); void flushPacketQueues(void); void freeBpf(void); void freePMKSACache(void); const char *getBSDName(); IO80211Controller *getController(void); IO80211WorkLoop *getControllerWorkLoop(void); bool getExtendedStats(apple80211_extended_stats *); bool getLeakyApStats(apple80211_leaky_ap_stats const**); IOOutputQueue *getOutputQueue(void); IOOutputQueue *getOutputQueueForDLT(UInt); void getPMKSAList(apple80211_pmk_cache_data *); void getWmeTxCounters(unsigned long long *); void handleLeakyApStatsModeTimer(IOTimerEventSource *); void handleLeakyApStatsResetTimer(IOTimerEventSource *); bool initSupplicant(unsigned char *,int); UInt32 inputAWSPacket(mbuf_t); IO80211LinkState linkState(void); void logDebug(char const*, ...); void logDebug(unsigned long long, char const*, ...); void logDebugHex(void const*,unsigned long,char const*,...); void logTxCompletionPacket(mbuf_t,int); void logTxPacket(mbuf_t); UInt32 monitorModeInputPacket(mbuf_t,UInt,void *,unsigned long); IOReturn netBootThread(IOService *); IOReturn netBootThreadGated(OSObject *,void *,void *,void *,void *); bool netBooting(void); UInt32 outputEAPOLFrame(mbuf_t); void outputPreEnqueueHandler(void *,void *,mbuf_t); IOReturn outputStart(UInt); UInt64 packetSpace(unsigned char); UInt64 pendingPackets(unsigned char); IOReturn performCountryCodeOpGated(OSObject *,void *,void *,void *,void *); IOReturn performGatedCommand(void *,void *,void *,void *,void *); bool pidLocked(void); UInt64 pmksaLookup(ether_addr *,unsigned char *); void postMessage(unsigned int, void* data = NULL, unsigned long dataLen = 0); IOReturn powerChangeHandler(void *,void *,UInt,IOService *,void *,unsigned long); bool poweredOnByUser(void); mbuf_t preQueuePacket(mbuf_t); void printDataPath(userPrintCtx *); void printPeers(UInt,UInt); void purgePMKSACache(void); UInt64 queueSize(unsigned char); IOReturn queueWMEPacket(mbuf_t,void *); void removePacketQueue(IO80211FlowQueueHash const*); IOReturn reportDataPathEvents(UInt,void *,unsigned long); IOReturn reportDataPathEventsGated(void *,void *,void *,void *,void *); IOReturn reportDataTransferRates(void); IOReturn reportDataTransferRatesGated(void); IOReturn reportDataTransferRatesStatic(void *); IOReturn reportTransmitCompletionStatus(mbuf_t,int,UInt,UInt,UInt); void reportTransmitStatus(mbuf_t,int,packet_info_tx *); void reportTxStatistics(apple80211_txstats *); void resetLeakyApStats(void); void resetSupplicant(void); #if __IO80211_TARGET >= __MAC_10_15 void resetUserClientReference(void); #endif #if __IO80211_TARGET >= __MAC_11_0 IOReturn resetUserClientReferenceGated(OSObject *,void *,void *,void *,void *); #endif void setAuthTimeout(unsigned long); bool setBTCoexWLANLostAntennaTime(unsigned long long,unsigned long long,bool,apple80211_btCoex_report *); void setCountermeasuresTimer(IOTimerEventSource *); void setDataPathState(bool); IOReturn setDataPointerAndLengthForMessageType(apple80211_postMessage_tlv_types,void **,unsigned long *); void setDebugFlags(unsigned long long,UInt); bool setFrameStats(apple80211_stat_report *,apple80211_frame_counters *); bool setInterfaceCCA(apple80211_channel,int); bool setInterfaceChipCounters(apple80211_stat_report *,apple80211_chip_counters_tx *,apple80211_chip_error_counters_tx *,apple80211_chip_counters_rx *); bool setInterfaceExtendedCCA(apple80211_channel,apple80211_cca_report *); bool setInterfaceMIBdot11(apple80211_stat_report *,apple80211_ManagementInformationBasedot11_counters *); IOReturn setLQM(unsigned long long); IOReturn setLQMGated(long long); IOReturn setLQMStatic(void *,void *); bool setLeakyAPStats(apple80211_leaky_ap_event *); bool setLeakyAPStatsMode(UInt); bool setLeakyApSsidMetrics(apple80211_leaky_ap_ssid_metrics *); void setNetBooting(bool); bool setPMK(unsigned char *,unsigned char *); #if __IO80211_TARGET >= __MAC_10_15 bool setPSKPMK(unsigned char *); #endif void setPeerManagerLogFlag(UInt,UInt,UInt); bool setPidLock(bool); void setScanningState(UInt,bool,apple80211_scan_data *,int); void setWoWEnabled(bool); bool shortGISupported20MHz(void); bool shortGISupported40MHz(void); bool shouldLog(unsigned long long); bool shouldRoam(apple80211_scan_result *); #if __IO80211_TARGET >= __MAC_10_15 IOReturn startAsyncEventUserClientForTask(task *,kIO80211InterfaceType); #endif void startOutputQueues(); void stopBpf(void); void stopCountermeasures(OSObject *,IOTimerEventSource *); void stopOutputQueues(); bool supplicantExchangeComplete(void); bool supplicantInitialized(void); void terminateSupplicant(void); void togglePeerManagerLogFlag(UInt,UInt); void updateBSSIDProperty(void); void updateChannelProperty(void); void updateChannelPropertyGated(void); void updateChannelPropertyStatic(void *); void updateCountryCodeProperty(bool); bool updateInterfaceCoexRiskPct(unsigned long long); void updateLinkParameters(apple80211_interface_availability *); void updateLinkParametersGated(apple80211_interface_availability *); void updateLinkParametersStatic(void *,void *); bool updateLinkSpeed(); IOReturn updateLinkStatus(void); IOReturn updateLinkStatusGated(void); IOReturn updateLinkStatusStatic(void *); void updateSSIDProperty(void); void updateStaticProperties(void); void vlogDebug(unsigned long long, char const*, va_list); void vlogDebugBPF(unsigned long long,char const*,va_list); void willRoam(ether_addr *,UInt); protected: u_int8_t dat[0x500]; }; #endif /* defined(KERNEL) && defined(__cplusplus) */ #endif /* ! _IO80211INTERFACE_H */ ================================================ FILE: include/Airport/IO80211P2PInterface.h ================================================ #ifndef IO80211P2PInterface_h #define IO80211P2PInterface_h #include "IO80211VirtualInterface.h" class IO80211P2PInterface : public IO80211VirtualInterface { OSDeclareDefaultStructors(IO80211P2PInterface) public: virtual void free(void) APPLE_KEXT_OVERRIDE; #if __IO80211_TARGET >= __MAC_11_0 virtual bool willTerminate(IOService *,uint) APPLE_KEXT_OVERRIDE; #endif virtual IOReturn configureReport(IOReportChannelList *channels, IOReportConfigureAction action, void *result, void *destination) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *channels, IOReportUpdateAction action, void *result, void *destination) APPLE_KEXT_OVERRIDE; virtual bool terminate( IOOptionBits options = 0 ) APPLE_KEXT_OVERRIDE; virtual bool attach(IOService *) APPLE_KEXT_OVERRIDE; virtual void detach(IOService *) APPLE_KEXT_OVERRIDE; #if __IO80211_TARGET >= __MAC_10_15 virtual IOReturn newUserClient(task_t,void *,UInt,OSDictionary *,IOUserClient **) APPLE_KEXT_OVERRIDE; #endif virtual const char * stringFromReturn( IOReturn rtn ) APPLE_KEXT_OVERRIDE; virtual int errnoFromReturn( IOReturn rtn ) APPLE_KEXT_OVERRIDE; virtual IOReturn powerStateWillChangeTo( IOPMPowerFlags capabilities, unsigned long stateNumber, IOService * whatDevice ) APPLE_KEXT_OVERRIDE; virtual IOReturn powerStateDidChangeTo( IOPMPowerFlags capabilities, unsigned long stateNumber, IOService * whatDevice ) APPLE_KEXT_OVERRIDE; virtual bool init(IO80211Controller *,ether_addr *,uint,char const*) APPLE_KEXT_OVERRIDE; virtual bool createPeerManager(ether_addr *,IO80211PeerManager **) APPLE_KEXT_OVERRIDE; virtual IOMediumType getMediumType() APPLE_KEXT_OVERRIDE; virtual void setLinkState(IO80211LinkState,uint) APPLE_KEXT_OVERRIDE; virtual bool dequeueOutputPacketsWithServiceClass(uint,IOMbufServiceClass,mbuf_t*,mbuf_t*,UInt *,unsigned long long *) APPLE_KEXT_OVERRIDE; virtual UInt32 outputPacket (mbuf_t m, void* param) APPLE_KEXT_OVERRIDE; virtual void setEnabledBySystem(bool) APPLE_KEXT_OVERRIDE; virtual void handleIoctl(unsigned long,void *) APPLE_KEXT_OVERRIDE; virtual UInt32 inputPacket(mbuf_t,packet_info_tag *) APPLE_KEXT_OVERRIDE; virtual IOReturn controllerWillChangePowerState(IO80211Controller *,unsigned long,UInt,IOService *) APPLE_KEXT_OVERRIDE; virtual IOReturn controllerDidChangePowerState(IO80211Controller *,unsigned long,UInt,IOService *) APPLE_KEXT_OVERRIDE; virtual bool handleDebugCmd(apple80211_debug_command *) APPLE_KEXT_OVERRIDE; virtual IOReturn postPeerPresence(ether_addr *,int,int,int,char *) APPLE_KEXT_OVERRIDE; virtual IOReturn postPeerAbsence(ether_addr *) APPLE_KEXT_OVERRIDE; #if __IO80211_TARGET >= __MAC_10_15 virtual IOReturn postPeerPresenceIPv6(ether_addr *,int,int,int,char *,unsigned char *) APPLE_KEXT_OVERRIDE; #endif virtual void signalOutputThread() APPLE_KEXT_OVERRIDE; virtual bool isOutputFlowControlled() APPLE_KEXT_OVERRIDE; virtual void setOutputFlowControlled() APPLE_KEXT_OVERRIDE; virtual void clearOutputFlowControlled() APPLE_KEXT_OVERRIDE; virtual void outputStart(uint) APPLE_KEXT_OVERRIDE; virtual UInt32 configureAQMOutput() APPLE_KEXT_OVERRIDE; virtual void setUnitNumber(char const*) APPLE_KEXT_OVERRIDE; virtual bool initIfnetEparams(ifnet_init_eparams *) APPLE_KEXT_OVERRIDE; virtual bool attachToBpf() APPLE_KEXT_OVERRIDE; virtual bool configureIfnet() APPLE_KEXT_OVERRIDE; OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 0); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 1); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 2); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 3); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 4); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 5); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 6); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 7); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 8); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 9); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 10); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 11); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 12); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 13); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 14); OSMetaClassDeclareReservedUnused( IO80211P2PInterface, 15); public: #if __IO80211_TARGET < __MAC_11_0 void setJoiningState(UInt,joinStatus,bool); void setInfraChannel(apple80211_channel *); #endif void p2pSetUnitNumber(char const*); bool p2pCreatePeerManager(ether_addr *,IO80211PeerManager **); bool p2pConfigureIfnet(void); bool p2pAttachToBpf(void); #if __IO80211_TARGET < __MAC_11_0 #if __IO80211_TARGET >= __MAC_10_15 void notifyHostapState(apple80211_hostap_state *); #endif bool isAwdlAssistedDiscoveryEnabled(void); void handleChannelSwitchAnnouncement(apple80211_channel_switch_announcement *); void awdlSetUnitNumber(char const*); void awdlInit(void); void awdlFree(void); bool awdlCreatePeerManager(ether_addr *,IO80211PeerManager **); bool awdlConfigureIfnet(void); bool awdlAttachToBpf(void); #endif #if __IO80211_TARGET >= __MAC_11_0 bool isP2P(void); bool isAPSTA(void); #endif errno_t apsta_if_output_pre_enqueue(ifnet_t, mbuf_t); void apStaSetUnitNumber(char const*); bool apStaInitIfnetEparams(ifnet_init_eparams *); bool apStaCreatePeerManager(ether_addr *,IO80211PeerManager **); bool apStaConfigureIfnet(void); bool apStaAttachToBpf(void); public: char buf[0x300]; }; #endif /* IO80211P2PInterface_h */ ================================================ FILE: include/Airport/IO80211SkywalkInterface.h ================================================ // // IO80211SkywalkInterface.h // IO80211Family // // Created by 钟先耀 on 2019/10/18. // Copyright © 2019 钟先耀. All rights reserved. // #ifndef _IO80211SKYWALK_H #define _IO80211SKYWALK_H #include #include "IOSkywalkEthernetInterface.h" // This is necessary, because even the latest Xcode does not support properly targeting 11.0. #ifndef __IO80211_TARGET #error "Please define __IO80211_TARGET to the requested version" #endif class TxSubmissionDequeueStats; class TxCompletionEnqueueStats; class IO80211NetworkPacket; class PacketSkywalkScratch; typedef UInt64 IO80211FlowQueueHash; class IO80211Peer; class CCPipe; class IO80211APIUserClient; struct apple80211_wme_ac; struct apple80211_interface_availability; struct apple80211_cca_report; struct apple80211_stat_report; struct apple80211_chip_counters_tx; struct apple80211_chip_counters_rx; struct apple80211_chip_error_counters_tx; struct apple80211_ManagementInformationBasedot11_counters; struct apple80211_lteCoex_report; struct apple80211_frame_counters; struct userPrintCtx; struct apple80211_lqm_summary; struct apple80211_infra_specific_stats; struct TxPacketRequest { uint16_t unk1; // 0 uint16_t t; // 2 uint16_t mU; // 4 uint16_t mM; // 6 uint16_t pkt_cnt; uint16_t unk2; uint16_t unk3; uint16_t unk4; uint32_t pad; mbuf_t bufs[8]; // 18 uint32_t reqTx; }; static_assert(sizeof(struct TxPacketRequest) == 0x60, "TxPacketRequest size error"); class IO80211SkywalkInterface : public IOSkywalkEthernetInterface { OSDeclareAbstractStructors(IO80211SkywalkInterface) public: virtual bool init() APPLE_KEXT_OVERRIDE; virtual void free() APPLE_KEXT_OVERRIDE; virtual IOReturn configureReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *,UInt,void *,void *) APPLE_KEXT_OVERRIDE; virtual bool start(IOService *) APPLE_KEXT_OVERRIDE; virtual void stop(IOService *) APPLE_KEXT_OVERRIDE; virtual IOReturn setPowerState( unsigned long powerStateOrdinal, IOService * whatDevice ) APPLE_KEXT_OVERRIDE; virtual unsigned long maxCapabilityForDomainState( IOPMPowerFlags domainState ) APPLE_KEXT_OVERRIDE; virtual unsigned long initialPowerStateForDomainState( IOPMPowerFlags domainState ) APPLE_KEXT_OVERRIDE; virtual IOReturn enable(UInt) APPLE_KEXT_OVERRIDE; virtual IOReturn disable(UInt) APPLE_KEXT_OVERRIDE; virtual SInt32 initBSDInterfaceParameters(ifnet_init_eparams *,sockaddr_dl **) APPLE_KEXT_OVERRIDE; virtual bool prepareBSDInterface(ifnet_t, UInt) APPLE_KEXT_OVERRIDE; virtual IOReturn processBSDCommand(ifnet_t, UInt, void *) APPLE_KEXT_OVERRIDE; virtual SInt32 setInterfaceEnable(bool) APPLE_KEXT_OVERRIDE; virtual SInt32 setRunningState(bool) APPLE_KEXT_OVERRIDE; virtual IOReturn handleChosenMedia(UInt) APPLE_KEXT_OVERRIDE; virtual void *getSupportedMediaArray(UInt *,UInt *) APPLE_KEXT_OVERRIDE; virtual UInt32 getFeatureFlags(void) APPLE_KEXT_OVERRIDE; virtual const char *classNameOverride(void) APPLE_KEXT_OVERRIDE; virtual IOReturn setPromiscuousModeEnable(bool, UInt) APPLE_KEXT_OVERRIDE; virtual void *createPeerManager(void); virtual void postMessage(UInt,void *,unsigned long,bool); virtual IOReturn reportDataPathEvents(UInt,void *,unsigned long,bool); virtual IOReturn recordOutputPackets(TxSubmissionDequeueStats *,TxSubmissionDequeueStats *); virtual IOReturn recordOutputPacket(apple80211_wme_ac,int,int); virtual void logTxPacket(IO80211NetworkPacket *,PacketSkywalkScratch *,apple80211_wme_ac,bool); virtual void logTxCompletionPacket(IO80211NetworkPacket *,PacketSkywalkScratch *,unsigned char *,apple80211_wme_ac,int,UInt,bool); virtual IOReturn recordCompletionPackets(TxCompletionEnqueueStats *,TxCompletionEnqueueStats *); virtual IOReturn inputPacket(IO80211NetworkPacket *,packet_info_tag *,ether_header *,bool *); virtual IOReturn forwardInfraRelayPackets(IO80211NetworkPacket*, ether_header*); virtual void logSkywalkTxReqPacket(IO80211NetworkPacket *,PacketSkywalkScratch *,unsigned char *,apple80211_wme_ac,bool); virtual SInt64 pendingPackets(unsigned char); virtual SInt64 packetSpace(unsigned char); virtual bool isChipInterfaceReady(void); virtual bool isDebounceOnGoing(void); virtual bool setLinkState(IO80211LinkState,UInt,bool debounceTimeout = 30,UInt code = 0); virtual IO80211LinkState linkState(void); virtual void setScanningState(UInt,bool,apple80211_scan_data *,int); virtual void setDataPathState(bool); virtual void *getScanManager(void); virtual void updateLinkParameters(apple80211_interface_availability *); virtual void updateInterfaceCoexRiskPct(unsigned long long); virtual void setLQM(unsigned long long); virtual void updateLinkStatus(void); virtual void updateLinkStatusGated(void); virtual void setInterfaceExtendedCCA(apple80211_channel,apple80211_cca_report *); virtual void setInterfaceCCA(apple80211_channel,int); virtual void setInterfaceNF(apple80211_channel,long long); virtual void setInterfaceOFDMDesense(apple80211_channel,long long); virtual void removePacketQueue(IO80211FlowQueueHash *); virtual void setDebugFlags(unsigned long long,UInt); virtual SInt64 debugFlags(void); virtual void setInterfaceChipCounters(apple80211_stat_report *,apple80211_chip_counters_tx *,apple80211_chip_error_counters_tx *,apple80211_chip_counters_rx *); virtual void setInterfaceMIBdot11(apple80211_stat_report *,apple80211_ManagementInformationBasedot11_counters *); virtual void setFrameStats(apple80211_stat_report *,apple80211_frame_counters *); #if __IO80211_TARGET >= __MAC_14_4 virtual void setInfraSpecificFrameStats(apple80211_stat_report *,apple80211_infra_specific_stats *); #endif virtual SInt64 getWmeTxCounters(unsigned long long *); virtual void setEnabledBySystem(bool); virtual bool enabledBySystem(void); virtual bool willRoam(ether_addr *,UInt); virtual void setPeerManagerLogFlag(UInt,UInt,UInt); virtual void setWoWEnabled(bool); virtual bool wowEnabled(void); virtual void printDataPath(userPrintCtx *); virtual bool findOrCreateFlowQueue(IO80211FlowQueueHash); virtual UInt64 findOrCreateFlowQueueWithCache(IO80211FlowQueueHash,bool *); virtual UInt64 findExistingFlowQueue(IO80211FlowQueueHash); virtual void removePacketQueue(IO80211FlowQueueHash const*); virtual void flushPacketQueues(void); virtual void cachePeer(ether_addr *,UInt *); virtual bool shouldLog(unsigned long long); virtual void vlogDebug(unsigned long long,char const*,va_list); virtual void vlogDebugBPF(unsigned long long,char const*,va_list); virtual UInt64 createLinkQualityMonitor(IO80211Peer *,IOService *); virtual void releaseLinkQualityMonitor(IO80211Peer *); virtual void *getP2PSkywalkPeerMgr(void); virtual bool isCommandProhibited(int); virtual void setNotificationProperty(OSSymbol const*,OSObject const*); virtual void *getWorkerMatchingDict(OSString *); virtual bool init(IOService *); virtual bool isInterfaceEnabled(void); virtual ether_addr *getSelfMacAddr(void); virtual void setSelfMacAddr(ether_addr *); virtual void *getPacketPool(OSString *); virtual void *getLogger(void); virtual IOReturn handleSIOCSIFADDR(void); virtual IOReturn debugHandler(apple80211_debug_command *); virtual void statsDump(void); virtual void powerOnNotification(void); virtual void powerOffNotification(void); virtual UInt64 getTxQueueDepth(void); virtual UInt64 getRxQueueCapacity(void); virtual void updateRxCounter(unsigned long long); virtual void *getMultiCastQueue(void); virtual void *getCurrentBssid(void); virtual int getAssocState(void); virtual void notifyQueueState(apple80211_wme_ac,unsigned short); virtual int getTxHeadroom(void); virtual void *getRxCompQueue(void); virtual void *getTxCompQueue(void); virtual void *getTxSubQueue(apple80211_wme_ac); virtual void *getTxPacketPool(void); virtual void *getRxPacketPool(void); virtual void enableDatapath(void); virtual void disableDatapath(void); virtual int getNumTxQueues(void); virtual void *getLQMSummary(apple80211_lqm_summary *); virtual int getEventPipeSize(void); virtual UInt64 createEventPipe(IO80211APIUserClient *); virtual void destroyEventPipe(IO80211APIUserClient *); virtual void postMessageIOUC(char const*,UInt,void *,unsigned long); virtual bool isIOUCPipeOpened(void); virtual void *getRingMD(IO80211APIUserClient *,unsigned long long); public: OSString *setInterfaceRole(UInt role); void *setInterfaceId(UInt id); int getInterfaceRole(); public: char _data[0x118]; }; #endif /* _IO80211SKYWALK_H */ ================================================ FILE: include/Airport/IO80211VirtualInterface.h ================================================ #ifndef IO80211VirtualInterface_h #define IO80211VirtualInterface_h #include "IO80211Interface.h" #include "apple_private_spi.h" typedef UInt64 IO80211FlowQueueHash; typedef UInt kIO80211InterfaceType; class IO80211PeerManager; class RSNSupplicant; struct TxPacketRequest; struct ifmediareq; struct realTimeServiceId; struct apple80211_awdl_app_specific_info; struct apple80211_awdl_statistics; struct apple80211_lowlatency_peer_statistics_evevt; struct apple80211_p2p_airplay_statistics; struct apple80211_awdl_sidecar_statistics; class IO80211VirtualInterface : public IOService { OSDeclareDefaultStructors(IO80211VirtualInterface) public: virtual void free(void) APPLE_KEXT_OVERRIDE; #if __IO80211_TARGET >= __MAC_11_0 virtual bool willTerminate( IOService * provider, IOOptionBits options ) APPLE_KEXT_OVERRIDE; #endif virtual IOReturn configureReport(IOReportChannelList *channels, IOReportConfigureAction action, void *result, void *destination) APPLE_KEXT_OVERRIDE; virtual IOReturn updateReport(IOReportChannelList *channels, IOReportUpdateAction action, void *result, void *destination) APPLE_KEXT_OVERRIDE; virtual bool terminate( IOOptionBits options = 0 ) APPLE_KEXT_OVERRIDE; virtual bool attach(IOService *) APPLE_KEXT_OVERRIDE; virtual void detach(IOService *) APPLE_KEXT_OVERRIDE; #if __IO80211_TARGET >= __MAC_10_15 virtual IOReturn newUserClient(task_t,void *,UInt,OSDictionary *,IOUserClient **) APPLE_KEXT_OVERRIDE; #endif virtual const char * stringFromReturn( IOReturn rtn ) APPLE_KEXT_OVERRIDE; virtual int errnoFromReturn( IOReturn rtn ) APPLE_KEXT_OVERRIDE; virtual IOReturn powerStateWillChangeTo( IOPMPowerFlags capabilities, unsigned long stateNumber, IOService * whatDevice ) APPLE_KEXT_OVERRIDE; virtual IOReturn powerStateDidChangeTo( IOPMPowerFlags capabilities, unsigned long stateNumber, IOService * whatDevice ) APPLE_KEXT_OVERRIDE; virtual bool init(IO80211Controller *,ether_addr *,UInt,char const*); virtual bool createPeerManager(ether_addr *,IO80211PeerManager **); virtual IOMediumType getMediumType(); virtual void setLinkState(IO80211LinkState,UInt); virtual bool dequeueOutputPacketsWithServiceClass(UInt,IOMbufServiceClass,mbuf_t*,mbuf_t*,UInt *,unsigned long long *); virtual UInt32 outputPacket (mbuf_t m, void* param); virtual void setEnabledBySystem(bool); virtual void handleIoctl(unsigned long,void *); virtual UInt32 inputPacket(mbuf_t,packet_info_tag *); virtual IOReturn controllerWillChangePowerState(IO80211Controller *,unsigned long,UInt,IOService *); virtual IOReturn controllerDidChangePowerState(IO80211Controller *,unsigned long,UInt,IOService *); virtual bool handleDebugCmd(apple80211_debug_command *); virtual IOReturn postPeerPresence(ether_addr *,int,int,int,char *); virtual IOReturn postPeerAbsence(ether_addr *); #if __IO80211_TARGET >= __MAC_10_15 virtual IOReturn postPeerPresenceIPv6(ether_addr *,int,int,int,char *,unsigned char *); #endif virtual void signalOutputThread(); virtual bool isOutputFlowControlled(); virtual void setOutputFlowControlled(); virtual void clearOutputFlowControlled(); virtual void outputStart(UInt); virtual UInt32 configureAQMOutput(); virtual void setUnitNumber(char const*); virtual bool initIfnetEparams(ifnet_init_eparams *); virtual bool attachToBpf(); virtual bool configureIfnet(); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 0); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 1); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 2); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 3); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 4); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 5); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 6); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 7); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 8); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 9); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 10); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 11); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 12); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 13); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 14); OSMetaClassDeclareReservedUnused( IO80211VirtualInterface, 15); public: IOReturn IO80211InterfacePostMessage(UInt,void *,unsigned long); #if __IO80211_TARGET < __MAC_10_15 IOReturn _outputStart(OSObject *,void *,void *,void *,void *); IOReturn _outputStartGated(UInt); IOReturn _outputStartGatedNoPM(UInt); #endif bool attachIfnet(ether_addr *,char const*); bool authTimeout(void); errno_t bpfAttach(UInt,UInt); errno_t bpfAttach(UInt,UInt,OSObject *,UInt (OSObject::*)(mbuf_t,void *),int (OSObject::*)(UInt,UInt),IOWorkLoop *); errno_t bpfAttachEN10MB(UInt); UInt32 bpfOutput(UInt,mbuf_t); UInt32 bpfOutputPacket(mbuf_t,void *); UInt32 bpfTap(UInt,UInt); void bpfTapInput(mbuf_t,UInt,void *,unsigned long); UInt32 cachePMKSA(unsigned char *,unsigned long,ether_addr *); UInt32 cachePMKSA(unsigned char *,unsigned long,ether_addr *,unsigned char *); bool controllerLostPower(void); UInt64 createIOReporters(IOService *); UInt64 debugFlags(void); mbuf_t dequeueTxPackets(TxPacketRequest *); errno_t detachIfnet(void); void dropTxPacket(mbuf_t); bool dualBandCapable(void); bool enabledBySystem(void); IO80211FlowQueue *findExistingFlowQueue(IO80211FlowQueueHash); IO80211FlowQueue *findOrCreateFlowQueue(IO80211FlowQueueHash); void flushPacketQueues(void); const char *getBSDName(void); IO80211Controller *getController(void); IOLock *getDetachLock(void); ifnet_t getIfnet(void); #if __IO80211_TARGET >= __MAC_10_15 bool getInterfaceAddress(unsigned char *); #endif UInt getInterfaceRole(void); IOOutputQueue *getOutputQueueForDLT(UInt); void getPMKSAList(apple80211_pmk_cache_data *); void getWmeTxCounters(unsigned long long *); IO80211WorkLoop *getWorkLoop(void); #if __IO80211_TARGET >= __MAC_11_0 void handleChannelSwitchAnnouncement(apple80211_channel_switch_announcement *); #endif IOReturn handleIoctlGated(void *,void *,void *,void *,void *); SInt32 handleSIOCGIFMEDIA(unsigned long,ifmediareq *); SInt32 handleSIOCSIFADDR(void); SInt32 handleSIOCSIFFLAGS(char const*); static void ifnet_detach_callback(ifnet_t); static void ifnet_ioctl_callback(ifnet_t,unsigned long,void *); static void ifnet_start_callback(ifnet_t); bool initSupplicant(unsigned char *,int); void ioctl_internal(void *); IOReturn ioctl_internal_gated(void *,void *,void *,void *,void *); #if __IO80211_TARGET >= __MAC_11_0 bool isAwdlAssistedDiscoveryEnabled(void); bool isPeerToPeerInterface(void); #endif IO80211LinkState linkState(void); void logDebug(char const*,...); void logDebug(unsigned long long,char const*,...); void logTxCompletionPacket(mbuf_t,int); void logTxPacket(mbuf_t); #if __IO80211_TARGET >= __MAC_11_0 void notifyHostapState(apple80211_hostap_state *); void p2pDaemonExited(void); #endif UInt64 packetSpace(unsigned char); #if __IO80211_TARGET >= __MAC_11_0 bool peerToPeerAttachToBpf(void); errno_t peerToPeerConfigureIfnet(void); #endif UInt64 pendingPackets(unsigned char); #if __IO80211_TARGET >= __MAC_10_15 void postAwdlAppSpecificInfo(apple80211_awdl_app_specific_info *); #endif #if __IO80211_TARGET >= __MAC_11_0 void postAwdlHppStatsEvent(realTimeServiceId); #else void postAwdlSidecarStatistics(apple80211_awdl_sidecar_statistics *); #endif void postAwdlStatistics(apple80211_awdl_statistics *); #if __IO80211_TARGET >= __MAC_11_0 void postHostapChannelChanged(apple80211_hostap_state *); void postLowlatencyStatistics(apple80211_lowlatency_peer_statistics_evevt *); #endif void postMessage(unsigned int, void* data = NULL, unsigned long dataLen = 0); void postNewMasterElected(void); #if __IO80211_TARGET >= __MAC_11_0 void postP2PAirplayStatistics(apple80211_p2p_airplay_statistics *); #endif void postServiceIndication(void); void postSyncStateChanged(void); IOReturn powerStateDidChangeToGated(void *,void *,void *,void *,void *); IOReturn powerStateWillChangeToGated(void *,void *,void *,void *,void *); mbuf_t preQueuePacket(mbuf_t); void printDataPath(userPrintCtx *); void pushPacket(mbuf_t); UInt64 queueSize(unsigned char); void removePacketQueue(IO80211FlowQueueHash const*); IOReturn reportDataPathEvents(UInt,void *,unsigned long); IOReturn reportDataPathEventsGated(void *,void *,void *,void *,void *); IOReturn reportTransmitCompletionStatus(mbuf_t,int,UInt,UInt,UInt); void reportTransmitStatus(mbuf_t,int,packet_info_tx *); void resetSupplicant(void); #if __IO80211_TARGET >= __MAC_10_15 void resetUserClientReference(void); #endif #if __IO80211_TARGET >= __MAC_11_0 IOReturn resetUserClientReferenceGated(OSObject *,void *,void *,void *,void *); void sendToBpfTap(mbuf_t,UInt,void *,unsigned long); void setAMPDUstat(apple80211_stat_report *,apple80211_ampdu_stat_report *); #endif void setAuthTimeout(unsigned long); void setDebugFlags(unsigned long long,UInt); bool setFrameStats(apple80211_stat_report *,apple80211_frame_counters *); #if __IO80211_TARGET >= __MAC_11_0 void setInfraChannel(apple80211_channel *); #endif void setInfraTxState(bool); bool setInterfaceCCA(apple80211_channel,int,apple80211_awdl_sync_channel_sequence *); bool setInterfaceChipCounters(apple80211_stat_report *,apple80211_chip_counters_tx *,apple80211_chip_error_counters_tx *,apple80211_chip_counters_rx *); bool setInterfaceExtendedCCA(apple80211_channel,apple80211_cca_report *,apple80211_awdl_sync_channel_sequence *); bool setInterfaceMIBdot11(apple80211_stat_report *,apple80211_ManagementInformationBasedot11_counters *); void setInterfaceRole(UInt); #if __IO80211_TARGET >= __MAC_11_0 void setJoiningState(UInt,joinStatus,bool); #endif bool setPMK(unsigned char *); #if __IO80211_TARGET >= __MAC_10_15 bool setPSKPMK(unsigned char *); #endif void setScanningState(UInt,bool,apple80211_scan_data *,int); void setUnitNumber(char const*,UInt); void setWaitingForDetach(bool); void setWoWEnabled(bool); bool shouldLog(unsigned long long); #if __IO80211_TARGET >= __MAC_10_15 IOReturn startAsyncEventUserClientForTask(task *,kIO80211InterfaceType); #endif void startOutputQueues(void); #if __IO80211_TARGET >= __MAC_11_0 IOReturn startP2PDaemonUserClientForTask(task *); #endif void stopOutputQueues(void); bool supplicantExchangeComplete(void); bool supplicantInitialized(void); void terminateSupplicant(void); void updateInterfaceCoexRiskPct(unsigned long long); void updateLinkParameters(apple80211_interface_availability *); void vlogDebug(unsigned long long,char const*,va_list); void vlogDebugBPF(unsigned long long,char const*,va_list); public: char buf[0x300]; }; #endif /* IO80211VirtualInterface_h */ ================================================ FILE: include/Airport/IO80211WorkLoop.h ================================================ /* * IO80211WorkLoop.h * IO80211Family * * Created by Pete on 5/31/06. * Copyright 2006 Apple Computer, Inc. All rights reserved. * */ #ifndef _IO80211WORKLOOP_H #define _IO80211WORKLOOP_H #include #include // This is necessary, because even the latest Xcode does not support properly targeting 11.0. #ifndef __IO80211_TARGET #error "Please define __IO80211_TARGET to the requested version" #endif class IO80211WorkLoop : public IOWorkLoop { OSDeclareDefaultStructors( IO80211WorkLoop ) public: static IO80211WorkLoop * workLoop(); virtual void openGate() APPLE_KEXT_OVERRIDE; virtual void closeGate() APPLE_KEXT_OVERRIDE; virtual int sleepGate( void * event, UInt32 interuptibleType ) APPLE_KEXT_OVERRIDE; virtual int sleepGateDeadline( void * event, UInt32 interuptibleType, AbsoluteTime deadline ); virtual void wakeupGate( void * event, bool oneThread ) APPLE_KEXT_OVERRIDE; }; #endif ================================================ FILE: include/Airport/IO80211WorkQueue.h ================================================ #ifndef _IO80211WORKQUEUE_H #define _IO80211WORKQUEUE_H #include #include // This is necessary, because even the latest Xcode does not support properly targeting 11.0. #ifndef __IO80211_TARGET #error "Please define __IO80211_TARGET to the requested version" #endif class IO80211WorkQueue : public IOWorkLoop { OSDeclareDefaultStructors( IO80211WorkQueue ) public: virtual IOThread getThread() const APPLE_KEXT_OVERRIDE; virtual void enableAllInterrupts() const APPLE_KEXT_OVERRIDE; virtual void disableAllInterrupts() const APPLE_KEXT_OVERRIDE; virtual IOReturn runAction(Action action, OSObject *target, void *arg0 = NULL, void *arg1 = NULL, void *arg2 = NULL, void *arg3 = NULL) APPLE_KEXT_OVERRIDE; virtual int commandSleep(void *,unsigned long long); virtual void commandWakeup(void *); static IO80211WorkQueue * workQueue(); public: uint8_t filter[0x50]; }; #endif ================================================ FILE: include/Airport/IOSkywalkEthernetInterface.h ================================================ #ifndef IOSkywalkEthernetInterface_h #define IOSkywalkEthernetInterface_h #include "IOSkywalkNetworkInterface.h" struct nicproxy_limits_info_s; struct nicproxy_info_s; class IOSkywalkEthernetInterface : public IOSkywalkNetworkInterface { OSDeclareAbstractStructors( IOSkywalkEthernetInterface ) public: struct RegistrationInfo { uint8_t pad[304]; } __attribute__((packed)); public: virtual void free() APPLE_KEXT_OVERRIDE; virtual bool init(OSDictionary *) APPLE_KEXT_OVERRIDE; virtual IOReturn newUserClient( task_t owningTask, void * securityID, UInt32 type, OSDictionary * properties, LIBKERN_RETURNS_RETAINED IOUserClient ** handler ) APPLE_KEXT_OVERRIDE; virtual IOReturn setPowerState( unsigned long powerStateOrdinal, IOService * whatDevice ) APPLE_KEXT_OVERRIDE; virtual IOReturn enable(UInt) APPLE_KEXT_OVERRIDE; virtual SInt32 initBSDInterfaceParameters(ifnet_init_eparams *,sockaddr_dl **) APPLE_KEXT_OVERRIDE; virtual bool prepareBSDInterface(ifnet_t,UInt) APPLE_KEXT_OVERRIDE; virtual IOReturn processBSDCommand(ifnet_t,UInt,void *) APPLE_KEXT_OVERRIDE; virtual void *getPacketTapInfo(UInt *,UInt *) APPLE_KEXT_OVERRIDE; virtual void enableNetworkWake(UInt) APPLE_KEXT_OVERRIDE; virtual UInt getMaxTransferUnit(void) APPLE_KEXT_OVERRIDE; virtual UInt getMinPacketSize(void) APPLE_KEXT_OVERRIDE; virtual void *getInterfaceFamily(void) APPLE_KEXT_OVERRIDE; virtual void *getInterfaceSubFamily(void) APPLE_KEXT_OVERRIDE; virtual UInt getInitialMedia(void) APPLE_KEXT_OVERRIDE; virtual const char *getBSDNamePrefix(void) APPLE_KEXT_OVERRIDE; virtual IOReturn registerNetworkInterfaceWithLogicalLink(IOSkywalkEthernetInterface::RegistrationInfo const*, IOSkywalkLogicalLink*, IOSkywalkPacketBufferPool*, IOSkywalkPacketBufferPool*, UInt); virtual void getHardwareAddress(ether_addr *); virtual void setHardwareAddress(ether_addr *); virtual void setLinkLayerAddress(ether_addr *); virtual bool configureMulticastFilter(UInt,ether_addr const*,UInt); virtual bool setMulticastAddresses(ether_addr const*,UInt); virtual void setAllMulticastModeEnable(bool); virtual IOReturn setPromiscuousModeEnable(bool, UInt); virtual void reportNicProxyLimits(nicproxy_limits_info_s); virtual void hwConfigNicProxyData(nicproxy_info_s *); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 0 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 1 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 2 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 3 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 4 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 5 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 6 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 7 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 8 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 9 ); OSMetaClassDeclareReservedUnused( IOSkywalkEthernetInterface, 10 ); public: bool initRegistrationInfo(IOSkywalkEthernetInterface::RegistrationInfo*, unsigned int, unsigned long); bool registerEthernetInterface(IOSkywalkEthernetInterface::RegistrationInfo const*, IOSkywalkPacketQueue**, unsigned int, IOSkywalkPacketBufferPool*, IOSkywalkPacketBufferPool*, unsigned int); public: void *vptr; uint8_t pad1[0x30]; struct ExpansionData { RegistrationInfo *fRegistrationInfo; ifnet_t fBSDInterface; }; ExpansionData *mExpansionData2; }; static_assert(__offsetof(IOSkywalkEthernetInterface, mExpansionData2) == 0x108, "Invalid class size"); static_assert(sizeof(IOSkywalkEthernetInterface) == 0x110, "Invalid class size"); #endif /* IOSkywalkEthernetInterface_h */ ================================================ FILE: include/Airport/IOSkywalkInterface.h ================================================ // // IOSkywalkInterface.h // itlwm // // Created by qcwap on 2023/6/7. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef IOSkywalkInterface_h #define IOSkywalkInterface_h class IOSkywalkInterface : public IOService { OSDeclareAbstractStructors(IOSkywalkInterface) public: virtual void free() APPLE_KEXT_OVERRIDE; virtual bool init(OSDictionary *) APPLE_KEXT_OVERRIDE; virtual bool willTerminate( IOService * provider, IOOptionBits options ) APPLE_KEXT_OVERRIDE; virtual bool didTerminate( IOService * provider, IOOptionBits options, bool * defer ) APPLE_KEXT_OVERRIDE; virtual bool handleOpen( IOService * forClient, IOOptionBits options, void * arg ) APPLE_KEXT_OVERRIDE; virtual void handleClose( IOService * forClient, IOOptionBits options ) APPLE_KEXT_OVERRIDE; virtual bool handleIsOpen( const IOService * forClient ) const APPLE_KEXT_OVERRIDE; virtual IOReturn enable( IOOptionBits options ) = 0; virtual IOReturn disable( IOOptionBits options ) = 0; virtual IOReturn clientConnectWithTask( task_t task, IOService * forClient, IOOptionBits options ); virtual void clientDisconnect( IOService * forClient, IOOptionBits options ); virtual bool isTerminating(void); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 0 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 1 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 2 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 3 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 4 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 5 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 6 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 7 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 8 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 9 ); OSMetaClassDeclareReservedUnused( IOSkywalkInterface, 10 ); public: uint8_t filter[0xB0 - 136]; }; static_assert(sizeof(IOSkywalkInterface) == 0xB0, "Invalid class size"); #endif /* IOSkywalkInterface_h */ ================================================ FILE: include/Airport/IOSkywalkLegacyEthernetInterface.h ================================================ // // IOSkywalkLegacyEthernetInterface.h // itlwm // // Created by qcwap on 2023/6/19. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef IOSkywalkLegacyEthernetInterface_h #define IOSkywalkLegacyEthernetInterface_h #include #include class IOSkywalkLegacyEthernetInterface : public IOEthernetInterface { OSDeclareDefaultStructors(IOSkywalkLegacyEthernetInterface) public: virtual void free() APPLE_KEXT_OVERRIDE; virtual OSObject * getProperty( const OSSymbol * aKey) const APPLE_KEXT_OVERRIDE; virtual OSObject * copyProperty( const OSSymbol * aKey) const APPLE_KEXT_OVERRIDE; virtual bool serializeProperties( OSSerialize * serialize ) const APPLE_KEXT_OVERRIDE; virtual IOReturn setProperties( OSObject * properties ) APPLE_KEXT_OVERRIDE; virtual bool init( IONetworkController * controller ) APPLE_KEXT_OVERRIDE; virtual const char * getNamePrefix() const APPLE_KEXT_OVERRIDE; virtual bool controllerDidOpen(IONetworkController * controller) APPLE_KEXT_OVERRIDE; virtual void controllerWillClose(IONetworkController * controller) APPLE_KEXT_OVERRIDE; virtual ifnet_t getIfnet( void ) const APPLE_KEXT_OVERRIDE; virtual IOReturn attachToDataLinkLayer( IOOptionBits options, void * parameter ) APPLE_KEXT_OVERRIDE; virtual void detachFromDataLinkLayer( IOOptionBits options, void * parameter ) APPLE_KEXT_OVERRIDE; public: uint8_t filter[0x160]; }; #endif /* IOSkywalkLegacyEthernetInterface_h */ ================================================ FILE: include/Airport/IOSkywalkLogicalLink.h ================================================ // // IOSkywalkLogicalLink.h // itlwm // // Created by qcwap on 2023/6/12. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef IOSkywalkLogicalLink_h #define IOSkywalkLogicalLink_h class IOSkywalkLogicalLink : public IOService { OSDeclareAbstractStructors(IOSkywalkLogicalLink) public: public: }; #endif /* IOSkywalkLogicalLink_h */ ================================================ FILE: include/Airport/IOSkywalkNetworkInterface.h ================================================ // // IOSkywalkNetworkInterface.h // itlwm // // Created by qcwap on 2023/6/7. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef IOSkywalkNetworkInterface_h #define IOSkywalkNetworkInterface_h #include #include "IOSkywalkInterface.h" typedef UInt if_link_status; class IOSkywalkPacketQueue; class IOSkywalkLogicalLink; class IOSkywalkPacketBufferPool; class IOSkywalkNetworkInterface : public IOSkywalkInterface { OSDeclareAbstractStructors( IOSkywalkNetworkInterface ) public: struct RegistrationInfo { uint8_t pad[304]; } __attribute__((packed)); struct IOSkywalkTSOOptions; public: virtual void free() APPLE_KEXT_OVERRIDE; virtual bool init(OSDictionary *) APPLE_KEXT_OVERRIDE; virtual void stop(IOService *) APPLE_KEXT_OVERRIDE; virtual void joinPMtree( IOService * driver ) APPLE_KEXT_OVERRIDE; virtual IOReturn setAggressiveness( unsigned long type, unsigned long newLevel ) APPLE_KEXT_OVERRIDE; virtual IOReturn enable(UInt) APPLE_KEXT_OVERRIDE; virtual IOReturn disable(UInt) APPLE_KEXT_OVERRIDE; virtual SInt32 initBSDInterfaceParameters(ifnet_init_eparams *,sockaddr_dl **) = 0; virtual bool prepareBSDInterface(ifnet_t,UInt); virtual void finalizeBSDInterface(ifnet_t,UInt); virtual ifnet_t getBSDInterface(void); virtual void setBSDName(char const*); virtual const char *getBSDName(void); virtual IOReturn processBSDCommand(ifnet_t,UInt,void *); virtual IOReturn processInterfaceCommand(ifdrv *); virtual IOReturn interfaceAdvisoryEnable(bool); virtual SInt32 setInterfaceEnable(bool); virtual SInt32 setRunningState(bool); virtual IOReturn handleChosenMedia(UInt); virtual void *getSupportedMediaArray(UInt *,UInt *); virtual void *getPacketTapInfo(UInt *,UInt *); virtual UInt getUnsentDataByteCount(UInt *,UInt *,UInt); virtual UInt32 getSupportedWakeFlags(UInt *); virtual void enableNetworkWake(UInt); virtual void calculateRingSizeForQueue(IOSkywalkPacketQueue const*,UInt *); virtual UInt getMaxTransferUnit(void); virtual void setMaxTransferUnit(UInt); virtual UInt getMinPacketSize(void); virtual UInt getHardwareAssists(void); virtual void setHardwareAssists(UInt,UInt); virtual void *getInterfaceFamily(void); virtual void *getInterfaceSubFamily(void); virtual UInt getInitialMedia(void); virtual UInt getFeatureFlags(void); virtual UInt getTxDataOffset(void); virtual UInt captureInterfaceState(UInt); virtual void restoreInterfaceState(UInt); virtual void setMTU(UInt); virtual bool bpfTap(UInt,UInt); virtual const char *getBSDNamePrefix(void); virtual UInt getBSDUnitNumber(void); virtual const char *classNameOverride(void); virtual void deferBSDAttach(bool); virtual void reportDetailedLinkStatus(if_link_status const*); virtual IOReturn registerNetworkInterfaceWithLogicalLink(IOSkywalkNetworkInterface::RegistrationInfo const*,IOSkywalkLogicalLink *,IOSkywalkPacketBufferPool *,IOSkywalkPacketBufferPool *,UInt); virtual IOReturn deregisterLogicalLink(void); virtual UInt getTSOOptions(IOSkywalkNetworkInterface::IOSkywalkTSOOptions *); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 0); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 1); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 2); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 3); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 4); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 5); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 6); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 7); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 8); OSMetaClassDeclareReservedUnused( IOSkywalkNetworkInterface, 9); public: void reportLinkStatus(unsigned int, unsigned int); public: void *vptr; struct ExpansionData { RegistrationInfo *fRegistrationInfo; ifnet_t fBSDInterface; }; ExpansionData *mExpansionData; uint8_t pad[2 * 8]; }; static_assert(sizeof(IOSkywalkNetworkInterface) == 0xD0, "Invalid class size"); #endif /* IOSkywalkNetworkInterface_h */ ================================================ FILE: include/Airport/IOSkywalkNetworkPacket.h ================================================ // // IOSkywalkNetworkPacket.h // itlwm // // Created by qcwap on 2023/6/13. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef IOSkywalkInterface_h #define IOSkywalkInterface_h class IOSkywalkPacketBufferPool; class IOSkywalkPacketDescriptor; class IOSkywalkPacketBuffer; class IOSkywalkPacketQueue; class IOSkywalkNetworkPacket : public IOService { OSDeclareAbstractStructors(IOSkywalkNetworkPacket) public: virtual void free() APPLE_KEXT_OVERRIDE; virtual bool initWithPool(IOSkywalkPacketBufferPool *,IOSkywalkPacketDescriptor *,uint); virtual void *getPacketBuffers(IOSkywalkPacketBuffer **,uint); virtual UInt getPacketBufferCount(void); virtual IOSkywalkPacketDescriptor *getMemoryDescriptor(void); virtual void setDataLength(uint); virtual UInt getDataLength(void); virtual void setDataOffset(unsigned short); virtual unsigned short getDataOffset(void); virtual void setDataOffsetAndLength(unsigned short,uint); virtual void setDataOff(long long); virtual long long getDataOff(void); virtual void setDataOffAndLen(long long,unsigned long); virtual void *getDataVirtualAddress(void); virtual void *getDataIOVirtualAddress(void); virtual bool prepareWithQueue(IOSkywalkPacketQueue *,uint,uint); virtual bool prepare(IOSkywalkPacketQueue *,unsigned long long,uint); virtual void completeWithQueue(IOSkywalkPacketQueue *,uint,uint); virtual void complete(IOSkywalkPacketQueue *,uint); virtual UInt getPacketType(void); virtual void setWakeFlag(void); virtual UInt getTraceID(void); virtual void setTraceID(UInt); virtual void traceEvent(uint); virtual void *generateTraceTag(IOSkywalkPacketQueue *); virtual void *acquireWithPacketHandle(unsigned long long,uint); virtual void disposePacket(void); public: uint8_t filter[0x78]; }; #endif /* IOSkywalkInterface_h */ ================================================ FILE: include/Airport/IOSkywalkPacketBufferPool.h ================================================ // // IOSkywalkPacketBufferPool.h // itlwm // // Created by qcwap on 2023/6/15. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef IOSkywalkPacketBufferPool_h #define IOSkywalkPacketBufferPool_h #include class IOSkywalkMemorySegment; class IOSkywalkMemorySegmentDescriptor; class IOSkywalkPacket; class IOSkywalkPacketBuffer; class IOSkywalkPacketDescriptor; class IOSkywalkPacketBufferDescriptor; class IOSkywalkPacketBufferPool : public OSObject { OSDeclareDefaultStructors(IOSkywalkPacketBufferPool) public: struct PoolOptions { uint32_t packetCount; uint32_t bufferCount; uint32_t bufferSize; uint32_t maxBuffersPerPacket; uint32_t memorySegmentSize; uint32_t poolFlags; uint64_t pad; }; public: virtual void free() APPLE_KEXT_OVERRIDE; virtual bool initWithName(char const*,void *,uint,IOSkywalkPacketBufferPool::PoolOptions const*); virtual bool initWithName(char const*,OSObject *,uint,IOSkywalkPacketBufferPool::PoolOptions const*); virtual bool allocatePacket(IOSkywalkPacket **,uint); virtual bool allocatePacket(uint,IOSkywalkPacket **,uint); virtual bool allocatePackets(uint,uint *,IOSkywalkPacket **,uint); virtual void deallocatePacket(IOSkywalkPacket *); virtual void deallocatePackets(IOSkywalkPacket **,uint); virtual void deallocatePacketList(IOSkywalkPacket *); virtual void deallocatePacketChain(unsigned long long); virtual bool allocatePacketBuffer(IOSkywalkPacketBuffer **,uint); virtual bool allocatePacketBuffers(uint *,IOSkywalkPacketBuffer **,uint); virtual void deallocatePacketBuffer(IOSkywalkPacketBuffer *); virtual void deallocatePacketBuffers(IOSkywalkPacketBuffer **,uint); virtual bool newPacket(IOSkywalkPacketDescriptor *,IOSkywalkPacket **); virtual bool newPacketBuffer(IOSkywalkPacketBufferDescriptor *,IOSkywalkPacketBuffer **); virtual bool newMemorySegment(IOSkywalkMemorySegmentDescriptor *,IOSkywalkMemorySegment **); public: static IOSkywalkPacketBufferPool *withName(char const*,OSObject *,uint,IOSkywalkPacketBufferPool::PoolOptions const*); public: uint8_t filter[0xB8]; }; #endif /* IOSkywalkPacketBufferPool_h */ ================================================ FILE: include/Airport/apple80211_ioctl.h ================================================ /* * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef _APPLE80211_IOCTL_H_ #define _APPLE80211_IOCTL_H_ #include #include #include #include #include #include // This is necessary, because even the latest Xcode does not support properly targeting 11.0. #ifndef __IO80211_TARGET #error "Please define __IO80211_TARGET to the requested version" #endif #include "apple80211_var.h" struct apple80211req { char req_if_name[IFNAMSIZ]; // 16 bytes int req_type; // 4 bytes int req_val; // 4 bytes u_int32_t req_len; // 4 bytes void *req_data; // 4 bytes }; #if __IO80211_TARGET >= __MAC_10_15 #define SIOCSA80211 2150656456 #define SIOCGA80211 3224398281 #else #define SIOCSA80211 2150132168 #define SIOCGA80211 3223873993 #endif #define APPLE80211_AWDL_CAP_CCA_STATS 2 #define APPLE80211_AWDL_CAP_SEC_PAYLOAD 0x100000000 // req_type #define APPLE80211_IOC_SSID 1 // req_type #define APPLE80211_IOC_AUTH_TYPE 2 // req_type #define APPLE80211_AUTH_TYPE_UNICAST 1 // req_val, SIOCGA80211 only #define APPLE80211_AUTH_TYPE_MULTICAST 2 // req_val, SIOCGA80211 only #define APPLE80211_IOC_CIPHER_KEY 3 // req_type #define APPLE80211_CIPHER_KEY_UNICAST 1 // req_val #define APPLE80211_CIPHER_KEY_MULICAST 2 // req_val #define APPLE80211_IOC_CHANNEL 4 // req_type #define APPLE80211_IOC_POWERSAVE 5 // req_type #define APPLE80211_IOC_PROTMODE 6 // req_type #define APPLE80211_IOC_TXPOWER 7 // req_type #define APPLE80211_IOC_RATE 8 // req_type #define APPLE80211_IOC_BSSID 9 // req_type #define APPLE80211_IOC_SCAN_REQ 10 // req_type #define APPLE80211_IOC_SCAN_RESULT 11 // req_type #define APPLE80211_IOC_CARD_CAPABILITIES 12 // req_type #define APPLE80211_IOC_STATE 13 // req_type (apple80211_state) #define APPLE80211_IOC_PHY_MODE 14 // req_type (apple80211_phymode) #define APPLE80211_IOC_OP_MODE 15 // req_type (apple80211_opmode) #define APPLE80211_IOC_RSSI 16 // req_type #define APPLE80211_IOC_NOISE 17 // req_type #define APPLE80211_IOC_INT_MIT 18 #define APPLE80211_IOC_INT_MIT_OFF 1 // req_val #define APPLE80211_IOC_INT_MIT_ON 2 // req_val // card power #define APPLE80211_IOC_POWER 19 // req_type #define APPLE80211_IOC_ASSOCIATE 20 // req_type #define APPLE80211_IOC_ASSOCIATE_RESULT 21 // req_type #define APPLE80211_IOC_DISASSOCIATE 22 // req_type #define APPLE80211_IOC_STATUS_DEV_NAME 23 // req_type #define APPLE80211_IOC_IBSS_MODE 24 // req_type #define APPLE80211_IOC_IBSS_MODE_START 1 // req_val #define APPLE80211_IOC_IBSS_MODE_STOP 2 // req_val #define APPLE80211_IOC_HOST_AP_MODE 25 // req_type #define APPLE80211_IOC_HOST_AP_MODE_START 1 // req_val #define APPLE80211_IOC_HOST_AP_MODE_STOP 2 // req_val #define APPLE80211_IOC_AP_MODE 26 // req_type (apple80211_apmode) #define APPLE80211_IOC_SUPPORTED_CHANNELS 27 // req_type #define APPLE80211_IOC_LOCALE 28 // req_type #define APPLE80211_IOC_DEAUTH 29 // req_type #define APPLE80211_IOC_COUNTERMEASURES 30 // req_type #define APPLE80211_IOC_FRAG_THRESHOLD 31 // req_type #define APPLE80211_IOC_RATE_SET 32 // req_type #define APPLE80211_IOC_SHORT_SLOT 33 // req_type #define APPLE80211_IOC_MULTICAST_RATE 34 // req_type #define APPLE80211_IOC_SHORT_RETRY_LIMIT 35 // req_type #define APPLE80211_IOC_LONG_RETRY_LIMIT 36 // req_type #define APPLE80211_IOC_TX_ANTENNA 37 // req_type #define APPLE80211_IOC_RX_ANTENNA 38 // req_type #define APPLE80211_IOC_ANTENNA_DIVERSITY 39 // req_type #define APPLE80211_IOC_ROM 40 // req_type #define APPLE80211_IOC_DTIM_INT 41 // req_type #define APPLE80211_IOC_STATION_LIST 42 // req_type #define APPLE80211_IOC_DRIVER_VERSION 43 // req_type #define APPLE80211_IOC_HARDWARE_VERSION 44 // req_type #define APPLE80211_IOC_RAND 45 // req_type #define APPLE80211_IOC_RSN_IE 46 // req_type #define APPLE80211_IOC_BACKGROUND_SCAN 47 // req_type #define APPLE80211_IOC_AP_IE_LIST 48 // req_type #define APPLE80211_IOC_STATS 49 // req_type #define APPLE80211_IOC_ASSOCIATION_STATUS 50 // req_type #define APPLE80211_IOC_COUNTRY_CODE 51 // req_type #define APPLE80211_IOC_DEBUG_FLAGS 52 // req_type #define APPLE80211_IOC_LAST_RX_PKT_DATA 53 // req_type #define APPLE80211_IOC_RADIO_INFO 54 // req_type #define APPLE80211_IOC_GUARD_INTERVAL 55 // req_type #define APPLE80211_IOC_MIMO_POWERSAVE 56 // req_type #define APPLE80211_IOC_MCS 57 // req_type #define APPLE80211_IOC_RIFS 58 // req_type #define APPLE80211_IOC_LDPC 59 // req_type #define APPLE80211_IOC_MSDU 60 // req_type #define APPLE80211_IOC_MPDU 61 // req_type #define APPLE80211_IOC_BLOCK_ACK 62 // req_type #define APPLE80211_IOC_PLS 63 // req_type #define APPLE80211_IOC_PSMP 64 // req_type #define APPLE80211_IOC_PHY_SUB_MODE 65 // req_type #define APPLE80211_IOC_MCS_INDEX_SET 66 // req_type #define APPLE80211_IOC_CACHE_THRESH_BCAST 67 // req_type #define APPLE80211_IOC_CACHE_THRESH_DIRECT 68 // req_type #define APPLE80211_IOC_WOW_PARAMETERS 69 // req_type #define APPLE80211_IOC_WOW_ENABLED 70 // req_type #define APPLE80211_IOC_40MHZ_INTOLERANT 71 // req_type #define APPLE80211_IOC_PID_LOCK 72 #define APPLE80211_IOC_STA_IE_LIST 73 #define APPLE80211_IOC_STA_AUTHORIZE 74 #define APPLE80211_IOC_STA_DISASSOCIATE 75 #define APPLE80211_IOC_STA_DEAUTH 76 #define APPLE80211_IOC_RSN_CONF 77 #define APPLE80211_IOC_KEY_RSC 78 #define APPLE80211_IOC_STA_STATS 79 #define APPLE80211_IOC_ROAM_THRESH 80 #define APPLE80211_IOC_VENDOR_DBG_FLAGS 81 #define APPLE80211_IOC_CACHE_AGE_THRESH 82 #define APPLE80211_IOC_PMK_CACHE 83 #define APPLE80211_IOC_LINK_QUAL_EVENT_PARAMS 84 #define APPLE80211_IOC_IE 85 #define APPLE80211_IOC_SCAN_REQ_MULTIPLE 86 #define APPLE80211_IOC_BTCOEX_MODE 87 #define APPLE80211_IOC_WOW_TEST 88 #define APPLE80211_IOC_CLEAR_PMK_CACHE 89 #define APPLE80211_IOC_SCANCACHE_CLEAR 90 #define APPLE80211_IOC_P2P_ENABLE 91 #define APPLE80211_IOC_P2P_LISTEN 92 #define APPLE80211_IOC_P2P_SCAN 93 #define APPLE80211_IOC_VIRTUAL_IF_CREATE 94 #define APPLE80211_IOC_VIRTUAL_IF_DELETE 95 #define APPLE80211_IOC_VIRTUAL_IF_ROLE 96 #define APPLE80211_IOC_VIRTUAL_IF_PARENT 97 #define APPLE80211_IOC_P2P_GO_CONF 98 #define APPLE80211_IOC_P2P_NOA_LIST 99 #define APPLE80211_IOC_P2P_OPP_PS 100 #define APPLE80211_IOC_P2P_CT_WINDOW 101 #define APPLE80211_IOC_BT_COEX_FLAGS 102 #define APPLE80211_IOC_CURRENT_NETWORK 103 #define APPLE80211_IOC_BT_POWER 104 #define APPLE80211_IOC_AVAILABILITY 105 #define APPLE80211_IOC_RSSI_BOUNDS 106 #define APPLE80211_IOC_ROAM 107 #define APPLE80211_IOC_TX_CHAIN_POWER 108 #define APPLE80211_IOC_CDD_MODE 109 #define APPLE80211_IOC_LAST_BCAST_SCAN_TIME 110 #define APPLE80211_IOC_THERMAL_THROTTLING 111 #define APPLE80211_IOC_FACTORY_MODE 112 #define APPLE80211_IOC_REASSOCIATE 113 #define APPLE80211_IOC_POWER_DEBUG_INFO 115 #define APPLE80211_IOC_AWDL_SYNC_PARAMS 116 #define APPLE80211_IOC_AWDL_SYNC_ENABLED 117 #define APPLE80211_IOC_AWDL_EXTENSION_STATE_MACHINE_PARAMETERS 118 #define APPLE80211_IOC_AWDL_SERVICE_PARAMS 119 #define APPLE80211_IOC_AWDL_PEER_SERVICE_REQUEST 120 #define APPLE80211_IOC_AWDL_ELECTION_ALGORITHM_ENABLED 121 #define APPLE80211_IOC_AWDL_ELECTION_ID 122 #define APPLE80211_IOC_AWDL_MAX_TREE_DEPTH 123 #define APPLE80211_IOC_AWDL_GUARD_TIME 124 #define APPLE80211_IOC_AWDL_BSSID 125 #define APPLE80211_IOC_AWDL_ELECTION_METRIC 126 #define APPLE80211_IOC_AWDL_AVAILABILITY_WINDOW_AP_ALIGNMENT 127 #define APPLE80211_IOC_AWDL_SYNC_FRAME_AP_BEACON_ALIGNMENT 128 #define APPLE80211_IOC_AWDL_SYNCHRONIZATION_CHANNEL_SEQUENCE 129 #define APPLE80211_IOC_PEER_CACHE_MAXIMUM_SIZE 130 #define APPLE80211_IOC_AWDL_OUI 131 #define APPLE80211_IOC_AWDL_MASTER_CHANNEL 132 #define APPLE80211_IOC_AWDL_TOP_MASTER 133 #define APPLE80211_IOC_AWDL_SYNC_STATE 134 #define APPLE80211_IOC_AWDL_ELECTION_RSSI_THRESHOLDS 135 #define APPLE80211_IOC_AWDL_PRESENCE_MODE 136 #define APPLE80211_IOC_AWDL_ELECTION_MASTER_COUNTS 137 #define APPLE80211_IOC_AWDL_PERIODIC_SYNC_FRAME_PACKET_LIFETIME 138 #define APPLE80211_IOC_AWDL_MASTER_MODE_SYNC_FRAME_PERIOD 139 #define APPLE80211_IOC_AWDL_NON_ELECTION_MASTER_MODE_SYNC_FRAME_PERIOD 140 #define APPLE80211_IOC_AWDL_EXPLICIT_AVAILABILITY_WINDOW_EXTENSION_OPT_OUT 141 #define APPLE80211_IOC_AWDL_GET_AWDL_MASTER_DATABASE 142 #define APPLE80211_IOC_PEER_CACHE_CONTROL 143 #define APPLE80211_IOC_AWDL_BATTERY_LEVEL 144 #define APPLE80211_IOC_AWDL_BT_COEX_AW_PROTECTED_PERIOD_LENGTH 145 #define APPLE80211_IOC_AWDL_BT_COEX_AGREEMENT 146 #define APPLE80211_IOC_AWDL_BT_COEX_AGREEMENT_ENABLED 147 #define APPLE80211_IOC_AWDL_STRATEGY 148 #define APPLE80211_IOC_AWDL_OOB_REQUEST 149 #define APPLE80211_IOC_AWDL_MAX_NO_MASTER_PERIODS 150 #define APPLE80211_IOC_AWDL_SYNC_FRAME_TEMPLATE 151 #define APPLE80211_IOC_LOG_FLAGS 152 #define APPLE80211_IOC_PEER_STATS 153 #define APPLE80211_IOC_HT_CAPABILITY 154 #define APPLE80211_IOC_AWDL_ELECTION_PARAMS 155 #define APPLE80211_IOC_LINK_CHANGED_EVENT_DATA 156 #define APPLE80211_IOC_GET_DEBUG_INFO 157 #define APPLE80211_IOC_AWDL_DEVICE_CAPABILITIES 158 #define APPLE80211_IOC_AWDL_RSSI_MEASUREMENT_REQUEST 159 #define APPLE80211_IOC_AWDL_AES_KEY 160 #define APPLE80211_IOC_AWDL_SCAN_RESERVED_TIME 161 #define APPLE80211_IOC_AWDL_CTL 162 #define APPLE80211_IOC_AWDL_SOCIAL_TIME_SLOTS 163 #define APPLE80211_IOC_AWDL_PEER_TRAFFIC_REGISTRATION 164 #define APPLE80211_IOC_EXTENDED_STATS 165 #define APPLE80211_IOC_BEACON_PERIOD 166 #define APPLE80211_IOC_AWDL_FORCED_ROAM_CONFIG 167 #define APPLE80211_IOC_AWDL_QUIET 168 #define APPLE80211_IOC_ACL_POLICY 169 #define APPLE80211_IOC_ACL_ADD 170 #define APPLE80211_IOC_ACL_REMOVE 171 #define APPLE80211_IOC_ACL_FLUSH 172 #define APPLE80211_IOC_ACL_LIST 173 #define APPLE80211_IOC_CHAIN_ACK 174 #define APPLE80211_IOC_DESENSE 175 #define APPLE80211_IOC_OFFLOAD_SCANNING 176 #define APPLE80211_IOC_OFFLOAD_RSN 177 #define APPLE80211_IOC_OFFLOAD_COUNTRY_CODE 178 #define APPLE80211_IOC_OFFLOAD_KEEPALIVE_L2 179 #define APPLE80211_IOC_OFFLOAD_ARP_NDP 180 #define APPLE80211_IOC_VHT_MCS_INDEX_SET 181 #define APPLE80211_IOC_DWDS 182 #define APPLE80211_IOC_INTERRUPT_STATS 183 #define APPLE80211_IOC_INTERRUPT_STATS_RESET 184 #define APPLE80211_IOC_TIMER_STATS 185 #define APPLE80211_IOC_TIMER_STATS_RESET 186 #define APPLE80211_IOC_OFFLOAD_STATS 187 #define APPLE80211_IOC_OFFLOAD_STATS_RESET 188 #define APPLE80211_IOC_OFFLOAD_BEACONS 189 #define APPLE80211_IOC_ROAMING 190 #define APPLE80211_IOC_OFFLOAD_ARP 191 #define APPLE80211_IOC_OFFLOAD_NDP 192 #define APPLE80211_IOC_OFFLOAD_SCAN 193 #define APPLE80211_IOC_DESENSE_LEVEL 194 #define APPLE80211_IOC_MCS_VHT 195 #define APPLE80211_IOC_TX_NSS 196 #define APPLE80211_IOC_GAS_REQ 197 #define APPLE80211_IOC_GAS_START 198 #define APPLE80211_IOC_GAS_SET_PEER 199 #define APPLE80211_IOC_GAS_RESULTS 200 #define APPLE80211_IOC_AWDL_BTLE_PEER_INDICATION 201 #define APPLE80211_IOC_AWDL_BTLE_STATE_PARAMS 202 #define APPLE80211_IOC_AWDL_PEER_DATABASE 203 #define APPLE80211_IOC_AWDL_BTLE_ENABLE_SYNC_WITH_PARAMS 204 #define APPLE80211_IOC_AWDL_SECONDARY_MASTER_CHANNEL 205 #define APPLE80211_IOC_PHY_STATS 206 #define APPLE80211_IOC_CHANNELS_INFO 207 #define APPLE80211_IOC_AWDL_AF_TX_MODE 208 #define APPLE80211_IOC_ERROR_STRING 209 #define APPLE80211_IOC_ERROR_NO 210 #define APPLE80211_IOC_AWDL_PIGGYBACK_SCAN_REQ 211 #define APPLE80211_IOC_AWDL_PRIVATE_ELECTION_ID 212 #define APPLE80211_IOC_AWDL_MIN_RATE 213 #define APPLE80211_IOC_VHT_CAPABILITY 214 #define APPLE80211_IOC_BGSCAN_CACHE_RESULTS 215 #define APPLE80211_IOC_ROAM_PROFILE 216 #define APPLE80211_IOC_AWDL_OPER_MODE 217 #define APPLE80211_IOC_RESTORE_DEFAULTS 218 #define APPLE80211_IOC_AWDL_ENCRYPTION_KEYS 219 #define APPLE80211_IOC_AWDL_ENCRYPTION_TYPE 220 #define APPLE80211_IOC_BTCOEX_PROFILES 221 #define APPLE80211_IOC_BTCOEX_CONFIG 222 #define APPLE80211_IOC_AWDL_STATISTICS 223 #define APPLE80211_IOC_AWDL_ENABLE_ROAMING 224 #define APPLE80211_IOC_AWDL_OOB_AUTO_REQUEST 225 #define APPLE80211_IOC_AWDL_TXCAL_PERIOD 226 #define APPLE80211_IOC_CHIP_COUNTER_STATS 227 #define APPLE80211_IOC_DBG_GUARD_TIME_PARAMS 228 #define APPLE80211_IOC_AWDL_AWDL_ADVERTISERS 229 #define APPLE80211_IOC_LEAKY_AP_STATS_MODE 230 #define APPLE80211_IOC_CAPTURE 231 #define APPLE80211_IOC_LEAKY_AP_STATS 232 #define APPLE80211_IOC_AWDL_BLOCK_SET_COMMANDS 233 #define APPLE80211_IOC_LEAKY_AP_AWD_MODE 234 #define APPLE80211_IOC_BTCOEX_OPTIONS 235 #define APPLE80211_IOC_FORCE_SYNC_TO_PEER 236 #define APPLE80211_IOC_COUNTRY_CHANNELS 237 #define APPLE80211_IOC_PRIVATE_MAC 238 #define APPLE80211_IOC_RESET_CHIP 239 #define APPLE80211_IOC_CRASH 240 #define APPLE80211_IOC_RANGING_ENABLE 241 #define APPLE80211_IOC_RANGING_START 242 #define APPLE80211_IOC_RANGING_AUTHENTICATE 243 #define APPLE80211_IOC_AWDL_PREFERRED_CHANNELS 244 #define APPLE80211_IOC_LEAKY_AP_SSID_STATS 245 #define APPLE80211_IOC_AWDL_RSDB_CAPS 246 #define APPLE80211_IOC_AWDL_DEV_STATS 247 #define APPLE80211_IOC_LAST_ASSOC_HISTORY 248 #define APPLE80211_IOC_AWDL_COMMON_CHANNEL 249 #define APPLE80211_IOC_AWDL_PEERS_INFO 250 #define APPLE80211_IOC_TKO_PARAMS 251 #define APPLE80211_IOC_TKO_DUMP 252 #define APPLE80211_IOC_AWDL_NEARBY_LOG_TRIGGER 253 #define APPLE80211_IOC_HW_SUPPORTED_CHANNELS 254 #define APPLE80211_IOC_BTCOEX_PROFILE 255 #define APPLE80211_IOC_BTCOEX_PROFILE_ACTIVE 256 #define APPLE80211_IOC_TRAP_INFO 257 #define APPLE80211_IOC_THERMAL_INDEX 258 #define APPLE80211_IOC_MAX_NSS_FOR_AP 259 #define APPLE80211_IOC_BTCOEX_2G_CHAIN_DISABLE 260 #define APPLE80211_IOC_POWER_BUDGET 261 #define APPLE80211_IOC_AWDL_DFSP_CONFIG 262 #define APPLE80211_IOC_AWDL_DFSP_UCSA_CONFIG 263 #define APPLE80211_IOC_SCAN_BACKOFF_REPORT 264 #define APPLE80211_IOC_OFFLOAD_TCPKA_ENABLE 265 #define APPLE80211_IOC_RANGING_CAPS 266 #define APPLE80211_IOC_SUPPRESS_SCANS 267 #define APPLE80211_IOC_HOST_AP_MODE_HIDDEN 336 #define APPLE80211_IOC_LQM_CONFIG 337 #define APPLE80211_IOC_AWDL_CCA 338 #define APPLE80211_IOC_TRAP_CRASHTRACER_MINI_DUMP 339 #define APPLE80211_IOC_AWDL_SIDECAR_STATISTICS 340 #define APPLE80211_IOC_AWDL_CAPABILITIES 341 #define APPLE80211_IOC_LLW_PARAMS 344 #define APPLE80211_IOC_HE_CAPABILITY 345 #define APPLE80211_IOC_SOFTAP_PARAMS 347 #define APPLE80211_IOC_SOFTAP_TRIGGER_CSA 349 #define APPLE80211_IOC_SOFTAP_STATS 350 #define APPLE80211_IOC_AWDL_SIDECAR_DIAGNOSTICS 351 #define APPLE80211_IOC_SOFTAP_WIFI_NETWORK_INFO_IE 352 #define APPLE80211_IOC_NSS 353 #define APPLE80211_IOC_CARD_SPECIFIC 0xffffffff // req_type // Kernel interface // Bump this value when structures change #define APPLE80211_VERSION 1 struct apple80211_ssid_data { u_int32_t version; u_int32_t ssid_len; u_int8_t ssid_bytes[APPLE80211_MAX_SSID_LEN]; }; struct apple80211_virt_if_create_data { uint32_t version; uint8_t mac[APPLE80211_ADDR_LEN]; uint16_t unk1; uint32_t role; uint8_t bsd_name[IFNAMSIZ]; } __attribute__((packed)); struct apple80211_virt_if_delete_data { uint32_t version; uint8_t bsd_name[IFNAMSIZ]; } __attribute__((packed)); struct apple80211_ht_capability { uint32_t version; uint8_t hc_id; /* element ID */ uint8_t hc_len; /* length in bytes */ uint16_t hc_cap; /* HT caps (see below) */ uint8_t hc_param; /* HT params (see below) */ uint8_t hc_mcsset[16]; /* supported MCS set */ uint16_t hc_extcap; /* extended HT capabilities */ uint32_t hc_txbf; /* txbf capabilities */ uint8_t hc_antenna; /* antenna capabilities */ } __attribute__((packed)); struct apple80211_vht_capability { uint32_t version; uint16_t cap; // 4 uint32_t unk1; // 6 uint16_t unk2; // 10 uint16_t unk3; // 12 uint16_t unk4; // 14 uint16_t unk5; // 16 uint16_t unk6; // 18 } __attribute__((packed)); struct apple80211_channel_data { u_int32_t version; struct apple80211_channel channel; }; struct apple80211_bssid_data { u_int32_t version; struct ether_addr bssid; }; #if __IO80211_TARGET >= __MAC_14_0 struct apple80211_capability_data { u_int32_t version; u_int8_t capabilities[14]; }; #else struct apple80211_capability_data { u_int32_t version; u_int8_t capabilities[11]; }; #endif struct apple80211_state_data { u_int32_t version; u_int32_t state; }; struct apple80211_rssi_data { u_int32_t version; u_int32_t num_radios; u_int32_t rssi_unit; int32_t rssi[APPLE80211_MAX_RADIO]; // control channel int32_t aggregate_rssi; // aggregate control channel rssi int32_t rssi_ext[APPLE80211_MAX_RADIO]; // extension channel rssi int32_t aggregate_rssi_ext; // aggregate extension channel rssi }; struct apple80211_power_data { u_int32_t version; u_int32_t num_radios; u_int32_t power_state[APPLE80211_MAX_RADIO]; }; struct apple80211_assoc_result_data { u_int32_t version; u_int32_t result; }; struct apple80211_assoc_status_data { u_int32_t version; u_int32_t status; }; struct apple80211_rate_data { u_int32_t version; u_int32_t num_radios; u_int32_t rate[APPLE80211_MAX_RADIO]; }; struct apple80211_status_dev_data { u_int32_t version; u_int8_t dev_name[MAXPATHLEN]; }; struct apple80211_powersave_data { u_int32_t version; u_int32_t powersave_level; }; struct apple80211_protmode_data { u_int32_t version; u_int32_t protmode; u_int32_t threshold; // bytes }; struct apple80211_txpower_data { u_int32_t version; u_int32_t txpower_unit; int32_t txpower; }; struct apple80211_phymode_data { u_int32_t version; u_int32_t phy_mode; // vector of supported phy modes u_int32_t active_phy_mode; // current active phy mode }; struct apple80211_opmode_data { u_int32_t version; u_int32_t op_mode; }; struct apple80211_noise_data { u_int32_t version; u_int32_t num_radios; u_int32_t noise_unit; int32_t noise[APPLE80211_MAX_RADIO]; // control channel int32_t aggregate_noise; // aggregate control channel noise int32_t noise_ext[APPLE80211_MAX_RADIO]; // extension channel noise int32_t aggregate_noise_ext; // aggregate extension channel noise }; struct apple80211_intmit_data { u_int32_t version; u_int32_t int_mit; }; struct apple80211_authtype_data { u_int32_t version; u_int32_t authtype_lower; // apple80211_authtype_lower u_int32_t authtype_upper; // apple80211_authtype_upper }; struct apple80211_sup_channel_data { u_int32_t version; u_int32_t num_channels; struct apple80211_channel supported_channels[APPLE80211_MAX_CHANNELS]; }; struct apple80211_roam_threshold_data { u_int32_t threshold; u_int32_t count; }; struct apple80211_locale_data { u_int32_t version; u_int32_t locale; }; struct apple80211_scan_data { u_int32_t version; u_int32_t bss_type; // apple80211_apmode struct ether_addr bssid; // target BSSID u_int32_t ssid_len; // length of the SSID u_int8_t ssid[APPLE80211_MAX_SSID_LEN]; // direct scan ssid or AirDrop scan ssid like "Air-xxxx" u_int32_t scan_type; // apple80211_scan_type u_int32_t phy_mode; // apple80211_phymode vector u_int16_t dwell_time; // time to spend on each channel (ms) u_int32_t rest_time; // time between scanning each channel (ms) u_int32_t num_channels; // 0 if not passing in channels struct apple80211_channel channels[APPLE80211_MAX_CHANNELS]; // channel list }; struct apple80211_scan_multiple_data { uint32_t version; uint32_t ap_mode; // apple80211_apmode uint32_t ssid_count; apple80211_ssid_data ssids[10]; uint32_t bssid_count; ether_addr bssids[16]; uint32_t scan_type; uint32_t phy_mode; uint32_t dwell_time; uint32_t rest_time; uint32_t num_channels; struct apple80211_channel channels[APPLE80211_MAX_CHANNELS]; uint16_t unk_2; }; static_assert(__offsetof(struct apple80211_scan_multiple_data, bssid_count) == 0x19c, "zxystd: BSSID offset invalid"); struct apple80211_link_changed_event_data { bool isLinkDown; // 0 uint32_t rssi; // 4 uint16_t snr; // 8 uint16_t nf; // 10 char cca; // 12 bool voluntary; // 16 uint32_t reason; // 20 }; struct apple80211_apmode_data { u_int32_t version; u_int32_t apmode; }; struct apple80211_assoc_data { u_int32_t version; u_int16_t ad_mode; // apple80211_apmode u_int16_t ad_auth_lower; // apple80211_authtype_lower u_int16_t ad_auth_upper; // apple80211_authtype_upper u_int32_t ad_ssid_len; u_int8_t ad_ssid[ APPLE80211_MAX_SSID_LEN ]; struct ether_addr ad_bssid; // prefer over ssid if not zeroed struct apple80211_key ad_key; uint16_t ad_rsn_ie_len; u_int8_t ad_rsn_ie[ APPLE80211_MAX_RSN_IE_LEN + 1 ]; u_int32_t ad_flags; // apple80211_assoc_flags }; static_assert(offsetof(apple80211_assoc_data, ad_key) == 0x38, "aaaa"); static_assert(offsetof(apple80211_assoc_data, ad_rsn_ie) == 206, "offsetof(apple80211_assoc_data, ad_rsn_ie)"); static_assert(offsetof(apple80211_assoc_data, ad_flags) == 464, "ad_flags offset error"); struct apple80211_deauth_data { u_int32_t version; u_int32_t deauth_reason; // reason code struct ether_addr deauth_ea; // BSSID of AP }; struct apple80211_countermeasures_data { u_int32_t version; u_int32_t enabled; }; struct apple80211_frag_threshold_data { u_int32_t version; u_int32_t threshold; // bytes }; struct apple80211_rate_set_data { u_int32_t version; u_int16_t num_rates; struct apple80211_rate rates[APPLE80211_MAX_RATES]; }; struct apple80211_short_slot_data { u_int32_t version; u_int8_t mode; }; struct apple80211_retry_limit_data { u_int32_t version; u_int32_t limit; }; struct apple80211_antenna_data { u_int32_t version; u_int32_t num_radios; int32_t antenna_index[APPLE80211_MAX_RADIO]; }; struct apple80211_dtim_int_data { u_int32_t version; u_int32_t interval; }; struct apple80211_sta_data { u_int32_t version; u_int32_t num_stations; struct apple80211_station station_list[APPLE80211_MAX_STATIONS]; }; struct apple80211_version_data { u_int32_t version; u_int16_t string_len; char string[APPLE80211_MAX_VERSION_LEN]; }; struct apple80211_rom_data { u_int32_t version; u_int32_t rom_len; u_int8_t rom[1]; // variable length }; struct apple80211_rand_data { u_int32_t version; u_int32_t rand; }; struct apple80211_rsn_ie_data { u_int32_t version; u_int16_t len; u_int8_t ie[ APPLE80211_MAX_RSN_IE_LEN ]; }; struct apple80211_ap_ie_data { u_int32_t version; u_int32_t len; #if __IO80211_TARGET < __MAC_13_0 u_int8_t *ie_data; #else u_int8_t ie_data[APPLE80211_NETWORK_DATA_MAX_IE_LEN]; #endif }; struct apple80211_stats_data { u_int32_t version; u_int32_t tx_frame_count; u_int32_t tx_errors; u_int32_t rx_frame_count; u_int32_t rx_errors; }; struct apple80211_country_code_data { u_int32_t version; u_int8_t cc[APPLE80211_MAX_CC_LEN]; }; struct apple80211_last_rx_pkt_data { u_int32_t version; u_int32_t rate; int32_t rssi; u_int32_t num_streams; // number of spatial streams struct ether_addr sa; // source address }; struct apple80211_radio_info_data { u_int32_t version; u_int32_t count; // number of rf chains }; struct apple80211_guard_interval_data { u_int32_t version; u_int32_t interval; // apple80211_guard_interval }; struct apple80211_mcs_data { u_int32_t version; u_int32_t index; // 0 to APPLE80211_MAX_MCS_INDEX }; struct apple80211_rifs_data { u_int32_t version; u_int32_t enabled; }; struct apple80211_ldpc_data { u_int32_t version; u_int32_t enabled; }; struct apple80211_msdu_data { u_int32_t version; u_int32_t max_length; // 3839 or 7935 bytes }; struct apple80211_mpdu_data { u_int32_t version; u_int32_t max_factor; // 0 - APPLE80211_MAX_MPDU_FACTOR u_int32_t max_density; // 0 - APPLE80211_MAX_MPDU_DENSITY }; struct apple80211_block_ack_data { u_int32_t version; u_int8_t ba_enabled; // block ack enabled u_int8_t immediate_ba_enabled; // immediate block ack enabled u_int8_t cbba_enabled; // compressed bitmap block ack enabled u_int8_t implicit_ba_enabled; // implicit block ack enabled }; struct apple80211_pls_data { u_int32_t version; u_int32_t enabled; // phy level spoofing enabled }; struct apple80211_psmp_data { u_int32_t version; u_int32_t enabled; }; struct apple80211_physubmode_data { u_int32_t version; u_int32_t phy_mode; // one apple80211_phymode u_int32_t phy_submode; // one apple80211_physubmode u_int32_t flags; // apple80211_channel_flag vector }; struct apple80211_mcs_index_set_data { u_int32_t version; u_int8_t mcs_set_map[APPLE80211_MAP_SIZE( APPLE80211_MAX_MCS_INDEX + 1 )]; }; struct apple80211_vht_mcs_index_set_data { u_int32_t version; u_int16_t mcs_map; } __attribute__((packed)); struct apple80211_mcs_vht_data { u_int32_t version; u_int32_t index; u_int32_t nss; u_int32_t bw; u_int32_t guard_interval; } __attribute__((packed)); struct apple80211_wow_parameter_data { u_int32_t version; u_int8_t wake_cond_map[APPLE80211_MAP_SIZE( APPLE80211_MAX_WAKE_COND + 1 )]; u_int32_t beacon_loss_time; u_int32_t pattern_count; struct apple80211_wow_pattern patterns[APPLE80211_MAX_WOW_PATTERNS]; }; struct apple80211_40mhz_intolerant_data { u_int32_t version; u_int32_t enabled; // bit enabled or not }; struct apple80211_tx_nss_data { uint32_t version; uint8_t nss; }; struct apple80211_nss_data { uint32_t version; uint8_t nss; }; struct apple80211_awdl_peer_traffic_registration { uint32_t version; void *addr; uint32_t name_len; char name[152]; uint32_t active; } __attribute__((packed)); struct apple80211_awdl_election_metric { uint32_t version; uint32_t metric; } __attribute__((packed)); struct apple80211_awdl_sync_enabled { uint32_t version; uint32_t unk1; uint32_t enabled; } __attribute__((packed)); struct apple80211_awdl_sync_frame_template { uint32_t version; uint32_t payload_len; void *payload; } __attribute__((packed)); struct apple80211_awdl_bssid { uint32_t version; uint8_t bssid[APPLE80211_ADDR_LEN]; uint8_t unk_mac[APPLE80211_ADDR_LEN]; } __attribute__((packed)); struct apple80211_awdl_channel { uint16_t chan_spec; uint8_t chan_num; uint8_t indoor_restric; uint8_t radar_dfs; uint8_t passive; uint8_t support_40Mhz; uint8_t support_80Mhz; uint8_t z; uint32_t per_chan; uint32_t chan_bitmap; } __attribute__((packed)); struct apple80211_channels_info { uint32_t version; uint32_t unk1; uint16_t num_chan_specs; uint16_t chan_spec[APPLE80211_MAX_CHANNELS]; uint8_t chan_num[APPLE80211_MAX_CHANNELS]; uint8_t indoor_restric[APPLE80211_MAX_CHANNELS]; uint8_t radar_dfs[APPLE80211_MAX_CHANNELS]; uint8_t passive[APPLE80211_MAX_CHANNELS]; uint8_t support_40Mhz[APPLE80211_MAX_CHANNELS]; uint8_t support_80Mhz[APPLE80211_MAX_CHANNELS]; uint8_t z[APPLE80211_MAX_CHANNELS]; uint8_t pad[386]; uint32_t per_chan[APPLE80211_MAX_CHANNELS]; uint32_t chan_bitmap[APPLE80211_MAX_CHANNELS]; } __attribute__((packed)); static_assert(__offsetof(struct apple80211_channels_info, chan_num) == 0x10A, "invalid offset"); //wf_chspec_ctlchan static_assert(__offsetof(struct apple80211_channels_info, indoor_restric) == 0x18A, "invalid offset"); //wlc_restricted_chanspec static_assert(__offsetof(struct apple80211_channels_info, radar_dfs) == 0x20A, "invalid offset"); //wlc_radar_chanspec static_assert(__offsetof(struct apple80211_channels_info, passive) == 0x28A, "invalid offset"); //wlc_quiet_chanspec static_assert(__offsetof(struct apple80211_channels_info, support_40Mhz) == 0x30A, "invalid offset"); static_assert(__offsetof(struct apple80211_channels_info, support_80Mhz) == 0x38A, "invalid offset"); static_assert(__offsetof(struct apple80211_channels_info, per_chan) == 0x60C, "invalid offset"); struct apple80211_peer_cache_maximum_size { uint32_t version; uint32_t max_peers; } __attribute__((packed)); struct apple80211_awdl_election_id { uint32_t version; uint32_t election_id; } __attribute__((packed)); struct apple80211_awdl_master_channel { uint32_t version; uint32_t master_channel; } __attribute__((packed)); struct apple80211_awdl_secondary_master_channel { uint32_t version; uint32_t secondary_master_channel; } __attribute__((packed)); struct apple80211_awdl_min_rate { uint32_t version; uint8_t min_rate; } __attribute__((packed)); struct apple80211_awdl_election_rssi_thresholds { uint32_t version; uint32_t unk1; uint32_t unk2; uint32_t unk3; } __attribute__((packed)); struct apple80211_channel_sequence { uint16_t flags; uint8_t pad; } __attribute__((packed)); struct apple80211_awdl_sync_channel_sequence { uint32_t version; uint8_t pad1; uint8_t length; // 5 uint8_t encoding; // 6 uint8_t step_count; // 7 uint8_t duplicate_count; // 8 uint8_t fill_channel; // 9 uint8_t pad2[6]; struct apple80211_channel_sequence seqs[APPLE80211_MAX_CHANNELS]; } __attribute__((packed)); static_assert(__offsetof(apple80211_awdl_sync_channel_sequence, seqs) == 16, "seqs offset error"); static_assert(sizeof(struct apple80211_awdl_sync_channel_sequence) == 0x190, "apple80211_awdl_sync_channel_sequence struct corrupt"); struct apple80211_awdl_presence_mode { uint32_t version; uint32_t mode; } __attribute__((packed)); struct apple80211_awdl_extension_state_machine_parameter { uint32_t version; uint32_t unk1; uint32_t unk2; uint32_t unk3; uint32_t unk4; } __attribute__((packed)); struct apple80211_awdl_sync_state { uint32_t version; uint32_t state; } __attribute__((packed)); struct apple80211_awdl_sync_params { uint32_t version; uint32_t availability_window_length; uint32_t availability_window_period; uint32_t extension_length; uint32_t synchronization_frame_period; } __attribute__((packed)); struct apple80211_awdl_cap { uint32_t version; uint8_t cap; } __attribute__((packed)); struct apple80211_awdl_af_tx_mode { uint32_t version; uint64_t mode; } __attribute__((packed)); #define AWDL_OOB_AF_PARAMS_SIZE 38 struct apple80211_awdl_oob_request { uint32_t version; uint32_t unk1; // 4 uint32_t unk2; // 8 uint32_t unk3; // 12 uint32_t unk4; // 16 uint16_t pad1; uint32_t unk5; // 22 uint16_t unk6; // 26 uint32_t pad2; uint32_t unk7; // 32 uint32_t pad3; uint16_t data_len; // 40 uint32_t pad4; uint16_t unk9; // 44 uint8_t data[1782]; // 48 } __attribute__((packed)); //Roam: DISABLED, 2.4GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 10; // "ROAM_PROF_FULLSCAN_PERIOD" = 3000; // "ROAM_PROF_INIT_SCAN_PERIOD" = 600; // "ROAM_PROF_MAX_SCAN_PERIOD" = 60000; // "ROAM_PROF_NFSCAN" = 1; // "ROAM_PROF_ROAM_DELTA" = 50; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-120"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 55; // "ROAM_PROF_RSSI_BOOST_THRESH" = "-68"; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 4; // "ROAM_PROF_NUM" = 1; //} //Roam: SINGLE-BAND, SINGLE-AP, 2.4GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 3600; // "ROAM_PROF_INIT_SCAN_PERIOD" = 60; // "ROAM_PROF_MAX_SCAN_PERIOD" = 1200; // "ROAM_PROF_NFSCAN" = 1; // "ROAM_PROF_ROAM_DELTA" = 12; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-80"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 55; // "ROAM_PROF_RSSI_BOOST_THRESH" = "-68"; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 4; // "ROAM_PROF_NUM" = 1; //} //Roam: DUAL-BAND, SINGLE-AP, 2.4GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 300; // "ROAM_PROF_INIT_SCAN_PERIOD" = 180; // "ROAM_PROF_MAX_SCAN_PERIOD" = 180; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 16; // "ROAM_PROF_ROAM_FLAGS" = 1; // "ROAM_PROF_ROAM_TRIGGER" = "-10"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 55; // "ROAM_PROF_RSSI_BOOST_THRESH" = "-68"; // "ROAM_PROF_RSSI_LOWER" = "-75"; // }, // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 120; // "ROAM_PROF_INIT_SCAN_PERIOD" = 20; // "ROAM_PROF_MAX_SCAN_PERIOD" = 90; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 12; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-75"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 55; // "ROAM_PROF_RSSI_BOOST_THRESH" = "-68"; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 4; // "ROAM_PROF_NUM" = 2; //} //Roam: MULTI-AP, 2.4GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 1200; // "ROAM_PROF_INIT_SCAN_PERIOD" = 180; // "ROAM_PROF_MAX_SCAN_PERIOD" = 600; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 20; // "ROAM_PROF_ROAM_FLAGS" = 1; // "ROAM_PROF_ROAM_TRIGGER" = "-10"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 55; // "ROAM_PROF_RSSI_BOOST_THRESH" = "-68"; // "ROAM_PROF_RSSI_LOWER" = "-50"; // }, // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 600; // "ROAM_PROF_INIT_SCAN_PERIOD" = 180; // "ROAM_PROF_MAX_SCAN_PERIOD" = 180; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 16; // "ROAM_PROF_ROAM_FLAGS" = 1; // "ROAM_PROF_ROAM_TRIGGER" = "-50"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 55; // "ROAM_PROF_RSSI_BOOST_THRESH" = "-68"; // "ROAM_PROF_RSSI_LOWER" = "-75"; // }, // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 1; // "ROAM_PROF_FULLSCAN_PERIOD" = 120; // "ROAM_PROF_INIT_SCAN_PERIOD" = 20; // "ROAM_PROF_MAX_SCAN_PERIOD" = 90; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 12; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-75"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 55; // "ROAM_PROF_RSSI_BOOST_THRESH" = "-68"; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 4; // "ROAM_PROF_NUM" = 3; //} //Roam: AC POWER, 2.4GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 120; // "ROAM_PROF_INIT_SCAN_PERIOD" = 20; // "ROAM_PROF_MAX_SCAN_PERIOD" = 90; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 16; // "ROAM_PROF_ROAM_FLAGS" = 1; // "ROAM_PROF_ROAM_TRIGGER" = "-10"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 55; // "ROAM_PROF_RSSI_BOOST_THRESH" = "-68"; // "ROAM_PROF_RSSI_LOWER" = "-75"; // }, // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 120; // "ROAM_PROF_INIT_SCAN_PERIOD" = 20; // "ROAM_PROF_MAX_SCAN_PERIOD" = 90; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 12; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-75"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 55; // "ROAM_PROF_RSSI_BOOST_THRESH" = "-68"; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 4; // "ROAM_PROF_NUM" = 2; //} //Roam: DISABLED, 5GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 10; // "ROAM_PROF_FULLSCAN_PERIOD" = 3000; // "ROAM_PROF_INIT_SCAN_PERIOD" = 600; // "ROAM_PROF_MAX_SCAN_PERIOD" = 60000; // "ROAM_PROF_NFSCAN" = 1; // "ROAM_PROF_ROAM_DELTA" = 50; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-120"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 0; // "ROAM_PROF_RSSI_BOOST_THRESH" = 0; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 2; // "ROAM_PROF_NUM" = 1; //} //Roam: SINGLE-BAND, SINGLE-AP, 5GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 3600; // "ROAM_PROF_INIT_SCAN_PERIOD" = 60; // "ROAM_PROF_MAX_SCAN_PERIOD" = 1200; // "ROAM_PROF_NFSCAN" = 1; // "ROAM_PROF_ROAM_DELTA" = 12; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-80"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 0; // "ROAM_PROF_RSSI_BOOST_THRESH" = 0; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 2; // "ROAM_PROF_NUM" = 1; //} //Roam: DUAL-BAND, SINGLE-AP, 5GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 120; // "ROAM_PROF_INIT_SCAN_PERIOD" = 20; // "ROAM_PROF_MAX_SCAN_PERIOD" = 90; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 12; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-75"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 0; // "ROAM_PROF_RSSI_BOOST_THRESH" = 0; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 2; // "ROAM_PROF_NUM" = 1; //} //Roam: MULTI-AP, 5GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 120; // "ROAM_PROF_INIT_SCAN_PERIOD" = 20; // "ROAM_PROF_MAX_SCAN_PERIOD" = 90; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 12; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-75"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 0; // "ROAM_PROF_RSSI_BOOST_THRESH" = 0; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 2; // "ROAM_PROF_NUM" = 1; //} //Roam: AC POWER, 5GHz on awdl0 => { // "ROAM_PROF" = ( // { // "ROAM_PROF_BACKOFF_MULTIPLIER" = 2; // "ROAM_PROF_FULLSCAN_PERIOD" = 120; // "ROAM_PROF_INIT_SCAN_PERIOD" = 20; // "ROAM_PROF_MAX_SCAN_PERIOD" = 90; // "ROAM_PROF_NFSCAN" = 2; // "ROAM_PROF_ROAM_DELTA" = 12; // "ROAM_PROF_ROAM_FLAGS" = 0; // "ROAM_PROF_ROAM_TRIGGER" = "-75"; // "ROAM_PROF_RSSI_BOOST_DELTA" = 0; // "ROAM_PROF_RSSI_BOOST_THRESH" = 0; // "ROAM_PROF_RSSI_LOWER" = "-128"; // } // ); // "ROAM_PROF_BAND" = 2; // "ROAM_PROF_NUM" = 1; //} struct apple80211_roam_profile { int8_t flags; int8_t trigger; int8_t rssi_lower; int8_t rssi_boost_delta; int8_t rssi_boost_thresh; int8_t delta; uint16_t backoff_multiplier; uint16_t full_scan_period; uint16_t init_scan_period; uint16_t nfscan; uint16_t max_scan_period; } __attribute__((packed)); struct apple80211_roam_profile_band_data { uint32_t version; uint32_t flags; // 4 (0x2, 0x4) uint32_t profile_cnt; // 8 struct apple80211_roam_profile profiles[4]; } __attribute__((packed)); static_assert(sizeof(struct apple80211_roam_profile_band_data) == 76, "roam data size error"); struct apple80211_ie_data { uint32_t version; uint32_t frame_type_flags; // 4 uint32_t add; // 8 uint32_t signature_len; // 12 uint32_t ie_len; // 16 uint32_t pad1; // 20 uint8_t ie[2048]; } __attribute__((packed)); struct apple80211_p2p_listen_data { uint32_t version; uint32_t pad1; uint32_t channel; // 8 uint32_t flags; // 12 uint32_t duration; // 16 } __attribute__((packed)); struct apple80211_p2p_go_conf_data { uint32_t version; uint32_t auth_upper; // 4 should equal to 1 uint32_t auth_lower; // 6 should non zero void *dynbcn; // 8 uint32_t channel; // 12 uint32_t bcn_len; // 16 uint32_t ssid_len; // 20 uint8_t ssid[32]; // 24 uint32_t suppress_beacon;// 56 security:1,4 } __attribute__((packed)); struct apple80211_sta_roam_data { uint32_t version; uint8_t rcc_channels; uint8_t unk1; uint8_t taget_channel; uint8_t target_bssid[APPLE80211_ADDR_LEN]; } __attribute__((packed)); struct apple80211_btc_profiles_data { uint32_t version; uint32_t profile_cnt; uint8_t profiles[141][4]; } __attribute__((packed)); struct apple80211_btc_config_data { uint32_t version; uint32_t enable_2G; uint32_t profile_2g; uint32_t enable_5G; uint32_t profile_5G; } __attribute__((packed)); struct apple80211_btc_mode_data { uint32_t version; uint32_t btc_mode; } __attribute__((packed)); struct apple80211_btc_options_data { uint32_t version; uint32_t btc_options; } __attribute__((packed)); struct apple80211_driver_available_data { uint64_t event; uint64_t avaliable; uint32_t reason; uint32_t sub_reason; char pad[160]; } __attribute__((packed)); static_assert(sizeof(struct apple80211_driver_available_data) == 0xB8, "invalid struct apple80211_driver_available_data"); #endif // _APPLE80211_IOCTL_H_ ================================================ FILE: include/Airport/apple80211_var.h ================================================ /* * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef _APPLE80211_VAR_H_ #define _APPLE80211_VAR_H_ #include #include #include #include // This is necessary, because even the latest Xcode does not support properly targeting 11.0. #ifndef __IO80211_TARGET #error "Please define __IO80211_TARGET to the requested version" #endif // Sizes and limits #define APPLE80211_ADDR_LEN 6 #define APPLE80211_MAX_RATES 15 #define APPLE80211_MAX_SSID_LEN 32 #define APPLE80211_MAX_ANTENNAE 4 #define APPLE80211_MAX_RADIO 4 #define APPLE80211_MAX_CHANNELS 128 #define APPLE80211_MAX_STATIONS 128 #define APPLE80211_MAX_VERSION_LEN 256 #define APPLE80211_MAX_ROM_SIZE 32768 // 32 KB #define APPLE80211_MAX_RSN_IE_LEN 257 // 255 + type and length bytes #define APPLE80211_MAX_CC_LEN 3 #define APPLE80211_MAX_MCS_INDEX 76 #define APPLE80211_MAX_MPDU_FACTOR 3 #define APPLE80211_MAX_MPDU_DENSITY 7 #define APPLE80211_MAX_WOW_PAT_LEN 1500 // Max wake on wireless pattern length #define APPLE80211_MAX_WOW_PATTERNS 12 // Arbitrary..this can change #define APPLE80211_MAP_SIZE( _bits ) (roundup( _bits, NBBY )/NBBY) enum apple80211_phymode { APPLE80211_MODE_UNKNOWN = 0, APPLE80211_MODE_AUTO = 0x1, // autoselect APPLE80211_MODE_11A = 2 << (1 - 1), // 5GHz, OFDM APPLE80211_MODE_11B = 2 << (2 - 1), // 2GHz, CCK APPLE80211_MODE_11G = 2 << (3 - 1), // 2GHz, OFDM APPLE80211_MODE_11N = 2 << (4 - 1), // 2GHz/5GHz, OFDM APPLE80211_MODE_TURBO_A = 2 << (5 - 1), // 5GHz, OFDM, 2x clock APPLE80211_MODE_TURBO_G = 2 << (6 - 1), // 2GHz, OFDM, 2x clock APPLE80211_MODE_11AC = 2 << (7 - 1), APPLE80211_MODE_11AX = 2 << (8 - 1), }; enum apple80211_physubmode { APPLE80211_SUBMODE_UNKNOWN = 0x0, APPLE80211_SUBMODE_11N_AUTO = 0x1, // 11n mode determined by AP capabilities APPLE80211_SUBMODE_11N_LEGACY = 0x2, // legacy APPLE80211_SUBMODE_11N_LEGACY_DUP = 0x4, // legacy duplicate APPLE80211_SUBMODE_11N_HT = 0x8, // high throughput APPLE80211_SUBMODE_11N_HT_DUP = 0x10, // high throughput duplicate APPLE80211_SUBMODE_11N_GF = 0x20, // green field }; // flags enum apple80211_opmode { APPLE80211_M_NONE = 0x0, APPLE80211_M_STA = 0x1, // infrastructure station APPLE80211_M_IBSS = 0x2, // IBSS (adhoc) station APPLE80211_M_AHDEMO = 0x4, // Old lucent compatible adhoc demo APPLE80211_M_HOSTAP = 0x8, // Software Access Point APPLE80211_M_MONITOR = 0x10 // Monitor mode }; enum apple80211_apmode { APPLE80211_AP_MODE_UNKNOWN = 0, APPLE80211_AP_MODE_IBSS = 1, // IBSS (adhoc) station APPLE80211_AP_MODE_INFRA = 2, // Access Point APPLE80211_AP_MODE_ANY = 3, // Any supported mode }; enum apple80211_state { APPLE80211_S_INIT = 0, // default state APPLE80211_S_SCAN = 1, // scanning APPLE80211_S_AUTH = 2, // try to authenticate APPLE80211_S_ASSOC = 3, // try to assoc APPLE80211_S_RUN = 4, // associated }; enum apple80211_protmode { APPLE80211_PROTMODE_OFF = 0, // no protection APPLE80211_PROTMODE_AUTO = 1, // auto APPLE80211_PROTMODE_CTS = 2, // CTS to self APPLE80211_PROTMODE_RTSCTS = 3, // RTS-CTS APPLE80211_PROTMODE_DUAL_CTS = 4, // dual CTS }; enum apple80211_cipher_type { APPLE80211_CIPHER_NONE = 0, // open network APPLE80211_CIPHER_WEP_40 = 1, // 40 bit WEP APPLE80211_CIPHER_WEP_104 = 2, // 104 bit WEP APPLE80211_CIPHER_TKIP = 3, // TKIP (WPA) APPLE80211_CIPHER_AES_OCB = 4, // AES (OCB) APPLE80211_CIPHER_AES_CCM = 5, // AES (CCM) APPLE80211_CIPHER_PMK = 6, // PMK APPLE80211_CIPHER_PMKSA = 7, // PMK obtained from pre-authentication APPLE80211_CIPHER_SMS4 = 8, APPLE80211_CIPHER_MSK = 9, APPLE80211_CIPHER_PWD = 10, APPLE80211_CIPHER_AES_GCM = 11, APPLE80211_CIPHER_AES_GCM256 = 12, }; enum apple80211_cipher_key_type { APPLE80211_CIPHER_KEY_TYPE_UNICAST = 0, // unicast cipher key APPLE80211_CIPHER_KEY_TYPE_MULTICAST = 1 // multicast cipher key }; // Low level 802.11 authentication types enum apple80211_authtype_lower { APPLE80211_AUTHTYPE_OPEN = 1, // open APPLE80211_AUTHTYPE_SHARED = 2, // shared key APPLE80211_AUTHTYPE_CISCO = 3, // cisco net eap }; // Higher level authentication used after 802.11 association complete enum apple80211_authtype_upper { APPLE80211_AUTHTYPE_NONE = 0, // No upper auth APPLE80211_AUTHTYPE_WPA = 1 << 0, // WPA APPLE80211_AUTHTYPE_WPA_PSK = 1 << 1, // WPA PSK APPLE80211_AUTHTYPE_WPA2 = 1 << 2, // WPA2 APPLE80211_AUTHTYPE_WPA2_PSK = 1 << 3, // WPA2 PSK APPLE80211_AUTHTYPE_FT_PSK = 1 << 4, // APPLE80211_AUTHTYPE_LEAP = 1 << 5, // LEAP APPLE80211_AUTHTYPE_WEP_8021X = 1 << 6, // WEP 802.1x APPLE80211_AUTHTYPE_FT_8021X = 1 << 7, // 802.1x APPLE80211_AUTHTYPE_WPS = 1 << 8, // WiFi Protected Setup APPLE80211_AUTHTYPE_WAPI = 1 << 9, APPLE80211_AUTHTYPE_SHA256_PSK = 1 << 10, APPLE80211_AUTHTYPE_SHA256_8021X = 1 << 11, APPLE80211_AUTHTYPE_WPA3_SAE = 1 << 12, APPLE80211_AUTHTYPE_WPA3_FT_SAE = 1 << 13, APPLE80211_AUTHTYPE_WPA3_ENTERPRISE = 1 << 14, APPLE80211_AUTHTYPE_WPA3_FT_ENTERPRISE = 1 << 15, }; // Unify association status code and deauth reason codes into a single enum describing // common error conditions enum apple80211_associate_result { APPLE80211_RESULT_UNAVAILABLE = 0, // No association/authentication result ready APPLE80211_RESULT_SUCCESS = 1, // APPLE80211_STATUS_SUCCESS and no deauth APPLE80211_RESULT_UNSPECIFIED_FAILURE = 2, // APPLE80211_STATUS_UNSPECIFIED_FAILURE APPLE80211_RESULT_UNSUPPORTED_CAPAPBILITIES = 3, // APPLE80211_STATUS_UNSUPPORTED_CAPABILITIES APPLE80211_RESULT_REASSOCIATION_DENIED = 4, // APPLE80211_STATUS_REASSOCIATION_DENIED APPLE80211_RESULT_ASSOCIATION_DENIED = 5, // APPLE80211_STATUS_ASSOCIATION_DENIED APPLE80211_RESULT_AUTH_ALG_UNSUPPORTED = 6, // APPLE80211_STATUS_AUTH_ALG_UNSUPPORTED APPLE80211_RESULT_INVALID_AUTH_SEQ_NUM = 7, // APPLE80211_STATUS_INVALID_AUTH_SEQ_NUM APPLE80211_RESULT_CHALLENGE_FAILURE = 8, // APPLE80211_STATUS_CHALLENGE_FAILURE APPLE80211_RESULT_TIMEOUT = 9, // APPLE80211_STATUS_TIMEOUT APPLE80211_RESULT_AP_FULL = 10, // APPLE80211_STATUS_AP_FULL APPLE80211_RESULT_UNSUPPORTED_RATE_SET = 11, // APPLE80211_STATUS_UNSUPPORTED_RATE_SET APPLE80211_RESULT_SHORT_SLOT_UNSUPPORTED = 12, // APPLE80211_STATUS_SHORT_SLOT_UNSUPPORTED APPLE80211_RESULT_DSSS_OFDM_UNSUPPORTED = 13, // APPLE80211_STATUS_DSSS_OFDM_UNSUPPORTED APPLE80211_RESULT_INVALID_IE = 14, // APPLE80211_STATUS_INVALID_IE APPLE80211_RESULT_INVALID_GROUP_CIPHER = 15, // APPLE80211_STATUS_INVALID_GROUP_CIPHER APPLE80211_RESULT_INVALID_PAIRWISE_CIPHER = 16, // APPLE80211_STATUS_INVALID_PAIRWISE_CIPHER APPLE80211_RESULT_INVALID_AKMP = 17, // APPLE80211_STATUS_INVALID_AKMP APPLE80211_RESULT_UNSUPPORTED_RSN_VERSION = 18, // APPLE80211_STATUS_UNSUPPORTED_RSN_VERSION APPLE80211_RESULT_INVALID_RSN_CAPABILITIES = 19, // APPLE80211_STATUS_INVALID_RSN_CAPABILITIES APPLE80211_RESULT_CIPHER_SUITE_REJECTED = 20, // APPLE80211_STATUS_CIPHER_SUIT_REJECTED APPLE80211_RESULT_INVALID_PMK = 21, // APPLE80211_REASON_PREV_AUTH_EXPIRED received APPLE80211_RESULT_SUPPLICANT_TIMEOUT = 22, // RSNSupplicant did not finish handshake APPLE80211_RESULT_UNKNOWN = 0xffff // Unrecognized error condition }; enum apple80211_link_down_reason { APPLE80211_LINK_DOWN_REASON_INTERNAL_ERROR = 0, APPLE80211_LINK_DOWN_REASON_BEACONLOST = 1, APPLE80211_LINK_DOWN_REASON_DEAUTH = 2, APPLE80211_LINK_DOWN_REASON_INTERNAL_ERROR_2 = 3 }; enum apple80211_unit { APPLE80211_UNIT_DBM = 0, // dBm APPLE80211_UNIT_MW = 1, // milliwatts APPLE80211_UNIT_PERCENT = 2, // value expressed as a percentage }; enum apple80211_power_state { APPLE80211_POWER_OFF = 0, // Chain disabled APPLE80211_POWER_ON = 1, // Chain powered on for tx and rx APPLE80211_POWER_TX = 2, // Chain powered on for tx only APPLE80211_POWER_RX = 3, // Chain powered on for rx only }; enum apple80211_locale { APPLE80211_LOCALE_UNKNOWN = 0, APPLE80211_LOCALE_FCC = 1, APPLE80211_LOCALE_ETSI = 2, APPLE80211_LOCALE_JAPAN = 3, APPLE80211_LOCALE_KOREA = 4, APPLE80211_LOCALE_APAC = 5, APPLE80211_LOCALE_ROW = 6, APPLE80211_LOCALE_INDONESIA = 7 }; enum apple80211_scan_type { APPLE80211_SCAN_TYPE_NONE = 0, APPLE80211_SCAN_TYPE_ACTIVE = 1, APPLE80211_SCAN_TYPE_PASSIVE = 2, APPLE80211_SCAN_TYPE_FAST = 3, // Ok to return cached scan results APPLE80211_SCAN_TYPE_BACKGROUND = 4, // Initiate background scanning }; enum apple80211_int_mit { APPLE80211_INT_MIT_OFF = 0, APPLE80211_INT_MIT_AUTO = 1, }; enum apple80211_channel_flag { APPLE80211_C_FLAG_NONE = 0x0, // no flags APPLE80211_C_FLAG_10MHZ = 0x1, // 10 MHz wide APPLE80211_C_FLAG_20MHZ = 0x2, // 20 MHz wide APPLE80211_C_FLAG_40MHZ = 0x4, // 40 MHz wide APPLE80211_C_FLAG_2GHZ = 0x8, // 2.4 GHz APPLE80211_C_FLAG_5GHZ = 0x10, // 5 GHz APPLE80211_C_FLAG_IBSS = 0x20, // IBSS supported APPLE80211_C_FLAG_HOST_AP = 0x40, // HOST AP mode supported APPLE80211_C_FLAG_ACTIVE = 0x80, // active scanning supported APPLE80211_C_FLAG_DFS = 0x100, // DFS required APPLE80211_C_FLAG_EXT_ABV = 0x200, // If 40 Mhz, extension channel above. // If this flag is not set, then the // extension channel is below. APPLE80211_C_FLAG_80MHZ = 0x400, // name made up - set if channelWidth == 80 && 5ghz && AC APPLE80211_C_FLAG_160MHZ = 0x800, // zxystd: Apple Broadcom not use it, but we can use! }; enum apple80211_rate_flag { APPLE80211_RATE_FLAG_NONE = 0x0, // no flags APPLE80211_RATE_FLAG_BASIC = 0x1, // basic rate APPLE80211_RATE_FLAG_HT = 0x2, // HT rate computed from MCS index }; enum apple80211_short_slot_mode { APPLE80211_SHORT_SLOT_MODE_AUTO = 1, // Default behavior APPLE80211_SHORT_SLOT_MODE_LONG = 2, // long - short slot timing mode APPLE80211_SHORT_SLOT_MODE_SHORT = 3, // short - short slot timing mode }; enum apple80211_powersave_mode { // Standard modes APPLE80211_POWERSAVE_MODE_DISABLED = 0, APPLE80211_POWERSAVE_MODE_80211 = 1, APPLE80211_POWERSAVE_MODE_VENDOR = 2, // Vendor specific mode, there should be // more general apple modes in the future. // Vendor modes also likely require more info. // Mimo modes APPLE80211_POWERSAVE_MODE_MIMO_STATIC = 3, APPLE80211_POWERSAVE_MODE_MIMO_DYNAMIC = 4, APPLE80211_POWERSAVE_MODE_MIMO_MIMO = 5, // WOW APPLE80211_POWERSAVE_MODE_WOW = 6, // Vendor specific powersave mode, throughput is maximized APPLE80211_POWERSAVE_MODE_MAX_THROUGHPUT = 7, // Vendor specific powersave mode, power savings are maximized, possibly // at the expense of throughput/latency. APPLE80211_POWERSAVE_MODE_MAX_POWERSAVE = 8, }; enum apple80211_debug_flag { APPLE80211_DEBUG_FLAG_NONE = 0x0, // No logging APPLE80211_DEBUG_FLAG_INFORMATIVE = 0x1, // Log "interesting" events APPLE80211_DEBUG_FLAG_ERROR = 0x2, // Log errors APPLE80211_DEBUG_FLAG_RSN = 0x4, // Full RSN supplicant logging APPLE80211_DEBUG_FLAG_SCAN = 0x8, // Scan events and information }; enum apple80211_guard_interval { APPLE80211_GI_SHORT = 400, // ns APPLE80211_GI_LONG = 800, // ns }; #define APPLE80211_RSC_LEN 8 #define APPLE80211_KEY_BUFF_LEN 32 #define APPLE80211_KEY_FLAG_UNICAST 0x1 #define APPLE80211_KEY_FLAG_MULTICAST 0x2 #define APPLE80211_KEY_FLAG_TX 0x4 #define APPLE80211_KEY_FLAG_RX 0x8 struct apple80211_key { u_int32_t version; u_int32_t key_len; u_int32_t key_cipher_type; // apple80211_cipher_type u_int16_t key_flags; u_int16_t key_index; u_int8_t key[ APPLE80211_KEY_BUFF_LEN ]; u_int8_t pad[30]; u_int32_t key_rsc_len; u_int8_t key_rsc[ APPLE80211_RSC_LEN ]; // receive sequence counter struct ether_addr key_ea; // key applies to this bssid uint wowl_kck_len; uint8_t wowl_kck_key[16]; uint wowl_kek_len; u_int8_t wowl_kek_key[24]; }; // Changing this affects any structure that contains a channel struct apple80211_channel { u_int32_t version; u_int32_t channel; // channel number u_int32_t flags; // apple80211_channel_flag vector }; struct apple80211_rate { u_int32_t version; u_int32_t rate; // rate mbps u_int32_t flags; // apple80211_rate_flag vector }; // Probe response capability flags, IEEE 7.3.1.4 #define APPLE80211_CAPINFO_ESS 0x0001 #define APPLE80211_CAPINFO_IBSS 0x0002 #define APPLE80211_CAPINFO_CF_POLLABLE 0x0004 #define APPLE80211_CAPINFO_CF_POLLREQ 0x0008 #define APPLE80211_CAPINFO_PRIVACY 0x0010 #define APPLE80211_CAPINFO_SHORT_PREAMBLE 0x0020 #define APPLE80211_CAPINFO_PBCC 0x0040 #define APPLE80211_CAPINFO_AGILITY 0x0080 // 0x0100, 0x0200 reserved #define APPLE80211_CAPINFO_SHORT_SLOT_TIME 0x0400 // 0x0800, 0x1000 reserved #define APPLE80211_CAPINFO_DSSS_OFDM 0x2000 // 0x4000, 0x8000 reserved // Reason codes IEEE 7.3.1.7 #define APPLE80211_REASON_UNSPECIFIED 1 #define APPLE80211_REASON_PREV_AUTH_EXPIRED 2 #define APPLE80211_REASON_AUTH_LEAVING 3 #define APPLE80211_REASON_INACTIVE 4 #define APPLE80211_REASON_AP_OVERLOAD 5 #define APPLE80211_REASON_NOT_AUTHED 6 #define APPLE80211_REASON_NOT_ASSOCED 7 #define APPLE80211_REASON_ASSOC_LEAVING 8 #define APPLE80211_REASON_ASSOC_NOT_AUTHED 9 #define APPLE80211_REASON_POWER_CAP 10 #define APPLE80211_REASON_SUPPORTED_CHANS 11 #define APPLE80211_REASON_INVALID_IE 13 #define APPLE80211_REASON_MIC_FAILURE 14 #define APPLE80211_REASON_4_WAY_TIMEOUT 15 #define APPLE80211_REASON_GROUP_KEY_TIMEOUT 16 #define APPLE80211_REASON_DIFF_IE 17 #define APPLE80211_REASON_INVALID_GROUP_KEY 18 #define APPLE80211_REASON_INVALID_PAIR_KEY 19 #define APPLE80211_REASON_INVALID_AKMP 20 #define APPLE80211_REASON_UNSUPP_RSN_VER 21 #define APPLE80211_REASON_INVALID_RSN_CAPS 22 #define APPLE80211_REASON_8021X_AUTH_FAILED 23 // Status codes IEEE 7.3.1.9 #define APPLE80211_STATUS_SUCCESS 0 #define APPLE80211_STATUS_UNSPECIFIED_FAILURE 1 // 2-9 reserved #define APPLE80211_STATUS_UNSUPPORTED_CAPABILITIES 10 #define APPLE80211_STATUS_REASSOCIATION_DENIED 11 #define APPLE80211_STATUS_ASSOCIATION_DENIED 12 #define APPLE80211_STATUS_AUTH_ALG_UNSUPPORTED 13 #define APPLE80211_STATUS_INVALID_AUTH_SEQ_NUM 14 #define APPLE80211_STATUS_CHALLENGE_FAILURE 15 #define APPLE80211_STATUS_TIMEOUT 16 #define APPLE80211_STATUS_AP_FULL 17 #define APPLE80211_STATUS_UNSUPPORTED_RATE_SET 18 // 22-24 reserved #define APPLE80211_STATUS_SHORT_SLOT_UNSUPPORTED 25 #define APPLE80211_STATUS_DSSS_OFDM_UNSUPPORTED 26 // 27-39 reserved #define APPLE80211_STATUS_INVALID_IE 40 #define APPLE80211_STATUS_INVALID_GROUP_CIPHER 41 #define APPLE80211_STATUS_INVALID_PAIRWISE_CIPHER 42 #define APPLE80211_STATUS_INVALID_AKMP 43 #define APPLE80211_STATUS_UNSUPPORTED_RSN_VERSION 44 #define APPLE80211_STATUS_INVALID_RSN_CAPABILITIES 45 #define APPLE80211_STATUS_CIPHER_SUITE_REJECTED 46 // 47 - 65535 reserved #define APPLE80211_STATUS_UNAVAILABLE 0xffff // If mcs index is set to APPLE80211_MCS_INDEX_AUTO, the interface // should go to auto rate selection, and abandon any previously // configured static MCS indices #define APPLE80211_MCS_INDEX_AUTO 0xffffffff /* DSCP TOS/Traffic class values for WME access categories taken from WiFi WMM Test Plan v 1.3.1 Appendix C. TOS/Traffic class field looks like: 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | DSCP | ECN | +---+---+---+---+---+---+---+---+ These bits are numbered according to rfc 2474, but might be misleading. It looks like bit 0 is actually the high order bit. */ #define APPLE80211_DSCP_WME_BE 0x00 #define APPLE80211_DSCP_WME_BK 0x08 #define APPLE80211_DSCP_WME_VI 0x28 #define APPLE80211_DSCP_WME_VO 0x38 // Access category values set in the mbuf #define APPLE80211_WME_AC_BE 0 #define APPLE80211_WME_AC_BK 1 #define APPLE80211_WME_AC_VI 2 #define APPLE80211_WME_AC_VO 3 // Working within the limitations of the kpi mbuf routines, the receive interface pointer // is the best place to put this for now since it is not used on the output path. The mbuf // kpi doesn't allow us to access unused flags, or I would put the WME AC in there like // everyone else. #define APPLE80211_MBUF_SET_WME_AC( m, ac ) mbuf_pkthdr_setrcvif( m, (ifnet_t)ac ) #define APPLE80211_MBUF_WME_AC( m ) (int)mbuf_pkthdr_rcvif( m ) // FIXME: seems that rates array starts at 0x24, immediately after struct apple80211_scan_result { u_int32_t version; // 0x00 - 0x03 apple80211_channel asr_channel; // 0x04 - 0x0f int16_t asr_unk; // 0x10 - 0x11 int16_t asr_noise; // 0x12 - 0x13 int16_t asr_snr; // 0x14 - 0x15 int16_t asr_rssi; // 0x16 - 0x17 int16_t asr_beacon_int; // 0x18 - 0x19 int16_t asr_cap; // 0x1a - 0x1b (capabilities) u_int8_t asr_bssid[ APPLE80211_ADDR_LEN ]; // 0x1c 0x1d 0x1e 0x1f 0x20 0x21 u_int8_t asr_nrates; // 0x22 u_int8_t asr_nr_unk; // 0x23 u_int32_t asr_rates[ APPLE80211_MAX_RATES ]; // 0x24 - 0x5f u_int8_t asr_ssid_len; // 0x60 u_int8_t asr_ssid[ APPLE80211_MAX_SSID_LEN ]; // 0x61 - 0x80 int16_t unk; uint8_t unk2; u_int32_t asr_age; // (ms) non-zero for cached scan result // 0x84 u_int16_t unk3; // 0x88 int16_t asr_ie_len; // 0x8A #if __IO80211_TARGET < __MAC_12_0 uint32_t asr_unk3; // 0x8C void* asr_ie_data; // 90 #else uint8_t asr_ie_data[1024]; // 0x8C #endif } __attribute__((packed)); struct apple80211_network_data { u_int32_t version; u_int16_t nd_mode; // apple80211_apmode u_int16_t nd_auth_lower; // apple80211_authtype_lower u_int16_t nd_auth_upper; // apple80211_authtype_upper struct apple80211_channel nd_channel; u_int32_t nd_ssid_len; u_int8_t nd_ssid[ APPLE80211_MAX_SSID_LEN ]; struct apple80211_key nd_key; u_int32_t nd_ie_len; void *nd_ie_data; }; #define APPLE80211_NETWORK_DATA_MAX_IE_LEN 1024 // As hostap support improves, this will grow struct apple80211_station { u_int32_t version; struct ether_addr sta_mac; int32_t sta_rssi; }; // WOW structures and defines struct apple80211_wow_pattern { size_t len; u_int8_t *pattern; }; enum apple80211_wake_condition { APPLE80211_WAKE_COND_MAGIC_PATTERN = 0, APPLE80211_WAKE_COND_NET_PATTERN = 1, APPLE80211_WAKE_COND_DISASSOCIATED = 2, APPLE80211_WAKE_COND_DEAUTHED = 3, APPLE80211_WAKE_COND_RETROGRADE_TSF = 4, APPLE80211_WAKE_COND_BEACON_LOSS = 5, }; #define APPLE80211_MAX_WAKE_COND 5 enum apple80211_card_capability { APPLE80211_CAP_WEP = 0, // CAPABILITY: WEP available APPLE80211_CAP_TKIP = 1, // CAPABILITY: TKIP available APPLE80211_CAP_AES = 2, // CAPABILITY: AES OCB avail APPLE80211_CAP_AES_CCM = 3, // CAPABILITY: AES CCM avail APPLE80211_CAP_CKIP = 4, // CAPABILITY: CKIP available APPLE80211_CAP_IBSS = 5, // CAPABILITY: IBSS available APPLE80211_CAP_PMGT = 6, // CAPABILITY: Power mgmt APPLE80211_CAP_HOSTAP = 7, // CAPABILITY: HOSTAP avail APPLE80211_CAP_TXPMGT = 8, // CAPABILITY: tx power mgmt APPLE80211_CAP_SHSLOT = 9, // CAPABILITY: short slottime APPLE80211_CAP_SHPREAMBLE = 10, // CAPABILITY: short preamble APPLE80211_CAP_MONITOR = 11, // CAPABILITY: monitor mode APPLE80211_CAP_TKIPMIC = 12, // CAPABILITY: TKIP MIC avail APPLE80211_CAP_WPA1 = 13, // CAPABILITY: WPA1 avail APPLE80211_CAP_WPA2 = 14, // CAPABILITY: WPA2 avail APPLE80211_CAP_WPA = 15, // CAPABILITY: WPA1+WPA2 avail APPLE80211_CAP_BURST = 16, // CAPABILITY: frame bursting APPLE80211_CAP_WME = 17, // CAPABILITY: WME avail APPLE80211_CAP_SHORT_GI_40MHZ = 18, // CAPABILITY: Short guard interval in 40 MHz APPLE80211_CAP_SHORT_GI_20MHZ = 19, // CAPABILITY: Short guard interval in 20 MHz APPLE80211_CAP_WOW = 20, // CAPABILITY: Wake on wireless APPLE80211_CAP_TSN = 21, // CAPABILITY: WPA with WEP group key }; #define APPLE80211_CAP_MAX 63 enum apple80211_virtual_interface_type { #if __IO80211_TARGET < __MAC_13_0 APPLE80211_VIF_P2P_DEVICE = 1, #else APPLE80211_VIF_P2P_DEVICE = 3, #endif APPLE80211_VIF_P2P_CLIENT, APPLE80211_VIF_P2P_GO, APPLE80211_VIF_AWDL, APPLE80211_VIF_SOFT_AP, APPLE80211_VIF_MAX }; enum apple80211_ie_type { APPLE80211_IE_FLAG_PROBE_REQ = (1 << 0), APPLE80211_IE_FLAG_PROBE_RESP = (1 << 1), APPLE80211_IE_FLAG_ASSOC_REQ = (1 << 2), APPLE80211_IE_FLAG_ASSOC_RESP = (1 << 3), APPLE80211_IE_FLAG_BEACON = (1 << 4), }; enum apple80211_assoc_flags { APPLE80211_ASSOC_F_CLOSED = 1, // flag: scan was directed, needed to remember closed networks }; enum IO80211LinkState { kIO80211NetworkLinkUndefined, // Starting link state when an interface is created kIO80211NetworkLinkDown, // Interface not capable of transmitting packets kIO80211NetworkLinkUp, // Interface capable of transmitting packets }; typedef enum IO80211LinkState IO80211LinkState; // Kernel messages struct apple80211_status_msg_hdr { u_int32_t msg_type; // type of message u_int32_t msg_len; // length of data (not including msg_type and msg_len) // data follows }; #define APPLE80211_M_MAX_LEN 2048 #define APPLE80211_M_POWER_CHANGED 1 #define APPLE80211_M_SSID_CHANGED 2 #define APPLE80211_M_BSSID_CHANGED 3 #define APPLE80211_M_LINK_CHANGED 4 #define APPLE80211_M_MIC_ERROR_UCAST 5 #define APPLE80211_M_MIC_ERROR_MCAST 6 #define APPLE80211_M_INT_MIT_CHANGED 7 #define APPLE80211_M_MODE_CHANGED 8 #define APPLE80211_M_ASSOC_DONE 9 #define APPLE80211_M_SCAN_DONE 10 #define APPLE80211_M_COUNTRY_CODE_CHANGED 11 #define APPLE80211_M_STA_ARRIVE 12 #define APPLE80211_M_STA_LEAVE 13 #define APPLE80211_M_DECRYPTION_FAILURE 14 #define APPLE80211_M_SCAN_CACHE_UPDATED 15 #define APPLE80211_M_INTERNAL_SCAN_DONE 16 #define APPLE80211_M_LINK_QUALITY 17 #define APPLE80211_M_IBSS_PEER_ARRIVED 18 #define APPLE80211_M_IBSS_PEER_LEFT 19 #define APPLE80211_M_RSN_HANDSHAKE_DONE 20 #define APPLE80211_M_BT_COEX_CHANGED 21 #define APPLE80211_M_P2P_PEER_DETECTED 22 #define APPLE80211_M_P2P_LISTEN_COMPLETE 23 #define APPLE80211_M_P2P_SCAN_COMPLETE 24 #define APPLE80211_M_P2P_LISTEN_STARTED 25 #define APPLE80211_M_P2P_SCAN_STARTED 26 #define APPLE80211_M_P2P_INTERFACE_CREATED 27 #define APPLE80211_M_P2P_GROUP_STARTED 28 #define APPLE80211_M_BGSCAN_NET_DISCOVERED 29 #define APPLE80211_M_ROAMED 30 #define APPLE80211_M_ACT_FRM_TX_COMPLETE 31 #define APPLE80211_M_DEAUTH_RECEIVED 32 #define APPLE80211_M_RSSI_CHANGED 39 #define APPLE80211_M_PEER_STATE 40 #define APPLE80211_M_AWDL_AVAILABILITY_WINDOW_START 42 #define APPLE80211_M_AWDL_AVAILABILITY_WINDOW_EXTENSIONS_END 43 #define APPLE80211_M_AWDL_SYNC_STATE_CHANGED 46 #define APPLE80211_M_AWDL_PEER_PRESENCE 47 #define APPLE80211_M_RESET_INTERFACE 49 #define APPLE80211_M_PEER_CREDIT_GRANT 50 #define APPLE80211_M_CHANNEL_SWITCH 54 #define APPLE80211_M_DRIVER_AVAILABLE 55 #define APPLE80211_M_INTERFACE_STATE 58 #define APPLE80211_M_LINK_ADDRESS_CHANGED 59 #define APPLE80211_M_BGSCAN_CACHED_NETWORK_AVAILABLE 63 #define APPLE80211_M_AWDL_STATISTICS 65 #define APPLE80211_M_AWDL_REALTIME_MODE_START 67 #define APPLE80211_M_AWDL_REALTIME_MODE_END 68 #define APPLE80211_M_ROAM_START 70 #define APPLE80211_M_ROAM_END 71 #define APPLE80211_M_DUMP_LOGS 79 #define APPLE80211_M_LEAKY_AP_STATISTICS 81 #define APPLE80211_M_RANGING_MEASUREMENT_DONE 83 #define APPLE80211_M_AWDL_DFS_CSA 88 #define APPLE80211_M_TCPKA_TIMEOUT 91 #define APPLE80211_M_AWDL_DFS_CSA_COMPLETE 94 #define APPLE80211_M_BSS_STEERING_REQUEST_EVENT 140 #define APPLE80211_M_AWDL_HPP_STATISTICS 142 #define APPLE80211_M_ACTION_FRAME 143 #define APPLE80211_M_AWDL_APP_SPECIFIC_INFO 144 #define APPLE80211_M_WSEC_NOTIFICATION 146 #define APPLE80211_M_MAX 170 #define APPLE80211_M_BUFF_SIZE APPLE80211_MAP_SIZE( APPLE80211_M_MAX ) // Registry Information #define APPLE80211_REGKEY_HARDWARE_VERSION "IO80211HardwareVersion" // #define APPLE80211_REG_FIRMWARE_VERSION "IO80211FirmwareVersion" #define APPLE80211_REGKEY_DRIVER_VERSION "IO80211DriverVersion" #define APPLE80211_REGKEY_LOCALE "IO80211Locale" #define APPLE80211_REGKEY_SSID "IO80211SSID" #define APPLE80211_REGKEY_CHANNEL "IO80211Channel" #define APPLE80211_REGKEY_EXT_CHANNEL "IO80211ExtensionChannel" #define APPLE80211_REGKEY_BAND "IO80211Band" #define APPLE80211_BAND_2GHZ "2 GHz" #define APPLE80211_BAND_5GHZ "5 GHz" #define APPLE80211_REGKEY_COUNTRY_CODE "IO80211CountryCode" // Userland messages #define APPLE80211_M_RSN_AUTH_SUCCESS 254 #define APPLE80211_M_RSN_AUTH_SUCCESS_TEMPLATE "com.apple.rsn.%s.auth.success" // string is interface name #define APPLE80211_M_RSN_AUTH_TIMEOUT 255 #define APPLE80211_M_RSN_AUTH_TIMEOUT_TEMPLATE "com.apple.rsn.%s.auth.timeout" // string is interface name #define APPLE80211_M_RSN_MSG_MAX 2 #endif // _APPLE80211_VAR_H_ ================================================ FILE: include/Airport/apple80211_wps.h ================================================ // // wps_eap.h // IO80211Family // // Created by Pete on 6/20/06. // Copyright 2006 Apple Computer, Inc. All rights reserved. // #ifndef _APPLE80211_WPS_H_ #define _APPLE80211_WPS_H_ #include #include #include // This is necessary, because even the latest Xcode does not support properly targeting 11.0. #ifndef __IO80211_TARGET #error "Please define __IO80211_TARGET to the requested version" #endif #define WPS_HANDSHAKE_TIMEOUT 120 /* seconds */ #define WPS_RETRANSMIT_TIMEOUT 5 #define WPS_MAX_RETRIES 3 #define WPS_IDENTITY_STR "WFA-SimpleConfig-Enrollee-1-0" #define WPS_IDENTITY_STR_LEN 29 #define WPS_PERSONALIZATION_STRING "Wi-Fi Easy and Secure Key Derivation" #define WPS_PERSONALIZATION_STRING_LEN ( sizeof( WPS_PERSONALIZATION_STRING ) - 1 ) #define WPS_KDF_KEY_BITS 640 #define WPS_DISPLAY_PIN_LEN 8 #define EAP_TYPE_ID 1 #define WPS_EAP_METHOD_TYPE 254 #define WPS_VENDOR_ID_BYTES 0x00, 0x37, 0x2A #define WPS_VENDOR_TYPE 0x00000001 #define WPS_OP_START 0x01 #define WPS_OP_ACK 0x02 #define WPS_OP_NACK 0x03 #define WPS_OP_MSG 0x04 #define WPS_OP_DONE 0x05 #define WPS_FLAG_MF 0x01 /* more fragments */ #define WPS_FLAG_LF 0x02 /* length field in use */ #define WPS_MAX_MSG_LEN UINT16_MAX /* max frag len, my limit */ #define PACKED __attribute__((packed)) struct wps_eap_hdr { u_int8_t code; u_int8_t identifier; u_int16_t length; u_int8_t type; u_int8_t vendor_id[3]; u_int32_t vendor_type; u_int8_t op_code; u_int8_t flags; u_int16_t msg_length; // u_int8_t msg[1]; /* data follows */ } PACKED; #define WPS_EAP_HDR_LEN( _whdr ) ( ( _whdr->flags & WPS_FLAG_LF ) ? sizeof( struct wps_eap_hdr ) : sizeof( struct wps_eap_hdr ) - sizeof( u_int16_t ) ) // Messages elements #define BUF_SIZE_64_BITS 8 #define BUF_SIZE_128_BITS 16 #define BUF_SIZE_160_BITS 20 #define BUF_SIZE_256_BITS 32 #define BUF_SIZE_512_BITS 64 #define BUF_SIZE_1024_BITS 128 #define BUF_SIZE_1536_BITS 192 struct wps_msg_elem_hdr { u_int16_t elem_id; u_int16_t elem_len; } PACKED; #define WPS_ELEM_SET_HEADER( elem, id, len ) (elem)->hdr.elem_id = htons( id ); (elem)->hdr.elem_len = htons( len ) struct wps_dev_type { u_int16_t category; u_int8_t oui[4]; u_int16_t sub_category; } PACKED; #define WIFI_DEV_TYPE_OUI_BYTES 0x00, 0x50, 0xf2, 0x04 #define DEFINE_WPS_ELEMENT( name, param ) \ typedef struct { \ struct wps_msg_elem_hdr hdr; \ param; \ } PACKED name #define WPS_VERSION 0x10 DEFINE_WPS_ELEMENT( wps_elem_ap_channel_t, u_int16_t channel ); DEFINE_WPS_ELEMENT( wps_elem_assoc_state_t, u_int16_t assoc_state ); DEFINE_WPS_ELEMENT( wps_elem_auth_type_t, u_int16_t auth_type ); DEFINE_WPS_ELEMENT( wps_elem_auth_type_flags_t, u_int16_t auth_flags ); #define AUTHENTICATOR_MSG_SIZE ( sizeof( struct wps_msg_elem_hdr ) + 8 ) DEFINE_WPS_ELEMENT( wps_elem_authenticator_t, u_int8_t authenticator[8] ); DEFINE_WPS_ELEMENT( wps_elem_config_methods_t, u_int16_t config_methods ); DEFINE_WPS_ELEMENT( wps_elem_config_error_t, u_int16_t error ); DEFINE_WPS_ELEMENT( wps_elem_confirm_url4_t, u_int16_t url4[1] ); // <= 64B DEFINE_WPS_ELEMENT( wps_elem_confirm_url6_t, u_int16_t url6[1] ); // <= 76B DEFINE_WPS_ELEMENT( wps_elem_conn_type_t, u_int8_t conn_type ); DEFINE_WPS_ELEMENT( wps_elem_conn_type_flags_t, u_int8_t conn_type_flags ); DEFINE_WPS_ELEMENT( wps_elem_credential_t, u_int8_t cred[1] ); // <= ??? DEFINE_WPS_ELEMENT( wps_elem_dev_name_t, u_int8_t dev_name[1] ); // <= 32B DEFINE_WPS_ELEMENT( wps_elem_dev_pw_id_t, u_int16_t dev_pw_id ); DEFINE_WPS_ELEMENT( wps_elem_e_hash1_t, u_int8_t e_hash1[BUF_SIZE_256_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_e_hash2_t, u_int8_t e_hash2[BUF_SIZE_256_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_e_snonce1_t, u_int8_t e_snonce1[BUF_SIZE_128_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_e_snonce2_t, u_int8_t e_snonce2[BUF_SIZE_128_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_ecrypt_settings_t, u_int8_t settings[1] ); // no limit defined DEFINE_WPS_ELEMENT( wps_elem_encrypt_type_t, u_int16_t encrypt_type ); DEFINE_WPS_ELEMENT( wps_elem_encrypt_type_flags_t, u_int16_t encrypt_type_flags ); DEFINE_WPS_ELEMENT( wps_elem_enrl_nonce_t, u_int8_t nonce[BUF_SIZE_128_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_feature_id_t, u_int32_t feature_id ); DEFINE_WPS_ELEMENT( wps_elem_identity_t, u_int8_t identity[1] ); // <= 80 // identity proof? DEFINE_WPS_ELEMENT( wps_elem_iv_t, u_int8_t iv[BUF_SIZE_256_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_key_wrap_authenticator_t, u_int8_t key_wrap_authenticator[8] ); DEFINE_WPS_ELEMENT( wps_elem_key_id_t, u_int8_t key_id[16] ); DEFINE_WPS_ELEMENT( wps_elem_mac_addr_t, u_int8_t mac[ETHER_ADDR_LEN] ); DEFINE_WPS_ELEMENT( wps_elem_manufacturer_t, u_int8_t manufacturer[1] ); // <= 64 DEFINE_WPS_ELEMENT( wps_elem_msg_type_t, u_int8_t msg_type ); DEFINE_WPS_ELEMENT( wps_elem_model_name_t, u_int8_t model_name[1] ); // <= 32B DEFINE_WPS_ELEMENT( wps_elem_model_number_t, u_int8_t model_number[1] ); // <= 32B DEFINE_WPS_ELEMENT( wps_elem_network_index_t, u_int8_t network_index ); DEFINE_WPS_ELEMENT( wps_elem_network_key_t, u_int8_t network_key[1] ); // <= 64B DEFINE_WPS_ELEMENT( wps_elem_network_key_index_t, u_int8_t network_key_index ); DEFINE_WPS_ELEMENT( wps_elem_new_dev_name_t, u_int8_t new_dev_name[1] ); // <= 32B DEFINE_WPS_ELEMENT( wps_elem_new_pw_t, u_int8_t new_pw[1] ); // <= 64 // oob device password? DEFINE_WPS_ELEMENT( wps_elem_os_version_t, u_int32_t os_version ); DEFINE_WPS_ELEMENT( wps_elem_power_level_t, u_int8_t power_level ); DEFINE_WPS_ELEMENT( wps_elem_psk_current_t, u_int8_t psk_current ); DEFINE_WPS_ELEMENT( wps_elem_psk_max_t, u_int8_t psk_max ); DEFINE_WPS_ELEMENT( wps_elem_public_key_t, u_int8_t key[BUF_SIZE_1536_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_radio_enabled_t, u_int8_t radio_enabled ); // bool? DEFINE_WPS_ELEMENT( wps_elem_reboot_t, u_int8_t reboot ); // bool? DEFINE_WPS_ELEMENT( wps_elem_reg_current_t, u_int8_t reg_current ); DEFINE_WPS_ELEMENT( wps_elem_reg_established_t, u_int8_t reg_established ); // bool? DEFINE_WPS_ELEMENT( wps_elem_reg_list_t, u_int8_t reg_list[1] ); // <= 512B DEFINE_WPS_ELEMENT( wps_elem_reg_max_t, u_int8_t reg_max ); DEFINE_WPS_ELEMENT( wps_elem_reg_nonce_t, u_int8_t nonce[BUF_SIZE_128_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_req_type_t, u_int8_t req_type ); DEFINE_WPS_ELEMENT( wps_elem_resp_type_t, u_int8_t resp_type ); DEFINE_WPS_ELEMENT( wps_elem_rf_band_t, u_int8_t rf_band ); DEFINE_WPS_ELEMENT( wps_elem_r_hash1, u_int8_t r_hash1[BUF_SIZE_256_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_r_hash2, u_int8_t r_hash2[BUF_SIZE_256_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_r_snonce1, u_int8_t r_snonce1[BUF_SIZE_128_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_r_snonce2, u_int8_t r_snonce2[BUF_SIZE_128_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_selected_reg_t, u_int8_t selected_reg ); // bool? DEFINE_WPS_ELEMENT( wps_elem_serial_number_t, u_int8_t serial_number[1] ); // <= 32B DEFINE_WPS_ELEMENT( wps_elem_simple_config_state_t, u_int8_t simple_config_state ); DEFINE_WPS_ELEMENT( wps_elem_ssid_t, u_int8_t ssid[32] ); DEFINE_WPS_ELEMENT( wps_elem_total_networks_t, u_int8_t total_networks ); DEFINE_WPS_ELEMENT( wps_elem_uuid_e_t, u_int8_t uuid_e[16] ); DEFINE_WPS_ELEMENT( wps_elem_uuid_r_t, u_int8_t uuid_r[16] ); DEFINE_WPS_ELEMENT( wps_elem_vendor_ext_t, u_int8_t vendor_ext[1] ); // <= 1024 DEFINE_WPS_ELEMENT( wps_elem_version_t, u_int8_t version ); // int? DEFINE_WPS_ELEMENT( wps_elem_x_509_cert_req_t, u_int8_t cert_req[1] ); // limit? DEFINE_WPS_ELEMENT( wps_elem_x_509_cert_t, u_int8_t cert[1] ); // limit? DEFINE_WPS_ELEMENT( wps_elem_eap_id_t, u_int8_t eap_id[1] ); // <= 64 DEFINE_WPS_ELEMENT( wps_elem_msg_counter_t, u_int8_t msg_counter[8] ); DEFINE_WPS_ELEMENT( wps_elem_public_key_hash_t, u_int8_t public_key_hash[BUF_SIZE_160_BITS] ); DEFINE_WPS_ELEMENT( wps_elem_rekey_key_t, u_int8_t rekey_key[32] ); DEFINE_WPS_ELEMENT( wps_elem_key_lifetime_t, u_int32_t key_lifetime ); DEFINE_WPS_ELEMENT( wps_elem_permitted_config_methods_t, u_int16_t permitted_config_methods ); DEFINE_WPS_ELEMENT( wps_elem_sel_reg_config_methods_t, u_int8_t sel_reg_config_methods ); DEFINE_WPS_ELEMENT( wps_elem_primary_dev_type_t, struct wps_dev_type prime_dev_type ); DEFINE_WPS_ELEMENT( wps_elem_secondary_dev_type_list_t, u_int8_t secondary_dev_type_list[1] ); // <= 128B DEFINE_WPS_ELEMENT( wps_elem_portable_dev_t, u_int8_t portable_dev ); // bool? DEFINE_WPS_ELEMENT( wps_elem_ap_setup_locked_t, u_int8_t ap_setup_locked ); // bool? DEFINE_WPS_ELEMENT( wps_elem_app_list_t, u_int8_t app_list[1] ); // <= 512B DEFINE_WPS_ELEMENT( wps_elem_eap_type_t, u_int8_t eap_type[1] ); // <= 8B #define WPS_NEXT_ELEMENT( cast, cur_elm, len ) (cast)( (UInt8 *)(cur_elm) + sizeof( struct wps_msg_elem_hdr ) + ntohs( cur_elm->hdr.elem_len ) ); \ len+=( sizeof( struct wps_msg_elem_hdr ) + ntohs( cur_elm->hdr.elem_len ) ) #define WPS_NEXT_ELEMENT_IE( cast, cur_elm, len ) (cast)( (UInt8 *)(cur_elm) + sizeof( struct wps_msg_elem_hdr ) + ntohs( cur_elm->hdr.elem_len ) ); \ len-=( sizeof( struct wps_msg_elem_hdr ) + ntohs( cur_elm->hdr.elem_len ) ); #define WPS_ELEMENT_IS( elem, id ) ( ntohs( elem->hdr.elem_id ) == id ) #define WPS_ELEMENT_LEN_VAR( elem ) ( sizeof( struct wps_msg_elem_hdr ) + ntohs( elem->hdr.elem_len ) ) #define WPS_ELEMENT_LEN_FIXED( fixed ) ( sizeof( struct wps_msg_elem_hdr ) + sizeof( fixed ) ) #define WPS_ELEMENT_PARAM_LEN( elem ) ( ntohs( elem->hdr.elem_len ) ) // Messages #define WPS_MBUF_GET_MSG_PTR( m, type ) (type *)( (UInt8 *)mbuf_data( m ) + sizeof( struct ether_header ) + sizeof( struct wps_eap_hdr ) ) struct wps_msg_nack { wps_elem_version_t version; wps_elem_msg_type_t msg_type; wps_elem_enrl_nonce_t enrl_nonce; wps_elem_reg_nonce_t reg_nonce; wps_elem_config_error_t error; }PACKED; struct wps_msg_ack { wps_elem_version_t version; wps_elem_msg_type_t msg_type; wps_elem_enrl_nonce_t enrl_nonce; wps_elem_reg_nonce_t reg_nonce; }PACKED; struct wps_msg_done { wps_elem_version_t version; wps_elem_msg_type_t msg_type; }; // From RFC 3748 section 4.1 for identity struct wps_identity_msg { u_int8_t code; u_int8_t id; u_int16_t length; u_int8_t type; // u_int8_t type_data[1]; /* data follows */ } PACKED; #define WPS_EAP_TYPE_IDENTITY 1 // Data Element Definitions #define WPS_ID_AP_CHANNEL 0x1001 #define WPS_ID_ASSOC_STATE 0x1002 #define WPS_ID_AUTH_TYPE 0x1003 #define WPS_ID_AUTH_TYPE_FLAGS 0x1004 #define WPS_ID_AUTHENTICATOR 0x1005 #define WPS_ID_CONFIG_METHODS 0x1008 #define WPS_ID_CONFIG_ERROR 0x1009 #define WPS_ID_CONF_URL4 0x100A #define WPS_ID_CONF_URL6 0x100B #define WPS_ID_CONN_TYPE 0x100C #define WPS_ID_CONN_TYPE_FLAGS 0x100D #define WPS_ID_CREDENTIAL 0x100E #define WPS_ID_DEVICE_NAME 0x1011 #define WPS_ID_DEVICE_PWD_ID 0x1012 #define WPS_ID_E_HASH1 0x1014 #define WPS_ID_E_HASH2 0x1015 #define WPS_ID_E_SNONCE1 0x1016 #define WPS_ID_E_SNONCE2 0x1017 #define WPS_ID_ENCR_SETTINGS 0x1018 #define WPS_ID_ENCR_TYPE 0x100F #define WPS_ID_ENCR_TYPE_FLAGS 0x1010 #define WPS_ID_ENROLLEE_NONCE 0x101A #define WPS_ID_FEATURE_ID 0x101B #define WPS_ID_IDENTITY 0x101C #define WPS_ID_IDENTITY_PROOF 0x101D #define WPS_ID_INIT_VECTOR 0x104B //this becomes 0x1060 later //#define WPS_ID_KEY_WRAP_AUTH WPS_ID_AUTHENTICATOR //this becomes 0x101E later #define WPS_ID_KEY_WRAP_AUTH 0x101E // HH changed for MS beta 2 testing #define WPS_ID_KEY_IDENTIFIER 0x101F #define WPS_ID_MAC_ADDR 0x1020 #define WPS_ID_MANUFACTURER 0x1021 #define WPS_ID_MSG_TYPE 0x1022 #define WPS_ID_MODEL_NAME 0x1023 #define WPS_ID_MODEL_NUMBER 0x1024 #define WPS_ID_NW_INDEX 0x1026 #define WPS_ID_NW_KEY 0x1027 #define WPS_ID_NW_KEY_INDEX 0x1028 #define WPS_ID_NEW_DEVICE_NAME 0x1029 #define WPS_ID_NEW_PWD 0x102A #define WPS_ID_OOB_DEV_PWD 0x102C #define WPS_ID_OS_VERSION 0x102D #define WPS_ID_POWER_LEVEL 0x102F #define WPS_ID_PSK_CURRENT 0x1030 #define WPS_ID_PSK_MAX 0x1031 #define WPS_ID_PUBLIC_KEY 0x1032 #define WPS_ID_RADIO_ENABLED 0x1033 #define WPS_ID_REBOOT 0x1034 #define WPS_ID_REGISTRAR_CURRENT 0x1035 #define WPS_ID_REGISTRAR_ESTBLSHD 0x1036 #define WPS_ID_REGISTRAR_LIST 0x1037 #define WPS_ID_REGISTRAR_MAX 0x1038 #define WPS_ID_REGISTRAR_NONCE 0x1039 #define WPS_ID_REQ_TYPE 0x103A #define WPS_ID_RESP_TYPE 0x103B #define WPS_ID_RF_BAND 0x103C #define WPS_ID_R_HASH1 0x103D #define WPS_ID_R_HASH2 0x103E #define WPS_ID_R_SNONCE1 0x103F #define WPS_ID_R_SNONCE2 0x1040 #define WPS_ID_SEL_REGISTRAR 0x1041 #define WPS_ID_SERIAL_NUM 0x1042 #define WPS_ID_SC_STATE 0x1044 #define WPS_ID_SSID 0x1045 #define WPS_ID_TOT_NETWORKS 0x1046 #define WPS_ID_UUID_E 0x1047 #define WPS_ID_UUID_R 0x1048 #define WPS_ID_VENDOR_EXT 0x1049 #define WPS_ID_VERSION 0x104A #define WPS_ID_X509_CERT_REQ 0x104B #define WPS_ID_X509_CERT 0x104C #define WPS_ID_EAP_IDENTITY 0x104D #define WPS_ID_MSG_COUNTER 0x104E #define WPS_ID_PUBKEY_HASH 0x104F #define WPS_ID_REKEY_KEY 0x1050 #define WPS_ID_KEY_LIFETIME 0x1051 #define WPS_ID_PERM_CFG_METHODS 0x1052 #define WPS_ID_SEL_REG_CFG_METHODS_ORIGINAL 0x0153 // This was the original val in the spec, we must support both #define WPS_ID_SEL_REG_CFG_METHODS 0x1053 #define WPS_ID_PRIM_DEV_TYPE 0x1054 #define WPS_ID_SEC_DEV_TYPE_LIST 0x1055 #define WPS_ID_PORTABLE_DEVICE 0x1056 #define WPS_ID_AP_SETUP_LOCKED 0x1057 #define WPS_ID_APP_LIST 0x1058 #define WPS_ID_EAP_TYPE 0x1059 // Association states #define WPS_ASSOC_NOT_ASSOCIATED 0 #define WPS_ASSOC_CONN_SUCCESS 1 #define WPS_ASSOC_CONFIG_FAIL 2 #define WPS_ASSOC_ASSOC_FAIL 3 #define WPS_ASSOC_IP_FAIL 4 // Authentication types #define WPS_AUTHTYPE_OPEN 0x0001 #define WPS_AUTHTYPE_WPAPSK 0x0002 #define WPS_AUTHTYPE_SHARED 0x0004 #define WPS_AUTHTYPE_WPA 0x0008 #define WPS_AUTHTYPE_WPA2 0x0010 #define WPS_AUTHTYPE_WPA2PSK 0x0020 // Config methods #define WPS_CONFMET_USBA 0x0001 #define WPS_CONFMET_ETHERNET 0x0002 #define WPS_CONFMET_LABEL 0x0004 #define WPS_CONFMET_DISPLAY 0x0008 #define WPS_CONFMET_EXT_NFC_TOK 0x0010 #define WPS_CONFMET_INT_NFC_TOK 0x0020 #define WPS_CONFMET_NFC_INTF 0x0040 #define WPS_CONFMET_PBC 0x0080 #define WPS_CONFMET_KEYPAD 0x0100 // WPS error messages #define WPS_ERROR_NO_ERROR 0 #define WPS_ERROR_OOB_INT_READ_ERR 1 #define WPS_ERROR_DECRYPT_CRC_FAIL 2 #define WPS_ERROR_CHAN24_NOT_SUPP 3 #define WPS_ERROR_CHAN50_NOT_SUPP 4 #define WPS_ERROR_SIGNAL_WEAK 5 #define WPS_ERROR_NW_AUTH_FAIL 6 #define WPS_ERROR_NW_ASSOC_FAIL 7 #define WPS_ERROR_NO_DHCP_RESP 8 #define WPS_ERROR_FAILED_DHCP_CONF 9 #define WPS_ERROR_IP_ADDR_CONFLICT 10 #define WPS_ERROR_FAIL_CONN_REGISTRAR 11 #define WPS_ERROR_MULTI_PBC_DETECTED 12 #define WPS_ERROR_ROGUE_SUSPECTED 13 #define WPS_ERROR_DEVICE_BUSY 14 #define WPS_ERROR_SETUP_LOCKED 15 #define WPS_ERROR_MSG_TIMEOUT 16 #define WPS_ERROR_REG_SESSION_TIMEOUT 17 #define WPS_ERROR_DEV_PWD_AUTH_FAIL 18 #define WPS_ERROR_MAX WPS_ERROR_DEV_PWD_AUTH_FAIL // Connection types #define WPS_CONNTYPE_ESS 0x01 #define WPS_CONNTYPE_IBSS 0x02 // Device password ID #define WPS_DEVICEPWDID_DEFAULT 0x0000 #define WPS_DEVICEPWDID_USER_SPEC 0x0001 #define WPS_DEVICEPWDID_MACHINE_SPEC 0x0002 #define WPS_DEVICEPWDID_REKEY 0x0003 #define WPS_DEVICEPWDID_PUSH_BTN 0x0004 #define WPS_DEVICEPWDID_REG_SPEC 0x0005 /* // Device type #define WPS_DEVICETYPE_COMPUTER "Computer" #define WPS_DEVICETYPE_AP "Access_Point" #define WPS_DEVICETYPE_ROUTER_AP "Router_AP" #define WPS_DEVICETYPE_PRINTER "Printer" #define WPS_DEVICETYPE_PRINTER_BRIDGE "Printer_Brigde" #define WPS_DEVICETYPE_ELECT_PIC_FRAME "Electronic_Picture_Frame" #define WPS_DEVICETYPE_DIG_AUDIO_RECV "Digital_Audio_Receiver" #define WPS_DEVICETYPE_WIN_MCE "Windows_Media_Center_Extender" #define WPS_DEVICETYPE_WIN_MOBILE "Windows_Mobile" #define WPS_DEVICETYPE_PVR "Personal_Video_Recorder" #define WPS_DEVICETYPE_VIDEO_STB "Video_STB" #define WPS_DEVICETYPE_PROJECTOR "Projector" #define WPS_DEVICETYPE_IP_TV "IP_TV" #define WPS_DEVICETYPE_DIG_STILL_CAM "Digital_Still_Camera" #define WPS_DEVICETYPE_PHONE "Phone" #define WPS_DEVICETYPE_VOID_PHONE "VoIP_Phone" #define WPS_DEVICETYPE_GAME_CONSOLE "Game_console" #define WPS_DEVICETYPE_OTHER "Other" */ // Encryption type #define WPS_ENCRTYPE_NONE 0x0001 #define WPS_ENCRTYPE_WEP 0x0002 #define WPS_ENCRTYPE_TKIP 0x0004 #define WPS_ENCRTYPE_AES 0x0008 // WPS Message Types #define WPS_ID_BEACON 0x01 #define WPS_ID_PROBE_REQ 0x02 #define WPS_ID_PROBE_RESP 0x03 #define WPS_ID_MESSAGE_M1 0x04 #define WPS_ID_MESSAGE_M2 0x05 #define WPS_ID_MESSAGE_M2D 0x06 #define WPS_ID_MESSAGE_M3 0x07 #define WPS_ID_MESSAGE_M4 0x08 #define WPS_ID_MESSAGE_M5 0x09 #define WPS_ID_MESSAGE_M6 0x0A #define WPS_ID_MESSAGE_M7 0x0B #define WPS_ID_MESSAGE_M8 0x0C #define WPS_ID_MESSAGE_ACK 0x0D #define WPS_ID_MESSAGE_NACK 0x0E #define WPS_ID_MESSAGE_DONE 0x0F //Device Type categories for primary and secondary device types #define WPS_DEVICE_TYPE_CAT_COMPUTER 1 #define WPS_DEVICE_TYPE_CAT_INPUT_DEVICE 2 #define WPS_DEVICE_TYPE_CAT_PRINTER 3 #define WPS_DEVICE_TYPE_CAT_CAMERA 4 #define WPS_DEVICE_TYPE_CAT_STORAGE 5 #define WPS_DEVICE_TYPE_CAT_NW_INFRA 6 #define WPS_DEVICE_TYPE_CAT_DISPLAYS 7 #define WPS_DEVICE_TYPE_CAT_MM_DEVICES 8 #define WPS_DEVICE_TYPE_CAT_GAME_DEVICES 9 #define WPS_DEVICE_TYPE_CAT_TELEPHONE 10 //Device Type sub categories for primary and secondary device types #define WPS_DEVICE_TYPE_SUB_CAT_COMP_PC 1 #define WPS_DEVICE_TYPE_SUB_CAT_COMP_SERVER 2 #define WPS_DEVICE_TYPE_SUB_CAT_COMP_MEDIA_CTR 3 #define WPS_DEVICE_TYPE_SUB_CAT_PRTR_PRINTER 1 #define WPS_DEVICE_TYPE_SUB_CAT_PRTR_SCANNER 2 #define WPS_DEVICE_TYPE_SUB_CAT_CAM_DGTL_STILL 1 #define WPS_DEVICE_TYPE_SUB_CAT_STOR_NAS 1 #define WPS_DEVICE_TYPE_SUB_CAT_NW_AP 1 #define WPS_DEVICE_TYPE_SUB_CAT_NW_ROUTER 2 #define WPS_DEVICE_TYPE_SUB_CAT_NW_SWITCH 3 #define WPS_DEVICE_TYPE_SUB_CAT_DISP_TV 1 #define WPS_DEVICE_TYPE_SUB_CAT_DISP_PIC_FRAME 2 #define WPS_DEVICE_TYPE_SUB_CAT_DISP_PROJECTOR 3 #define WPS_DEVICE_TYPE_SUB_CAT_MM_DAR 1 #define WPS_DEVICE_TYPE_SUB_CAT_MM_PVR 2 #define WPS_DEVICE_TYPE_SUB_CAT_MM_MCX 3 #define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX 1 #define WPS_DEVICE_TYPE_SUB_CAT_GAM_XBOX_360 2 #define WPS_DEVICE_TYPE_SUB_CAT_GAM_PS 3 #define WPS_DEVICE_TYPE_SUB_CAT_PHONE_WM 1 // Device request/response type #define WPS_MSGTYPE_ENROLLEE_INFO_ONLY 0x00 #define WPS_MSGTYPE_ENROLLEE_OPEN_8021X 0x01 #define WPS_MSGTYPE_REGISTRAR 0x02 #define WPS_MSGTYPE_AP_WLAN_MGR 0x03 // RF Band #define WPS_RFBAND_24GHZ 0x01 #define WPS_RFBAND_50GHZ 0x02 // Simple Config state #define WPS_SCSTATE_UNCONFIGURED 0x01 #define WPS_SCSTATE_CONFIGURED 0x02 // State business #define WPS_RETRY_INTERVAL 5 /* seconds */ #define WPS_PACKET_TIMEOUT 15 /* seconds */ #define WPS_TIMEOUT_SECS 1 enum WPSSupplicantState { WPS_S_INIT, WPS_S_EAPOL_START_TX, WPS_S_EAPOL_START_RX, WPS_S_IDENT_REQ_TX, WPS_S_IDENT_REQ_RX, WPS_S_IDENT_RESP_TX, WPS_S_IDENT_RESP_RX, WPS_S_START_TX, WPS_S_START_RX, WPS_S_M1_TX, WPS_S_M1_RX, WPS_S_M2_TX, WPS_S_M2_RX, WPS_S_M3_TX, WPS_S_M3_RX, WPS_S_M4_TX, WPS_S_M4_RX, WPS_S_M5_TX, WPS_S_M5_RX, WPS_S_M6_TX, WPS_S_M6_RX, WPS_S_M7_TX, WPS_S_M7_RX, WPS_S_M8_TX, WPS_S_M8_RX, WPS_S_DONE_TX, WPS_S_DONE_RX, WPS_S_FAIL_TX, WPS_S_FAIL_RX, WPS_S_MSG_TIMEOUT, WPS_S_SESSION_TIMEOUT, }; typedef enum WPSSupplicantState WPSSupplicantState; // Apple specific error codes #define WPSE_NOERR 0 // no error #define WPSE_ERR -1 // general error code #define WPSE_PROTO_ERR -2 // Problem with EAPOL handshake #define WPSE_IE_NOT_PRESENT -3 // No WPS IE present in IE list for ssid #define WPSE_IE_MALFORMED -4 // WPS IS missing required (for Apple) fields #define WPSE_SCAN_ERR -5 // Scan failed #define WPSE_NO_PIN_AT_REG -6 // No PIN configured at registrar #define WPSE_NO_PIN_AT_CLIENT -7 // No PIN configured at client #define WPSE_SSID_NOT_FOUND -8 // Scan did not find SSID #define WPSE_UNSUPPORTED_PW_ID -9 // Registrar reports that it is using an unsupported PW ID #define WPSE_ASSOC_FAILED -10 // Association attempt failed #define WPSE_API_REQ -11 // An apple80211 ioctl request failed #define WPSE_NOMEM -12 // memory error #define WPSE_WPA_RSN_NOT_SUP -13 // WPA/RSN not supported #define WPSE_TIMEOUT -14 // EAPOL timed out #define WPSE_NACKED -15 // NACKED by registrar #define WPSE_FAIL -16 // unexpected EAP-FAIL received #endif /* _APPLE80211_WPS_H_ */ ================================================ FILE: include/Airport/apple_private_spi.h ================================================ /* * Copyright (c) 1998-2016 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #ifndef apple_private_spi_h #define apple_private_spi_h #ifndef __PRIVATE_SPI__ /*! @enum IOMbufServiceClass @discussion Service class of a mbuf packet. @constant kIOMbufServiceClassBKSYS Background System-Initiated. @constant kIOMbufServiceClassBK Background. @constant kIOMbufServiceClassBE Best Effort. @constant kIOMbufServiceClassRD Responsive Data. @constant kIOMbufServiceClassOAM Operations, Administration, and Management. @constant kIOMbufServiceClassAV Multimedia Audio/Video Streaming. @constant kIOMbufServiceClassRV Responsive Multimedia Audio/Video. @constant kIOMbufServiceClassVI Interactive Video. @constant kIOMbufServiceClassVO Interactive Voice. @constant kIOMbufServiceClassCTL Network Control. */ enum IOMbufServiceClass { kIOMbufServiceClassBKSYS = 100, kIOMbufServiceClassBK = 200, kIOMbufServiceClassBE = 0, kIOMbufServiceClassRD = 300, kIOMbufServiceClassOAM = 400, kIOMbufServiceClassAV = 500, kIOMbufServiceClassRV = 600, kIOMbufServiceClassVI = 700, kIOMbufServiceClassVO = 800, kIOMbufServiceClassCTL = 900 }; #endif struct packet_info_tag { }; struct apple80211_debug_command { }; struct ifnet_init_eparams { }; #endif /* apple_private_spi_h */ ================================================ FILE: include/Airport/debug.h ================================================ // // debug.h // Black80211_HighSierra // // Created by Roman Peshkov on 05/07/2018. // Copyright © 2018 Roman Peshkov. All rights reserved. // #ifndef debug_h #define debug_h static const char* IOCTL_NAMES[] = { "UNKNOWN", "SSID", "AUTH_TYPE", "CIPHER_KEY", "CHANNEL", "POWERSAVE", "PROTMODE", "TXPOWER", "RATE", "BSSID", "SCAN_REQ", "SCAN_RESULT", "CARD_CAPABILITIES", "STATE", "PHY_MODE", "OP_MODE", "RSSI", "NOISE", "INT_MIT", "POWER", "ASSOCIATE", "ASSOCIATE_RESULT", "DISASSOCIATE", "STATUS_DEV_NAME", "IBSS_MODE", "HOST_AP_MODE", "AP_MODE", "SUPPORTED_CHANNELS", "LOCALE", "DEAUTH", "COUNTERMEASURES", "FRAG_THRESHOLD", "RATE_SET", "SHORT_SLOT", "MULTICAST_RATE", "SHORT_RETRY_LIMIT", "LONG_RETRY_LIMIT", "TX_ANTENNA", "RX_ANTENNA", "ANTENNA_DIVERSITY", "ROM", "DTIM_INT", "STATION_LIST", "DRIVER_VERSION", "HARDWARE_VERSION", "RAND", "RSN_IE", "BACKGROUND_SCAN", "AP_IE_LIST", "STATS", "ASSOCIATION_STATUS", "COUNTRY_CODE", "DEBUG_FLAGS", "LAST_RX_PKT_DATA", "RADIO_INFO", "GUARD_INTERVAL", "MIMO_POWERSAVE", "MCS", "RIFS", "LDPC", "MSDU", "MPDU", "BLOCK_ACK", "PLS", "PSMP", "PHY_SUB_MODE", "MCS_INDEX_SET", "CACHE_THRESH_BCAST", "CACHE_THRESH_DIRECT", "WOW_PARAMETERS", "WOW_ENABLED", "40MHZ_INTOLERANT", "PID_LOCK", "STA_IE_LIST", "STA_AUTHORIZE", "STA_DISASSOCIATE", "STA_DEAUTH", "RSN_CONF", "KEY_RSC", "STA_STATS", "ROAM_THRESH", "VENDOR_DBG_FLAGS", "CACHE_AGE_THRESH", "PMK_CACHE", "LINK_QUAL_EVENT_PARAMS", "IE", "SCAN_REQ_MULTIPLE", "BTCOEX_MODE", "WOW_TEST", "CLEAR_PMK_CACHE", "SCANCACHE_CLEAR", "P2P_ENABLE", "P2P_LISTEN", "P2P_SCAN", "VIRTUAL_IF_CREATE", "VIRTUAL_IF_DELETE", "VIRTUAL_IF_ROLE", "VIRTUAL_IF_PARENT", "P2P_GO_CONF", "P2P_NOA_LIST", "P2P_OPP_PS", "P2P_CT_WINDOW", "BT_COEX_FLAGS", "CURRENT_NETWORK", "BT_POWER", "AVAILABILITY", "RSSI_BOUNDS", "ROAM", "TX_CHAIN_POWER", "CDD_MODE", "LAST_BCAST_SCAN_TIME", "THERMAL_THROTTLING", "FACTORY_MODE", "REASSOCIATE", "???MISSING???", "POWER_DEBUG_INFO", "AWDL_SYNC_PARAMS", "AWDL_SYNC_ENABLED", "AWDL_EXTENSION_STATE_MACHINE_PARAMETERS", "AWDL_SERVICE_PARAMS", "AWDL_PEER_SERVICE_REQUEST", "AWDL_ELECTION_ALGORITHM_ENABLED", "AWDL_ELECTION_ID", "AWDL_MAX_TREE_DEPTH", "AWDL_GUARD_TIME", "AWDL_BSSID", "AWDL_ELECTION_METRIC", "AWDL_AVAILABILITY_WINDOW_AP_ALIGNMENT", "AWDL_SYNC_FRAME_AP_BEACON_ALIGNMENT", "AWDL_SYNCHRONIZATION_CHANNEL_SEQUENCE", "PEER_CACHE_MAXIMUM_SIZE", "AWDL_OUI", "AWDL_MASTER_CHANNEL", "AWDL_TOP_MASTER", "AWDL_SYNC_STATE", "AWDL_ELECTION_RSSI_THRESHOLDS", "AWDL_PRESENCE_MODE", "AWDL_ELECTION_MASTER_COUNTS", "AWDL_PERIODIC_SYNC_FRAME_PACKET_LIFETIME", "AWDL_MASTER_MODE_SYNC_FRAME_PERIOD", "AWDL_NON_ELECTION_MASTER_MODE_SYNC_FRAME_PERIOD", "AWDL_EXPLICIT_AVAILABILITY_WINDOW_EXTENSION_OPT_OUT", "AWDL_GET_AWDL_MASTER_DATABASE", "PEER_CACHE_CONTROL", "AWDL_BATTERY_LEVEL", "AWDL_BT_COEX_AW_PROTECTED_PERIOD_LENGTH", "AWDL_BT_COEX_AGREEMENT", "AWDL_BT_COEX_AGREEMENT_ENABLED", "AWDL_STRATEGY", "AWDL_OOB_REQUEST", "AWDL_MAX_NO_MASTER_PERIODS", "AWDL_SYNC_FRAME_TEMPLATE", "LOG_FLAGS", "PEER_STATS", "HT_CAPABILITY", "AWDL_ELECTION_PARAMS", "LINK_CHANGED_EVENT_DATA", "GET_DEBUG_INFO", "AWDL_DEVICE_CAPABILITIES", "AWDL_RSSI_MEASUREMENT_REQUEST", "AWDL_AES_KEY", "AWDL_SCAN_RESERVED_TIME", "AWDL_CTL", "AWDL_SOCIAL_TIME_SLOTS", "AWDL_PEER_TRAFFIC_REGISTRATION", "EXTENDED_STATS", "BEACON_PERIOD", "AWDL_FORCED_ROAM_CONFIG", "AWDL_QUIET", "ACL_POLICY", "ACL_ADD", "ACL_REMOVE", "ACL_FLUSH", "ACL_LIST", "CHAIN_ACK", "DESENSE", "OFFLOAD_SCANNING", "OFFLOAD_RSN", "OFFLOAD_COUNTRY_CODE", "OFFLOAD_KEEPALIVE_L2", "OFFLOAD_ARP_NDP", "VHT_MCS_INDEX_SET", "DWDS", "INTERRUPT_STATS", "INTERRUPT_STATS_RESET", "TIMER_STATS", "TIMER_STATS_RESET", "OFFLOAD_STATS", "OFFLOAD_STATS_RESET", "OFFLOAD_BEACONS", "ROAMING", "OFFLOAD_ARP", "OFFLOAD_NDP", "OFFLOAD_SCAN", "DESENSE_LEVEL", "MCS_VHT", "TX_NSS", "GAS_REQ", "GAS_START", "GAS_SET_PEER", "GAS_RESULTS", "AWDL_BTLE_PEER_INDICATION", "AWDL_BTLE_STATE_PARAMS", "AWDL_PEER_DATABASE", "AWDL_BTLE_ENABLE_SYNC_WITH_PARAMS", "AWDL_SECONDARY_MASTER_CHANNEL", "PHY_STATS", "CHANNELS_INFO", "AWDL_AF_TX_MODE", "ERROR_STRING", "ERROR_NO", "AWDL_PIGGYBACK_SCAN_REQ", "AWDL_PRIVATE_ELECTION_ID", "AWDL_MIN_RATE", "VHT_CAPABILITY", "BGSCAN_CACHE_RESULTS", "ROAM_PROFILE", "AWDL_OPER_MODE", "RESTORE_DEFAULTS", "AWDL_ENCRYPTION_KEYS", "AWDL_ENCRYPTION_TYPE", "BTCOEX_PROFILES", "BTCOEX_CONFIG", "AWDL_STATISTICS", "AWDL_ENABLE_ROAMING", "AWDL_OOB_AUTO_REQUEST", "AWDL_TXCAL_PERIOD", "CHIP_COUNTER_STATS", "DBG_GUARD_TIME_PARAMS", "AWDL_AWDL_ADVERTISERS", "LEAKY_AP_STATS_MODE", "CAPTURE", "LEAKY_AP_STATS", "AWDL_BLOCK_SET_COMMANDS", "LEAKY_AP_AWD_MODE", "BTCOEX_OPTIONS", "FORCE_SYNC_TO_PEER", "COUNTRY_CHANNELS", "PRIVATE_MAC", "RESET_CHIP", "CRASH", "RANGING_ENABLE", "RANGING_START", "RANGING_AUTHENTICATE", "AWDL_PREFERRED_CHANNELS", "LEAKY_AP_SSID_STATS", "AWDL_RSDB_CAPS", "AWDL_DEV_STATS", "LAST_ASSOC_HISTORY", "AWDL_COMMON_CHANNEL", "AWDL_PEERS_INFO", "TKO_PARAMS", "TKO_DUMP", "AWDL_NEARBY_LOG_TRIGGER", "HW_SUPPORTED_CHANNELS", "BTCOEX_PROFILE", "BTCOEX_PROFILE_ACTIVE", "TRAP_INFO", "THERMAL_INDEX", "MAX_NSS_FOR_AP", "BTCOEX_2G_CHAIN_DISABLE", "POWER_BUDGET", "AWDL_DFSP_CONFIG", "AWDL_DFSP_UCSA_CONFIG", "SCAN_BACKOFF_REPORT", "OFFLOAD_TCPKA_ENABLE", "RANGING_CAPS", "PER_CORE_RSSI_REPORT/SUPPRESS_SCANS", }; #endif /* debug_h */ ================================================ FILE: include/ClientKit/Common.h ================================================ /* * 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. */ #ifndef Common_h #define Common_h #include "IoctlId.h" #define IOCTL_MASK 0x800000 #define IOCTL_VERSION 1 #define NWID_LEN 32 #define WPA_KEY_LEN 128 #define kIONoScanResult 20008 struct ioctl_driver_info { unsigned int version; char fw_version[32]; //firmware version string char driver_version[32]; //driver version string char bsd_name[32]; //interface bsd name, eg. en1 }; enum itl_phy_mode { ITL80211_MODE_11A, ITL80211_MODE_11B, ITL80211_MODE_11G, ITL80211_MODE_11N, ITL80211_MODE_11AC, ITL80211_MODE_11AX }; struct ioctl_sta_info { unsigned int version; enum itl_phy_mode op_mode; int max_mcs; int cur_mcs; uint channel; uint16_t band_width;//20 40 80 160 int16_t rssi; int16_t noise; uint rate; unsigned char ssid[NWID_LEN]; uint8_t bssid[ETHER_ADDR_LEN]; }; struct ioctl_power { unsigned int version; unsigned int enabled; //1 == on, 0 == off unsigned int maxsleep; //max sleep in ms }; enum itl_80211_state { ITL80211_S_INIT = 0, /* default state */ ITL80211_S_SCAN = 1, /* scanning */ ITL80211_S_AUTH = 2, /* try to authenticate */ ITL80211_S_ASSOC = 3, /* try to assoc */ ITL80211_S_RUN = 4 /* associated */ }; struct ioctl_state { unsigned int version; int state; //itl_80211_state }; struct ioctl_nw_id { unsigned int version; unsigned int len; char nwid[NWID_LEN]; }; struct ioctl_nw_bssid { unsigned int version; char bssid[ETHER_ADDR_LEN]; }; struct ioctl_wpa_key { unsigned int version; unsigned int len; char key[WPA_KEY_LEN]; }; struct ioctl_associate { unsigned int version; struct ioctl_nw_id nwid; struct ioctl_wpa_key wpa_key; }; struct ioctl_disassociate { unsigned int version; unsigned char ssid[NWID_LEN]; }; struct ioctl_join { unsigned int version; struct ioctl_nw_id nwid; struct ioctl_wpa_key wpa_key; }; struct ioctl_scan { unsigned int version; }; struct ioctl_scan_result { unsigned int version; }; struct ioctl_tx_power { unsigned int version; }; /* * 802.11 ciphers. */ enum itl80211_cipher { ITL80211_CIPHER_NONE = 0x00000000, ITL80211_CIPHER_USEGROUP = 0x00000001, ITL80211_CIPHER_WEP40 = 0x00000002, ITL80211_CIPHER_TKIP = 0x00000004, ITL80211_CIPHER_CCMP = 0x00000008, ITL80211_CIPHER_WEP104 = 0x00000010, ITL80211_CIPHER_BIP = 0x00000020 /* 11w */ }; enum itl80211_wpa_proto { ITL80211_WPA_PROTO_WPA1 = 0x01, ITL80211_WPA_PROTO_WPA2 = 0x02 }; enum itl80211_proto { ITL80211_PROTO_NONE = 0, ITL80211_PROTO_RSN = 1 << 0, ITL80211_PROTO_WPA = 1 << 1 }; /* * 802.11 Authentication and Key Management Protocols. */ enum itl80211_akm { ITL80211_AKM_NONE = 0x00000000, ITL80211_AKM_8021X = 0x00000001, ITL80211_AKM_PSK = 0x00000002, ITL80211_AKM_SHA256_8021X = 0x00000004, /* 11w */ ITL80211_AKM_SHA256_PSK = 0x00000008 /* 11w */ }; struct ioctl_network_info { unsigned char ssid[NWID_LEN]; int16_t noise; int16_t rssi; uint8_t bssid[ETHER_ADDR_LEN]; uint32_t channel; unsigned int supported_rsnprotos; //itl80211_proto unsigned int rsn_protos; //itl80211_wpa_proto unsigned int supported_rsnakms; //itl80211_akm unsigned int rsn_akms; //rsn_akms unsigned int rsn_ciphers; enum itl80211_cipher rsn_groupcipher; enum itl80211_cipher rsn_groupmgmtcipher; u_int16_t ni_rsncaps; enum itl80211_cipher ni_rsncipher; uint32_t recv_timestamp; }; #endif /* Common_h */ ================================================ FILE: include/ClientKit/IoctlId.h ================================================ /* * 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. */ #ifndef IoctlId_h #define IoctlId_h enum IOCTL_IDS { IOCTL_80211_DRIVER_INFO, IOCTL_80211_STA_INFO, IOCTL_80211_POWER, IOCTL_80211_STATE, IOCTL_80211_NW_ID, IOCTL_80211_WPA_KEY, IOCTL_80211_ASSOCIATE, IOCTL_80211_DISASSOCIATE, IOCTL_80211_JOIN, IOCTL_80211_SCAN, IOCTL_80211_SCAN_RESULT, IOCTL_80211_TX_POWER_LEVEL, IOCTL_80211_NW_BSSID, IOCTL_ID_MAX }; #endif /* IoctlId_h */ ================================================ FILE: include/FwData.h ================================================ /* * 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. */ #ifndef FwData_h #define FwData_h #include #include #include #include struct FwDesc { const char *name; const unsigned char *var; const int size; }; #define IWL_FW(fw_name, fw_var, fw_size) \ .name = fw_name, .var = fw_var, .size = fw_size extern const struct FwDesc fwList[]; extern const int fwNumber; static inline OSData *getFWDescByName(const char* name) { for (int i = 0; i < fwNumber; i++) { if (strcmp(fwList[i].name, name) == 0) { FwDesc desc = fwList[i]; return OSData::withBytes(desc.var, desc.size); } } return NULL; } static inline bool uncompressFirmware(unsigned char *dest, uint *destLen, unsigned char *source, uint sourceLen) { z_stream stream; int err; stream.next_in = source; stream.avail_in = sourceLen; stream.next_out = dest; stream.avail_out = *destLen; stream.zalloc = zcalloc; stream.zfree = zcfree; err = inflateInit(&stream); if (err != Z_OK) { return false; } err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&stream); return false; } *destLen = (uint)stream.total_out; err = inflateEnd(&stream); return err == Z_OK; } #endif /* FwData_h */ ================================================ FILE: include/HAL/ItlDriverController.hpp ================================================ /* * 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. */ #ifndef ItlDriverController_h #define ItlDriverController_h class ItlDriverController { public: virtual void clearScanningFlags() = 0; virtual IOReturn setMulticastList(IOEthernetAddress *addr, int count) = 0; }; #endif /* ItlDriverController_h */ ================================================ FILE: include/HAL/ItlDriverInfo.hpp ================================================ /* * 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. */ #ifndef ItlDriverInfo_h #define ItlDriverInfo_h class ItlDriverInfo { public: virtual const char *getFirmwareVersion() = 0; virtual int16_t getBSSNoise() = 0; virtual bool is5GBandSupport() = 0; virtual int getTxNSS() = 0; virtual const char *getFirmwareName() = 0; virtual UInt32 supportedFeatures() = 0; virtual const char *getFirmwareCountryCode() = 0; virtual uint32_t getTxQueueSize() = 0; }; #endif /* ItlDriverInfo_h */ ================================================ FILE: include/HAL/ItlHalService.cpp ================================================ /* * 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 "ItlHalService.hpp" #define super OSObject OSDefineMetaClassAndAbstractStructors(ItlHalService, OSObject) bool ItlHalService:: initWithController(IOEthernetController *controller, IOWorkLoop *workloop, IOCommandGate *commandGate) { this->controller = controller; this->controller->retain(); this->mainWorkLoop = workloop; this->mainWorkLoop->retain(); this->mainCommandGate = commandGate; this->mainCommandGate->retain(); this->inner_attr = lck_attr_alloc_init(); this->inner_gp_attr = lck_grp_attr_alloc_init(); this->inner_gp = lck_grp_alloc_init("itlwm_tsleep", this->inner_gp_attr); this->inner_lock = lck_mtx_alloc_init(this->inner_gp, this->inner_attr); return true; } IOEthernetController *ItlHalService:: getController() { return this->controller; } IOCommandGate *ItlHalService:: getMainCommandGate() { return this->mainCommandGate; } IOWorkLoop *ItlHalService:: getMainWorkLoop() { return this->mainWorkLoop; } void ItlHalService:: wakeupOn(void *ident) { // XYLog("%s\n", __FUNCTION__); wakeup(ident); } int ItlHalService:: tsleep_nsec(void *ident, int priority, const char *wmesg, int timo) { // XYLog("%s %s\n", __FUNCTION__, wmesg); struct timespec ts; int err; memset(&ts, 0, sizeof(struct timespec)); ts.tv_nsec = timo; lck_mtx_lock(this->inner_lock); err = msleep(ident, this->inner_lock, priority, wmesg, &ts); lck_mtx_unlock(this->inner_lock); return err; } void ItlHalService:: free() { XYLog("%s\n", __PRETTY_FUNCTION__); if (this->mainWorkLoop) { this->mainWorkLoop->release(); } this->mainWorkLoop = NULL; if (this->mainCommandGate) { this->mainCommandGate->release(); } this->mainCommandGate = NULL; if (this->controller) { this->controller->release(); } if (this->inner_lock) { lck_attr_free(this->inner_attr); lck_mtx_free(this->inner_lock, this->inner_gp); lck_grp_free(this->inner_gp); lck_grp_attr_free(this->inner_gp_attr); this->inner_lock = NULL; } this->controller = NULL; super::free(); } ================================================ FILE: include/HAL/ItlHalService.hpp ================================================ /* * 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. */ #ifndef ItlHalService_hpp #define ItlHalService_hpp #include #include #include #include #include #include #include #include #include "ItlDriverInfo.hpp" #include "ItlDriverController.hpp" #include class ItlHalService : public OSObject { OSDeclareAbstractStructors(ItlHalService) public: virtual bool attach(IOPCIDevice *device) = 0; virtual void detach(IOPCIDevice *device) = 0; virtual IOReturn enable(IONetworkInterface *interface) = 0; virtual IOReturn disable(IONetworkInterface *interface) = 0; virtual struct ieee80211com *get80211Controller() = 0; virtual ItlDriverInfo *getDriverInfo() = 0; virtual ItlDriverController *getDriverController() = 0; virtual void free() override; public: virtual bool initWithController(IOEthernetController *controller, IOWorkLoop *workloop, IOCommandGate *commandGate); protected: int tsleep_nsec(void *ident, int priority, const char *wmesg, int timo); void wakeupOn(void* ident); IOEthernetController *getController(); IOCommandGate *getMainCommandGate(); IOWorkLoop *getMainWorkLoop(); private: IOEthernetController *controller; IOCommandGate *mainCommandGate; IOWorkLoop *mainWorkLoop; lck_grp_t *inner_gp; lck_grp_attr_t *inner_gp_attr; lck_attr_t *inner_attr; lck_mtx_t *inner_lock; }; #endif /* ItlHalService_hpp */ ================================================ FILE: itl80211/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 IOKitPersonalities NSHumanReadableCopyright Copyright © 2020 钟先耀. All rights reserved. OSBundleLibraries ================================================ FILE: itl80211/compat.cpp ================================================ /* * 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. */ // // compat.cpp // net80211 // // Copyright (c) 2012 Prashant Vaibhav. All rights reserved. // #include "compat.h" #include #include #include OSDefineMetaClassAndStructors(pci_intr_handle, OSObject) int pci_get_capability(pci_chipset_tag_t chipsettag, pcitag_t pcitag, int capid, int *offsetp, pcireg_t *valuep) { uint8_t offset; UInt32 value = pcitag->findPCICapability(capid, &offset); if (valuep) *valuep = (pcireg_t)value; if (offsetp) *offsetp = offset; if (value == 0) return 0; else return 1; } pcireg_t pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) { return tag->configRead32(reg); } void pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t val) { tag->configWrite32(reg, val); } pcireg_t pci_mapreg_type(pci_chipset_tag_t pc, pcitag_t tag, int reg) { return 0; // XXX this is not needed on OS X, will always be memorymap } int pci_mapreg_map(const struct pci_attach_args *pa, int reg, pcireg_t type, int busflags, bus_space_tag_t *tagp, bus_space_handle_t *handlep, bus_addr_t *basep, bus_size_t *sizep, bus_size_t maxsize) { IOMemoryMap* map = pa->pa_tag->mapDeviceMemoryWithRegister(reg); if (map == 0) return kIOReturnError; *handlep = reinterpret_cast(map->getVirtualAddress()); if (tagp) *tagp = map; if (basep) *basep = map->getVirtualAddress(); if (sizep) *sizep = map->getSize(); return 0; } int pci_intr_map_msix(struct pci_attach_args *pa, int vec, pci_intr_handle_t *ihp) { pci_chipset_tag_t pc = pa->pa_pc; pcitag_t tag = pa->pa_tag; pcireg_t reg; KASSERT(PCI_MSIX_VEC(vec) == vec, "PCI_MSIX_VEC(vec) == vec"); if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, ®) == 0) return 1; if (vec > PCI_MSIX_MC_TBLSZ(reg)) return 1; return pci_intr_map_msi(pa, ihp); } int pci_intr_map_msi(struct pci_attach_args *paa, pci_intr_handle_t *ih) { if (paa == 0 || ih == 0) return 1; *ih = new pci_intr_handle(); if (*ih == 0) return 1; (*ih)->dev = paa->pa_tag; // pci device reference (*ih)->workloop = paa->workloop; return 0; // XXX not required on OS X } int pci_intr_map(struct pci_attach_args *paa, pci_intr_handle_t *ih) { return pci_intr_map_msi(paa, ih); } void interruptTrampoline(OSObject *ih, IOInterruptEventSource *, int count); void interruptTrampoline(OSObject *ih, IOInterruptEventSource *, int count) { pci_intr_handle* _ih = OSDynamicCast(pci_intr_handle, ih); if (_ih == 0) return; _ih->func(_ih->arg); // jump to actual interrupt handler } void* pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level, int (*handler)(void *), void *arg) { ih->arg = arg; ih->intr = IOInterruptEventSource::interruptEventSource(ih, &interruptTrampoline, ih->dev); if (ih->intr == 0) return 0; if (ih->workloop->addEventSource(ih->intr) != kIOReturnSuccess) return 0; ih->intr->enable(); return ih; } void pci_intr_disestablish(pci_chipset_tag_t pc, void *ih) { pci_intr_handle_t intr = (pci_intr_handle_t) ih; intr->workloop->removeEventSource(intr->intr); intr->intr->release(); intr->intr = 0; intr->dev->release(); intr->dev = 0; intr->workloop->release(); intr->workloop = 0; intr->arg = 0; intr->release(); intr = 0; ih = 0; } uint64_t bus_space_read_8(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset) { return *((uint64_t*)(handle + offset)); } void bus_space_write_8(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint64_t value) { *((uint64_t*)(handle + offset)) = value; } uint32_t bus_space_read_4(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset) { return *((uint32_t*)(handle + offset)); } void bus_space_write_1(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint8_t value) { *((uint8_t*)(handle + offset)) = value; } void bus_space_write_4(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint32_t value) { *((uint32_t*)(handle + offset)) = value; } void bus_space_barrier(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, bus_size_t length, int flags) { return; // In OSX device memory access is always uncached and serialized (afaik!) } int bus_dmamap_create(bus_dma_tag_t tag, bus_size_t size, int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) { if (dmamp == 0) return 1; *dmamp = new bus_dmamap; (*dmamp)->cursor = IOMbufNaturalMemoryCursor::withSpecification(maxsegsz, nsegments); if ((*dmamp)->cursor == 0) return 1; else return 0; } IOBufferMemoryDescriptor* alloc_dma_memory(size_t size, mach_vm_address_t alignment,/* void** vaddr, mach_vm_address_t* paddr, */IOOptionBits opts); IOBufferMemoryDescriptor* alloc_dma_memory(size_t size, mach_vm_address_t alignment,/* void** vaddr, mach_vm_address_t* paddr, */IOOptionBits opts = kIOMemoryPhysicallyContiguous | kIOMapInhibitCache) { size_t reqsize; uint64_t phymask; int i; /* if (alignment <= PAGE_SIZE) { reqsize = size; phymask = 0x00000000ffffffffull & (~(alignment - 1)); } else { reqsize = size + alignment; phymask = 0x00000000fffff000ull; /* page-aligned }*/ phymask = 0x00000000ffffffffull & (~(alignment - 1)); reqsize = size; IOBufferMemoryDescriptor* mem = 0; mem = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, opts, reqsize, phymask); if (!mem) return 0; mem->prepare(); /* if (paddr) *paddr = mem->getPhysicalAddress(); if (vaddr) *vaddr = mem->getBytesNoCopy(); /* * Check the alignment and increment by 4096 until we get the * requested alignment. Fail if can't obtain the alignment * we requested. if ((*paddr & (alignment - 1)) != 0) { for (i = 0; i < alignment / 4096; i++) { if ((*paddr & (alignment - 1 )) == 0) break; *paddr += 4096; *vaddr = ((uint8_t*) *vaddr) + 4096; } if (i == alignment / 4096) { mem->complete(); mem->release(); return 0; } }*/ return mem; } int bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags) { // Ignore flags and don't pass in the number of segments, it's not used in the driver (always 1 anyway) if (segs == 0) return 1; *segs = alloc_dma_memory(size, alignment); if (*segs == 0) return 1; else return 0; } int bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs, size_t size, void **kvap, int flags) { // ignore flags, the memory is already mapped as one segment by the call to bus_dmamem_alloc so just return the virtual address if (*segs == 0 || kvap == 0) return 1; *kvap = (*segs)->getBytesNoCopy(); return 0; } bus_addr_t bus_dmamap_get_paddr(bus_dma_segment_t seg) { if (seg == 0) return 0; else return seg->getPhysicalAddress(); } void bus_dmamap_sync(bus_dma_tag_t tag, bus_dmamap_t dmam, bus_addr_t offset, bus_size_t len, int ops) { return; // no syncing, we mapped the memory with cache inhibition so pray it works } void bus_dmamem_unmap(bus_dma_segment_t seg) { if (seg == 0) return; seg->complete(); } void bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs) { if (segs == 0) return; if (*segs == 0) return; (*segs)->release(); *segs = 0; } void bus_dmamap_destroy(bus_dma_tag_t tag, bus_dmamap_t dmam) { if (dmam == 0) return; if (dmam->cursor == 0) return; dmam->cursor->release(); dmam->cursor = 0; delete dmam; } int bus_dmamap_load(bus_dmamap_t map, mbuf_t mb) { if (map == 0 || mb == 0) return 1; map->dm_nsegs = map->cursor->getPhysicalSegmentsWithCoalesce(mb, map->dm_segs, 1); if (map->dm_nsegs == 0) return 1; else return 0; } ================================================ FILE: itl80211/compat.h ================================================ /* * 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. */ // // compat.h // net80211 // // Copyright (c) 2012 Prashant Vaibhav. All rights reserved. // #ifndef net80211_compat_h #define net80211_compat_h // BSD compatibility definitions #include #include #include #include #include #include #include #include #include #include // the following isn't actually used #define BUS_SPACE_BARRIER_READ 0 #define BUS_SPACE_BARRIER_WRITE 0 #define BUS_DMA_NOWAIT 0 #define BUS_DMA_ZERO 0 #define BUS_DMA_COHERENT 0 #define BUS_DMA_READ 0 static inline void USEC_TO_TIMEVAL(uint64_t us, struct timeval *tv) { tv->tv_sec = us / 1000000; tv->tv_usec = us % 1000000; } static inline void NSEC_TO_TIMEVAL(uint64_t ns, struct timeval *tv) { tv->tv_sec = ns / 1000000000L; tv->tv_usec = (ns % 1000000000L) / 1000; } static inline uint64_t TIMEVAL_TO_NSEC(const struct timeval *tv) { uint64_t nsecs; if (tv->tv_sec > UINT64_MAX / 1000000000ULL) return UINT64_MAX; nsecs = tv->tv_sec * 1000000000ULL; if (tv->tv_usec * 1000ULL > UINT64_MAX - nsecs) return UINT64_MAX; return nsecs + tv->tv_usec * 1000ULL; } static inline void NSEC_TO_TIMESPEC(uint64_t ns, struct timespec *ts) { ts->tv_sec = ns / 1000000000L; ts->tv_nsec = ns % 1000000000L; } static inline uint64_t SEC_TO_NSEC(uint64_t seconds) { if (seconds > UINT64_MAX / 1000000000ULL) return UINT64_MAX; return seconds * 1000000000ULL; } static inline uint64_t MSEC_TO_NSEC(uint64_t milliseconds) { if (milliseconds > UINT64_MAX / 1000000ULL) return UINT64_MAX; return milliseconds * 1000000ULL; } static inline uint64_t USEC_TO_NSEC(uint64_t microseconds) { if (microseconds > UINT64_MAX / 1000ULL) return UINT64_MAX; return microseconds * 1000ULL; } static inline uint64_t TIMESPEC_TO_NSEC(const struct timespec *ts) { if (ts->tv_sec > (UINT64_MAX - ts->tv_nsec) / 1000000000ULL) return UINT64_MAX; return ts->tv_sec * 1000000000ULL + ts->tv_nsec; } #define MHLEN mbuf_get_mhlen() #define M_DONTWAIT MBUF_DONTWAIT #define M_EXT MBUF_EXT #define m_freem mbuf_freem #define m_free mbuf_free #define m_copydata mbuf_copydata static inline int flsl(long mask) { int bit; if (mask == 0) return (0); for (bit = 1; mask != 1; bit++) mask = (unsigned long)mask >> 1; return (bit); } /* * Find Last Set bit */ static inline int _fls(int mask) { int bit; if (mask == 0) return (0); for (bit = 1; mask != 1; bit++) mask = (unsigned int)mask >> 1; return (bit); } enum { BUS_DMASYNC_PREREAD, BUS_DMASYNC_PREWRITE, BUS_DMASYNC_POSTREAD, BUS_DMASYNC_POSTWRITE }; typedef int bus_dma_tag_t; typedef IOBufferMemoryDescriptor* bus_dma_segment_t; typedef caddr_t bus_space_handle_t; // pointer to device memory typedef int pci_chipset_tag_t; typedef mach_vm_address_t bus_addr_t; typedef u_int32_t bus_size_t; typedef IOMemoryMap* bus_space_tag_t; typedef IOPCIDevice* pcitag_t; typedef uint32_t pcireg_t; class pci_intr_handle : public OSObject { OSDeclareDefaultStructors(pci_intr_handle) public: IOWorkLoop* workloop; IOInterruptEventSource* intr; IOPCIDevice* dev; void (*func)(void* arg); void* arg; }; typedef pci_intr_handle* pci_intr_handle_t; /* * Actions for ca_activate. */ #define DVACT_DEACTIVATE 1 /* deactivate the device */ #define DVACT_QUIESCE 2 /* warn the device about suspend */ #define DVACT_SUSPEND 3 /* suspend the device */ #define DVACT_RESUME 4 /* resume the device */ #define DVACT_WAKEUP 5 /* tell device to recover after resume */ #define DVACT_POWERDOWN 6 /* power device down */ struct device { IOService *provider; void *_data; char dv_xname[16]; }; struct workq_task { int blah; }; struct pci_attach_args { IOWorkLoop* workloop; pci_chipset_tag_t pa_pc; pcitag_t pa_tag; bus_dma_tag_t pa_dmat; }; struct bus_dmamap { IOMbufNaturalMemoryCursor* cursor; int dm_nsegs; IOPhysicalSegment dm_segs[23]; // reserve space for 8 segments }; typedef struct bus_dmamap* bus_dmamap_t; /* max bufs per tfd the driver will use */ #define IWM_MAX_CMD_TBS_PER_TFD 2 #define IWM_TX_RING_COUNT 256 #define IWM_TX_RING_LOMARK 192 #define IWM_TX_RING_HIMARK 224 struct pci_matchid { int pm_vid; int pm_pid; int pm_sub_dev; int pm_sub_vid; void *drv_data; }; #define PCI_ANY_ID 0xffff static inline int pci_matchbyid(int vid, int pid, const struct pci_matchid *ids, int nent) { const struct pci_matchid *pm; int i; for (i = 0, pm = ids; i < nent; i++, pm++) if (vid == pm->pm_vid && pid == pm->pm_pid) return (1); return (0); } static inline int pci_match(int vid, int pid, int sub_vid, int sub_dev, const struct pci_matchid *ids, int nent, void **drv_data) { const struct pci_matchid *pm; int i; for (i = 0, pm = ids; i < nent; i++, pm++) { if (vid == pm->pm_vid && pid == pm->pm_pid) { if (pm->pm_sub_dev != PCI_ANY_ID && sub_dev != pm->pm_sub_dev) { return 0; } if (pm->pm_sub_vid != PCI_ANY_ID && sub_vid != pm->pm_sub_vid) { return 0; } if (drv_data) { *drv_data = pm->drv_data; } return 1; } } return 0; } /* * DMA glue is from iwn */ char* ether_sprintf(const u_char *ap); int pci_get_capability(pci_chipset_tag_t chipsettag, pcitag_t pcitag, int capid, int *offsetp, pcireg_t *valuep); pcireg_t pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg); void pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t val); pcireg_t pci_mapreg_type(pci_chipset_tag_t pc, pcitag_t tag, int reg); int pci_mapreg_map(const struct pci_attach_args *pa, int reg, pcireg_t type, int busflags, bus_space_tag_t *tagp, bus_space_handle_t *handlep, bus_addr_t *basep, bus_size_t *sizep, bus_size_t maxsize); int pci_intr_map_msix(struct pci_attach_args *pa, int vec, pci_intr_handle_t *ihp); int pci_intr_map_msi(struct pci_attach_args *paa, pci_intr_handle_t *ih); int pci_intr_map(struct pci_attach_args *paa, pci_intr_handle_t *ih); void* pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level, int (*handler)(void *), void *arg); void pci_intr_disestablish(pci_chipset_tag_t pc, void *ih); uint64_t bus_space_read_8(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset); void bus_space_write_8(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint64_t value); uint32_t bus_space_read_4(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset); void bus_space_write_4(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint32_t value); void bus_space_write_1(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, uint8_t value); void bus_space_barrier(bus_space_tag_t space, bus_space_handle_t handle, bus_size_t offset, bus_size_t length, int flags); int bus_dmamap_create(bus_dma_tag_t tag, bus_size_t size, int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp); int bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags); int bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs, size_t size, void **kvap, int flags); bus_addr_t bus_dmamap_get_paddr(bus_dma_segment_t seg); // XXX new void bus_dmamap_sync(bus_dma_tag_t tag, bus_dmamap_t dmam, bus_addr_t offset, bus_size_t len, int ops); void bus_dmamem_unmap(bus_dma_segment_t seg); // XXX changed args void bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs); void bus_dmamap_destroy(bus_dma_tag_t tag, bus_dmamap_t dmam); int bus_dmamap_load(bus_dmamap_t map, mbuf_t m); #define bus_dmamap_load_mbuf bus_dmamap_load #endif ================================================ FILE: itl80211/linux/bitfield.h ================================================ // // bitfield.h // AppleIntelWifiAdapter // // Created by qcwap on 2020/1/5. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef bitfield_h #define bitfield_h #include #include #define BITS_PER_LONG 64 #define BITS_PER_LONG_LONG 64 #define BIT(nr) (1UL << (nr)) #define BIT_ULL(nr) (1ULL << (nr)) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) #define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG)) #define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG) #define BITS_PER_BYTE 8 #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) #define __bf_shf(x) (__builtin_ffsll(x) - 1) #define FIELD_PREP(_mask, _val) \ ({ \ ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ }) static inline int find_first_zero_bit(volatile void *p, int max) { int b; volatile u_int *ptr = (volatile u_int *)p; for (b = 0; b < max; b += 32) { if (ptr[b >> 5] != ~0) { for (;;) { if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0) return b; b++; } } } return max; } static inline int find_next_zero_bit(volatile void *p, int max, int b) { volatile u_int *ptr = (volatile u_int *)p; for (; b < max; b += 32) { if (ptr[b >> 5] != ~0) { for (;;) { if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0) return b; b++; } } } return max; } static inline int find_first_bit(volatile void *p, int max) { int b; volatile u_int *ptr = (volatile u_int *)p; for (b = 0; b < max; b += 32) { if (ptr[b >> 5] != 0) { for (;;) { if (ptr[b >> 5] & (1 << (b & 0x1f))) return b; b++; } } } return max; } static inline int find_next_bit(volatile void *p, int max, int b) { volatile u_int *ptr = (volatile u_int *)p; for (; b < max; b+= 32) { if (ptr[b >> 5] != 0) { for (;;) { if (ptr[b >> 5] & (1 << (b & 0x1f))) return b; b++; } } } return max; } static inline int find_last_bit(volatile void *p, int max) { int b; volatile u_int *ptr = (volatile u_int *)p; for (b = max; b > 0; b -= 32) { if (ptr[b >> 5] != 0) { for (;;) { if (ptr[b >> 5] & (1 << (b & 0x1f))) return b; b--; } } } return max; } #define for_each_set_bit(bit, addr, size) \ for ((bit) = find_first_bit((addr), (size)); \ (bit) < (size); \ (bit) = find_next_bit((addr), (size), (bit) + 1)) #define GENMASK(h, l) \ (((~(0UL)) - ((1UL) << (l)) + 1) & \ (~(0UL) >> (BITS_PER_LONG - 1 - (h)))) #define GENMASK_ULL(h, l) \ (((~(0ULL)) - ((1ULL) << (l)) + 1) & \ (~(0ULL) >> (BITS_PER_LONG_LONG - 1 - (h)))) static inline UInt64 OSBitwiseAtomic64(unsigned long and_mask, unsigned long or_mask, unsigned long xor_mask, unsigned long * value) { unsigned long oldValue; unsigned long newValue; do { oldValue = *value; newValue = ((oldValue & and_mask) | or_mask) ^ xor_mask; } while (! OSCompareAndSwap64(oldValue, newValue, value)); return oldValue; } static inline unsigned long OSBitAndAtomic64(unsigned long mask, unsigned long * value) { return OSBitwiseAtomic64(mask, 0, 0, value); } static inline unsigned long OSBitOrAtomic64(unsigned long mask, unsigned long * value) { return OSBitwiseAtomic64(-1, mask, 0, value); } static inline void set_bit(int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); OSBitOrAtomic64(mask, p); } static inline void clear_bit(int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); OSBitAndAtomic64(~mask, p); } static inline int test_and_set_bit(int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); unsigned long old; old = *p; *p = old | mask; return (old & mask) != 0; } static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) { unsigned long mask = BIT_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); unsigned long old; old = *p; *p = old & ~mask; return (old & mask) != 0; } static inline int test_bit(int nr, const volatile unsigned long *addr) { return (OSAddAtomic(0, addr) & (1 << nr)) != 0; } static inline int linux_fls(int x) { int r = 32; if (!x) return 0; if (!(x & 0xffff0000u)) { x <<= 16; r -= 16; } if (!(x & 0xff000000u)) { x <<= 8; r -= 8; } if (!(x & 0xf0000000u)) { x <<= 4; r -= 4; } if (!(x & 0xc0000000u)) { x <<= 2; r -= 2; } if (!(x & 0x80000000u)) { x <<= 1; r -= 1; } return r; } #endif /* bitfield_h */ ================================================ FILE: itl80211/linux/kernel.h ================================================ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef kernel_h #define kernel_h #include #include #include #include #define ERFKILL 132 /* Operation not possible due to RF-kill */ #define EHWPOISON 133 /* Memory page has hardware error */ /* Defined for the NFSv3 protocol */ #define EBADHANDLE 521 /* Illegal NFS file handle */ #define ENOTSYNC 522 /* Update synchronization mismatch */ #define EBADCOOKIE 523 /* Cookie is stale */ #define ENOTSUPP 524 /* Operation is not supported */ #define ETOOSMALL 525 /* Buffer or request is too small */ #define ESERVERFAULT 526 /* An untranslatable error occurred */ #define EBADTYPE 527 /* Type not supported by server */ #define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */ #define EIOCBQUEUED 529 /* iocb queued, will get completion event */ #define ERECALLCONFLICT 530 /* conflict with recalled state */ #define min_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) #define max_t(type, x, y) \ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) #define OS_EXPECT(x, v) __builtin_expect((x), (v)) #define likely(x) OS_EXPECT(!!(x), 1) #define unlikely(x) ({ \ OS_EXPECT(!!(x), 0); \ !!(x); \ }) # define do_div(n,base) ({ \ uint32_t __base = (base); \ uint32_t __rem; \ __rem = ((uint64_t)(n)) % __base; \ (n) = ((uint64_t)(n)) / __base; \ __rem; \ }) #define MAX_ERRNO 4095 //判断x是不是在(0xfffff000,0xffffffff)之间,注意这里用unlikely()的用意 #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) //由错误码求指针,-1 -> 0xFFFFFFFF static inline void *ERR_PTR(long error) { return (void *) error; } //由指针求错误码,0xFFFFFFFF -> -1 ,依次类推 static inline long PTR_ERR(const void *ptr) { return (long) ptr; } //判断x是不是在(0xfffff000,0xffffffff)之间,x是不是一个有效的指针 static inline long IS_ERR(const void *ptr) { return IS_ERR_VALUE((unsigned long)ptr); } static inline int fls64(UInt64 x) { int bitpos = -1; /* * AMD64 says BSRQ won't clobber the dest reg if x==0; Intel64 says the * dest reg is undefined if x==0, but their CPU architect says its * value is written to set it to the same as before. */ asm("bsrq %1,%q0" : "+r" (bitpos) : "rm" (x)); return bitpos + 1; } static inline const char *reverse_strchr(const char *s, int c) { char *find = NULL; const char *ss = s; while (*ss != '\0' && (find = strchr(ss, c))) { ss = ++find; } return ss; } #ifndef strrchr #define strrchr(x, y) reverse_strchr((x), (y)) #endif /* * Runtime evaluation of get_order() */ static inline int __get_order(unsigned long size) { int order; size--; size >>= PAGE_SHIFT; #if BITS_PER_LONG == 32 order = linux_fls(size); #else order = fls64(size); #endif return order; } /** * get_order - Determine the allocation order of a memory size * @size: The size for which to get the order * * Determine the allocation order of a particular sized block of memory. This * is on a logarithmic scale, where: * * 0 -> 2^0 * PAGE_SIZE and below * 1 -> 2^1 * PAGE_SIZE to 2^0 * PAGE_SIZE + 1 * 2 -> 2^2 * PAGE_SIZE to 2^1 * PAGE_SIZE + 1 * 3 -> 2^3 * PAGE_SIZE to 2^2 * PAGE_SIZE + 1 * 4 -> 2^4 * PAGE_SIZE to 2^3 * PAGE_SIZE + 1 * ... * * The order returned is used to find the smallest allocation granule required * to hold an object of the specified size. * * The result is undefined if the size is 0. * * This function may be used to initialise variables with compile time * evaluations of constants. */ #define get_order(n) \ ( \ __builtin_constant_p(n) ? ( \ ((n) == 0UL) ? BITS_PER_LONG - PAGE_SHIFT : \ (((n) < (1UL << PAGE_SHIFT)) ? 0 : \ ilog2((n) - 1) - PAGE_SHIFT + 1) \ ) : \ __get_order(n) \ ) /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ pointer_t __mptr = (pointer_t)(ptr); \ ((type *)(__mptr - offsetof(type, member))); }) /* * This looks more complex than it should be. But we need to * get the type for the ~ right in round_down (it needs to be * as wide as the result!), and we want to evaluate the macro * arguments just once each. */ #define __round_mask(x, y) ((__typeof__(x))((y)-1)) #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) #define round_down(x, y) ((x) & ~__round_mask(x, y)) #define jiffies \ ({ \ uint64_t m,f; \ clock_get_uptime(&m); \ absolutetime_to_nanoseconds(m,&f); \ ((f * HZ) / 1000000000); \ }) #define time_after(a,b) \ ((long)(b) - (long)(a) < 0) #define time_is_before_jiffies(a) time_after(ticks, a) #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) #define struct_size(x, y, l) (sizeof(*x) + sizeof(*y) * l) // log2.h /* * Determine whether some value is a power of two, where zero is * *not* considered a power of two. */ static inline __attribute__((const)) bool is_power_of_2(unsigned long n) { return (n != 0 && ((n & (n - 1)) == 0)); } /** * kmemdup - duplicate region of memory * * @src: memory region to duplicate * @len: memory region length * @gfp: GFP mask to use */ static inline void *kmemdup(const void *src, size_t len) { void *p; p = IOMalloc(len); if (p) memcpy(p, src, len); return p; } static inline void* kcalloc(size_t n, size_t size) { if (size != 0 && n > SIZE_MAX / size) { return NULL; } void *ret = IOMalloc(n * size); if (ret) { bzero(ret, n * size); } return ret; } static inline void* kzalloc(size_t size) { void *ret = IOMalloc(size); if (ret) { bzero(ret, size); } return ret; } static inline int atomic_dec_and_test(volatile SInt32 * addr) { return ((OSDecrementAtomic(addr) == 1) ? 1 : 0); } static inline int atomic_inc_and_test(volatile SInt32 * addr) { return ((OSIncrementAtomic(addr) == -1) ? 1 : 0); } #define atomic_inc(v) OSIncrementAtomic(v) #define atomic_dec(v) OSDecrementAtomic(v) #if __has_builtin(__builtin_abs) #define abs(N) __builtin_abs((N)) #else #define abs(N) (((N)<0)?-(N):(N)) #endif /* __has_builtin(__builtin_abs) */ #endif /* kernel_h */ ================================================ FILE: itl80211/linux/random.h ================================================ // // random.h // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/22. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef random_h #define random_h #include static inline void get_random_bytes(void *buf, int nbytes) { random_buf(buf, nbytes); } #endif /* random_h */ ================================================ FILE: itl80211/linux/types.h ================================================ // // types.h // AppleIntelWifiAdapter // // Created by qcwap on 2020/1/5. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef types_h #define types_h #include #include #include #define local_bh_disable() #define local_bh_enable() #define NUM_DEFAULT_KEYS 4 #define NUM_DEFAULT_MGMT_KEYS 2 #define gfp_t int #define __packed __attribute__((packed)) __attribute__((aligned(1))) #define __aligned(x) __attribute__((aligned(x))) #define __must_check __attribute__((warn_unused_result)) /* #define MODULE_FIRMWARE(fw) #define MODULE_DESCRIPTION(x) #define MODULE_AUTHOR(x) #define MODULE_LICENSE(x) #define __init #define __exit #define module_init(x) #define module_exit(x) */ #define pr_info(x) #define __rcu # define __acquires(x) # define __releases(x) # define __acquire(x) (void)0 # define __release(x) (void)0 #define might_sleep() #define __bitwise #define __force #define list_head queue_entry #ifndef __WARN_printf /* * To port this properly we'd have to port warn_slowpath_null(), * which I'm lazy to do so just do a regular print for now. If you * want to port this read kernel/panic.c */ #define __WARN_printf(func, line, arg...) do { IOLog("(AppleIntelWifiAdapter) (%s:%d) WARN", func, line);} while (0); #endif #ifndef unlikely #include #endif #ifndef WARN_ON_ONCE #define WARN_ON_ONCE(condition, fmt...) ({ \ static int __warned; \ int __ret_warn_once = !!(condition); \ \ if(unlikely(__ret_warn_once)) \ if(WARN_ON(!__warned, fmt...)) \ __warned = 1; \ unlikely(__ret_warn_once); \ (bool)__ret_warn_once; \ }) #endif #ifndef WARN_ON #define WARN_ON(condition, fmt...) ({ \ int __ret_warn_on = !!(condition); \ if(unlikely(__ret_warn_on)) \ __WARN_printf(__FUNCTION__, __LINE__, fmt...) \ unlikely(__ret_warn_on); \ (bool)(__ret_warn_on);\ }) #endif #define __stringify OS_STRINGIFY #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #define XYLog(fmt, x...)\ do\ {\ kprintf("%s: " fmt, "itlwm", ##x);\ }while(0) typedef UInt8 u8; typedef UInt16 u16; typedef UInt32 u32; typedef UInt64 u64; typedef u8 __u8; typedef u16 __u16; typedef u32 __u32; typedef u64 __u64; typedef SInt16 __be16; typedef SInt32 __be32; typedef SInt64 __be64; typedef SInt16 __le16; typedef SInt32 __le32; typedef SInt64 __le64; typedef SInt8 s8; typedef SInt16 s16; typedef SInt32 s32; typedef SInt64 s64; typedef s8 __s8; typedef s16 __s16; typedef s32 __s32; typedef s64 __s64; typedef UInt16 __sum16; typedef u64 dma_addr_t; #define U8_MAX ((u8)~0U) #define S8_MAX ((s8)(U8_MAX >> 1)) #define S8_MIN ((s8)(-S8_MAX - 1)) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) #define lower_32_bits(n) ((u32)(n)) #define __cpu_to_le64(x) ((__force __le64)(__u64)(x)) #define __le64_to_cpu(x) ((__force __u64)(__le64)(x)) #define __cpu_to_le32(x) ((__force __le32)(__u32)(x)) #define __le32_to_cpu(x) ((__force __u32)(__le32)(x)) #define __cpu_to_le16(x) ((__force __le16)(__u16)(x)) #define __le16_to_cpu(x) ((__force __u16)(__le16)(x)) #define __cpu_to_be64(x) ((__force __be64)__swab64((x))) #define __be64_to_cpu(x) __swab64((__force __u64)(__be64)(x)) #define __cpu_to_be32(x) ((__force __be32)__swab32((x))) #define __be32_to_cpu(x) __swab32((__force __u32)(__be32)(x)) #define __cpu_to_be16(x) ((__force __be16)__swab16((x))) #define __be16_to_cpu(x) __swab16((__force __u16)(__be16)(x)) #define cpu_to_le64 __cpu_to_le64 #define le64_to_cpu __le64_to_cpu #define cpu_to_le32 __cpu_to_le32 #define le32_to_cpu __le32_to_cpu #define cpu_to_le16 __cpu_to_le16 #define le16_to_cpu __le16_to_cpu #define cpu_to_be64 OSSwapHostToBigInt64 #define be64_to_cpu OSSwapBigToHostInt64 #define cpu_to_be32 OSSwapHostToBigInt32 #define be32_to_cpu OSSwapBigToHostInt32 #define cpu_to_be16 OSSwapHostToBigInt16 #define be16_to_cpu OSSwapBigToHostInt16 static inline __u16 __be16_to_cpup(const __be16 *p) { return (__force __u16)*p; } static inline __u32 __be32_to_cpup(const __be32 *p) { return (__force __u32)*p; } static inline __be32 __cpu_to_be32p(const __u32 *p) { return (__force __be32)*p; } static inline __u64 __be64_to_cpup(const __be64 *p) { return (__force __u64)*p; } static inline __be64 __cpu_to_be64p(const __u64 *p) { return (__force __be64)*p; } static inline __u32 __le32_to_cpup(const __le32 *p) { return (__force __u32)*p; } static inline __u16 __le16_to_cpup(const __le16 *p) { return (__force __u16)*p; } #define le16_to_cpup(_a_) ((__uint16_t)(*(const uint16_t *)(_a_))) #define le32_to_cpup(_a_) ((__uint32_t)(*(const uint32_t *)(_a_))) static inline u32 get_unaligned_le32(const void *p) { return le32_to_cpup((__le32 *)p); } static inline u32 get_unaligned_le16(const void *p) { return le16_to_cpup((__le16 *)p); } static inline void put_unaligned_le32(u32 val, void *p) { *((__le32 *)p) = cpu_to_le32(val); } static inline unsigned int hweight8(unsigned int w) { unsigned int res = w - ((w >> 1) & 0x55); res = (res & 0x33) + ((res >> 2) & 0x33); return (res + (res >> 4)) & 0x0F; } static inline unsigned int hweight16(unsigned int w) { unsigned int res = w - ((w >> 1) & 0x5555); res = (res & 0x3333) + ((res >> 2) & 0x3333); res = (res + (res >> 4)) & 0x0F0F; return (res + (res >> 8)) & 0x00FF; } static inline unsigned int hweight32(unsigned int w) { unsigned int res = w - ((w >> 1) & 0x55555555); res = (res & 0x33333333) + ((res >> 2) & 0x33333333); res = (res + (res >> 4)) & 0x0F0F0F0F; res = res + (res >> 8); return (res + (res >> 16)) & 0x000000FF; } static inline unsigned long hweight64(uint64_t w) { uint64_t res = w - ((w >> 1) & 0x5555555555555555ul); res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful; res = res + (res >> 8); res = res + (res >> 16); return (res + (res >> 32)) & 0x00000000000000FFul; } static inline uint64_t field_multiplier(uint64_t field) { return field & -field; } static inline uint64_t field_mask(uint64_t field) { return field / field_multiplier(field); } /** * sizeof_field(TYPE, MEMBER) * * @TYPE: The structure containing the field of interest * @MEMBER: The field to return the size of */ #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) /** * offsetofend(TYPE, MEMBER) * * @TYPE: The type of the structure * @MEMBER: The member within the structure to get the end offset of */ #define offsetofend(TYPE, MEMBER) \ (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER)) #define ____MAKE_OP(type,base,to,from) \ static inline __##type type##_encode_bits(base v, base field) \ { \ return to((v & field_mask(field)) * field_multiplier(field)); \ } \ static inline __##type type##_replace_bits(__##type old, \ base val, base field) \ { \ return (old & ~to(field)) | type##_encode_bits(val, field); \ } \ static inline void type##p_replace_bits(__##type *p, \ base val, base field) \ { \ *p = (*p & ~to(field)) | type##_encode_bits(val, field); \ } \ static inline base type##_get_bits(__##type v, base field) \ { \ return (from(v) & field)/field_multiplier(field); \ } #define __MAKE_OP(size) \ ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \ ____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu) \ ____MAKE_OP(u##size,u##size,,) ____MAKE_OP(u8,u8,,) __MAKE_OP(16) __MAKE_OP(32) __MAKE_OP(64) #undef __MAKE_OP #undef ____MAKE_OP #define atomic_t volatile SInt32 #define atomic64_t volatile SInt64 #define ETHTOOL_FWVERS_LEN 32 #define RT_ALIGN_T(u, uAlignment, type) ( ((type)(u) + ((uAlignment) - 1)) & ~(type)((uAlignment) - 1) ) #define RT_ALIGN_Z(cb, uAlignment) RT_ALIGN_T(cb, uAlignment, size_t) #define LNX_ALIGN RT_ALIGN_Z #define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) #define _ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1) #define _usec_delay(x) IODelay(x) #define _msec_delay(x) IOSleep(x) #define _udelay(x) IODelay(x) #define _mdelay(x) IODelay(1000*(x)) #define _msleep(x) IOSleep(x) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define usleep_range(min, max) _msleep(DIV_ROUND_UP(min, 1000)) #endif /* types_h */ ================================================ FILE: itl80211/openbsd/crypto/aes.c ================================================ /* * Copyright (c) 2016 Thomas Pornin * * Modified for OpenBSD by Thomas Pornin and Mike Belopuhov. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include "aes.h" static inline void enc32le(void *dst, uint32_t x) { unsigned char *buf = (unsigned char *)dst; buf[0] = (unsigned char)x; buf[1] = (unsigned char)(x >> 8); buf[2] = (unsigned char)(x >> 16); buf[3] = (unsigned char)(x >> 24); } static inline uint32_t dec32le(const void *src) { const unsigned char *buf = (const unsigned char *)src; return (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24); } /* * This constant-time implementation is "bitsliced": the 128-bit state is * split over eight 32-bit words q* in the following way: * * -- Input block consists in 16 bytes: * a00 a10 a20 a30 a01 a11 a21 a31 a02 a12 a22 a32 a03 a13 a23 a33 * In the terminology of FIPS 197, this is a 4x4 matrix which is read * column by column. * * -- Each byte is split into eight bits which are distributed over the * eight words, at the same rank. Thus, for a byte x at rank k, bit 0 * (least significant) of x will be at rank k in q0 (if that bit is b, * then it contributes "b << k" to the value of q0), bit 1 of x will be * at rank k in q1, and so on. * * -- Ranks given to bits are in "row order" and are either all even, or * all odd. Two independent AES states are thus interleaved, one using * the even ranks, the other the odd ranks. Row order means: * a00 a01 a02 a03 a10 a11 a12 a13 a20 a21 a22 a23 a30 a31 a32 a33 * * Converting input bytes from two AES blocks to bitslice representation * is done in the following way: * -- Decode first block into the four words q0 q2 q4 q6, in that order, * using little-endian convention. * -- Decode second block into the four words q1 q3 q5 q7, in that order, * using little-endian convention. * -- Call aes_ct_ortho(). * * Converting back to bytes is done by using the reverse operations. Note * that aes_ct_ortho() is its own inverse. */ /* * The AES S-box, as a bitsliced constant-time version. The input array * consists in eight 32-bit words; 32 S-box instances are computed in * parallel. Bits 0 to 7 of each S-box input (bit 0 is least significant) * are spread over the words 0 to 7, at the same rank. */ static void aes_ct_bitslice_Sbox(uint32_t *q) { /* * This S-box implementation is a straightforward translation of * the circuit described by Boyar and Peralta in "A new * combinational logic minimization technique with applications * to cryptology" (https://eprint.iacr.org/2009/191.pdf). * * Note that variables x* (input) and s* (output) are numbered * in "reverse" order (x0 is the high bit, x7 is the low bit). */ uint32_t x0, x1, x2, x3, x4, x5, x6, x7; uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9; uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19; uint32_t y20, y21; uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9; uint32_t z10, z11, z12, z13, z14, z15, z16, z17; uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19; uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29; uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39; uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49; uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59; uint32_t t60, t61, t62, t63, t64, t65, t66, t67; uint32_t s0, s1, s2, s3, s4, s5, s6, s7; x0 = q[7]; x1 = q[6]; x2 = q[5]; x3 = q[4]; x4 = q[3]; x5 = q[2]; x6 = q[1]; x7 = q[0]; /* * Top linear transformation. */ y14 = x3 ^ x5; y13 = x0 ^ x6; y9 = x0 ^ x3; y8 = x0 ^ x5; t0 = x1 ^ x2; y1 = t0 ^ x7; y4 = y1 ^ x3; y12 = y13 ^ y14; y2 = y1 ^ x0; y5 = y1 ^ x6; y3 = y5 ^ y8; t1 = x4 ^ y12; y15 = t1 ^ x5; y20 = t1 ^ x1; y6 = y15 ^ x7; y10 = y15 ^ t0; y11 = y20 ^ y9; y7 = x7 ^ y11; y17 = y10 ^ y11; y19 = y10 ^ y8; y16 = t0 ^ y11; y21 = y13 ^ y16; y18 = x0 ^ y16; /* * Non-linear section. */ t2 = y12 & y15; t3 = y3 & y6; t4 = t3 ^ t2; t5 = y4 & x7; t6 = t5 ^ t2; t7 = y13 & y16; t8 = y5 & y1; t9 = t8 ^ t7; t10 = y2 & y7; t11 = t10 ^ t7; t12 = y9 & y11; t13 = y14 & y17; t14 = t13 ^ t12; t15 = y8 & y10; t16 = t15 ^ t12; t17 = t4 ^ t14; t18 = t6 ^ t16; t19 = t9 ^ t14; t20 = t11 ^ t16; t21 = t17 ^ y20; t22 = t18 ^ y19; t23 = t19 ^ y21; t24 = t20 ^ y18; t25 = t21 ^ t22; t26 = t21 & t23; t27 = t24 ^ t26; t28 = t25 & t27; t29 = t28 ^ t22; t30 = t23 ^ t24; t31 = t22 ^ t26; t32 = t31 & t30; t33 = t32 ^ t24; t34 = t23 ^ t33; t35 = t27 ^ t33; t36 = t24 & t35; t37 = t36 ^ t34; t38 = t27 ^ t36; t39 = t29 & t38; t40 = t25 ^ t39; t41 = t40 ^ t37; t42 = t29 ^ t33; t43 = t29 ^ t40; t44 = t33 ^ t37; t45 = t42 ^ t41; z0 = t44 & y15; z1 = t37 & y6; z2 = t33 & x7; z3 = t43 & y16; z4 = t40 & y1; z5 = t29 & y7; z6 = t42 & y11; z7 = t45 & y17; z8 = t41 & y10; z9 = t44 & y12; z10 = t37 & y3; z11 = t33 & y4; z12 = t43 & y13; z13 = t40 & y5; z14 = t29 & y2; z15 = t42 & y9; z16 = t45 & y14; z17 = t41 & y8; /* * Bottom linear transformation. */ t46 = z15 ^ z16; t47 = z10 ^ z11; t48 = z5 ^ z13; t49 = z9 ^ z10; t50 = z2 ^ z12; t51 = z2 ^ z5; t52 = z7 ^ z8; t53 = z0 ^ z3; t54 = z6 ^ z7; t55 = z16 ^ z17; t56 = z12 ^ t48; t57 = t50 ^ t53; t58 = z4 ^ t46; t59 = z3 ^ t54; t60 = t46 ^ t57; t61 = z14 ^ t57; t62 = t52 ^ t58; t63 = t49 ^ t58; t64 = z4 ^ t59; t65 = t61 ^ t62; t66 = z1 ^ t63; s0 = t59 ^ t63; s6 = t56 ^ ~t62; s7 = t48 ^ ~t60; t67 = t64 ^ t65; s3 = t53 ^ t66; s4 = t51 ^ t66; s5 = t47 ^ t65; s1 = t64 ^ ~s3; s2 = t55 ^ ~t67; q[7] = s0; q[6] = s1; q[5] = s2; q[4] = s3; q[3] = s4; q[2] = s5; q[1] = s6; q[0] = s7; } /* * Perform bytewise orthogonalization of eight 32-bit words. Bytes * of q0..q7 are spread over all words: for a byte x that occurs * at rank i in q[j] (byte x uses bits 8*i to 8*i+7 in q[j]), the bit * of rank k in x (0 <= k <= 7) goes to q[k] at rank 8*i+j. * * This operation is an involution. */ static void aes_ct_ortho(uint32_t *q) { #define SWAPN(cl, ch, s, x, y) do { \ uint32_t a, b; \ a = (x); \ b = (y); \ (x) = (a & (uint32_t)cl) | ((b & (uint32_t)cl) << (s)); \ (y) = ((a & (uint32_t)ch) >> (s)) | (b & (uint32_t)ch); \ } while (0) #define SWAP2(x, y) SWAPN(0x55555555, 0xAAAAAAAA, 1, x, y) #define SWAP4(x, y) SWAPN(0x33333333, 0xCCCCCCCC, 2, x, y) #define SWAP8(x, y) SWAPN(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y) SWAP2(q[0], q[1]); SWAP2(q[2], q[3]); SWAP2(q[4], q[5]); SWAP2(q[6], q[7]); SWAP4(q[0], q[2]); SWAP4(q[1], q[3]); SWAP4(q[4], q[6]); SWAP4(q[5], q[7]); SWAP8(q[0], q[4]); SWAP8(q[1], q[5]); SWAP8(q[2], q[6]); SWAP8(q[3], q[7]); } static inline uint32_t sub_word(uint32_t x) { uint32_t q[8]; int i; for (i = 0; i < 8; i ++) { q[i] = x; } aes_ct_ortho(q); aes_ct_bitslice_Sbox(q); aes_ct_ortho(q); return q[0]; } static const unsigned char Rcon[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 }; /* * Base key schedule code. The function sub_word() must be defined * below. Subkeys are produced in little-endian convention (but not * bitsliced). Key length is expressed in bytes. */ static unsigned aes_keysched_base(uint32_t *skey, const void *key, size_t key_len) { unsigned num_rounds; int i, j, k, nk, nkf; uint32_t tmp; switch (key_len) { case 16: num_rounds = 10; break; case 24: num_rounds = 12; break; case 32: num_rounds = 14; break; default: return 0; } nk = (int)(key_len >> 2); nkf = (int)((num_rounds + 1) << 2); for (i = 0; i < nk; i ++) { tmp = dec32le((const unsigned char *)key + (i << 2)); skey[i] = tmp; } tmp = skey[(key_len >> 2) - 1]; for (i = nk, j = 0, k = 0; i < nkf; i ++) { if (j == 0) { tmp = (tmp << 24) | (tmp >> 8); tmp = sub_word(tmp) ^ Rcon[k]; } else if (nk > 6 && j == 4) { tmp = sub_word(tmp); } tmp ^= skey[i - nk]; skey[i] = tmp; if (++ j == nk) { j = 0; k ++; } } return num_rounds; } /* * AES key schedule, constant-time version. skey[] is filled with n+1 * 128-bit subkeys, where n is the number of rounds (10 to 14, depending * on key size). The number of rounds is returned. If the key size is * invalid (not 16, 24 or 32), then 0 is returned. */ unsigned aes_ct_keysched(uint32_t *comp_skey, const void *key, size_t key_len) { uint32_t skey[60]; unsigned u, num_rounds; num_rounds = aes_keysched_base(skey, key, key_len); for (u = 0; u <= num_rounds; u ++) { uint32_t q[8]; q[0] = q[1] = skey[(u << 2) + 0]; q[2] = q[3] = skey[(u << 2) + 1]; q[4] = q[5] = skey[(u << 2) + 2]; q[6] = q[7] = skey[(u << 2) + 3]; aes_ct_ortho(q); comp_skey[(u << 2) + 0] = (q[0] & 0x55555555) | (q[1] & 0xAAAAAAAA); comp_skey[(u << 2) + 1] = (q[2] & 0x55555555) | (q[3] & 0xAAAAAAAA); comp_skey[(u << 2) + 2] = (q[4] & 0x55555555) | (q[5] & 0xAAAAAAAA); comp_skey[(u << 2) + 3] = (q[6] & 0x55555555) | (q[7] & 0xAAAAAAAA); } return num_rounds; } /* * Expand AES subkeys as produced by aes_ct_keysched(), into * a larger array suitable for aes_ct_bitslice_encrypt() and * aes_ct_bitslice_decrypt(). */ void aes_ct_skey_expand(uint32_t *skey, unsigned num_rounds, const uint32_t *comp_skey) { unsigned u, v, n; n = (num_rounds + 1) << 2; for (u = 0, v = 0; u < n; u ++, v += 2) { uint32_t x, y; x = y = comp_skey[u]; x &= 0x55555555; skey[v + 0] = x | (x << 1); y &= 0xAAAAAAAA; skey[v + 1] = y | (y >> 1); } } static inline void add_round_key(uint32_t *q, const uint32_t *sk) { q[0] ^= sk[0]; q[1] ^= sk[1]; q[2] ^= sk[2]; q[3] ^= sk[3]; q[4] ^= sk[4]; q[5] ^= sk[5]; q[6] ^= sk[6]; q[7] ^= sk[7]; } static inline void shift_rows(uint32_t *q) { int i; for (i = 0; i < 8; i ++) { uint32_t x; x = q[i]; q[i] = (x & 0x000000FF) | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6) | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4) | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2); } } static inline uint32_t rotr16(uint32_t x) { return (x << 16) | (x >> 16); } static inline void mix_columns(uint32_t *q) { uint32_t q0, q1, q2, q3, q4, q5, q6, q7; uint32_t r0, r1, r2, r3, r4, r5, r6, r7; q0 = q[0]; q1 = q[1]; q2 = q[2]; q3 = q[3]; q4 = q[4]; q5 = q[5]; q6 = q[6]; q7 = q[7]; r0 = (q0 >> 8) | (q0 << 24); r1 = (q1 >> 8) | (q1 << 24); r2 = (q2 >> 8) | (q2 << 24); r3 = (q3 >> 8) | (q3 << 24); r4 = (q4 >> 8) | (q4 << 24); r5 = (q5 >> 8) | (q5 << 24); r6 = (q6 >> 8) | (q6 << 24); r7 = (q7 >> 8) | (q7 << 24); q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0); q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1); q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2); q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3); q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4); q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5); q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6); q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7); } /* * Compute AES encryption on bitsliced data. Since input is stored on * eight 32-bit words, two block encryptions are actually performed * in parallel. */ void aes_ct_bitslice_encrypt(unsigned num_rounds, const uint32_t *skey, uint32_t *q) { unsigned u; add_round_key(q, skey); for (u = 1; u < num_rounds; u ++) { aes_ct_bitslice_Sbox(q); shift_rows(q); mix_columns(q); add_round_key(q, skey + (u << 3)); } aes_ct_bitslice_Sbox(q); shift_rows(q); add_round_key(q, skey + (num_rounds << 3)); } /* * Like aes_ct_bitslice_Sbox(), but for the inverse S-box. */ void aes_ct_bitslice_invSbox(uint32_t *q) { /* * AES S-box is: * S(x) = A(I(x)) ^ 0x63 * where I() is inversion in GF(256), and A() is a linear * transform (0 is formally defined to be its own inverse). * Since inversion is an involution, the inverse S-box can be * computed from the S-box as: * iS(x) = B(S(B(x ^ 0x63)) ^ 0x63) * where B() is the inverse of A(). Indeed, for any y in GF(256): * iS(S(y)) = B(A(I(B(A(I(y)) ^ 0x63 ^ 0x63))) ^ 0x63 ^ 0x63) = y * * Note: we reuse the implementation of the forward S-box, * instead of duplicating it here, so that total code size is * lower. By merging the B() transforms into the S-box circuit * we could make faster CBC decryption, but CBC decryption is * already quite faster than CBC encryption because we can * process two blocks in parallel. */ uint32_t q0, q1, q2, q3, q4, q5, q6, q7; q0 = ~q[0]; q1 = ~q[1]; q2 = q[2]; q3 = q[3]; q4 = q[4]; q5 = ~q[5]; q6 = ~q[6]; q7 = q[7]; q[7] = q1 ^ q4 ^ q6; q[6] = q0 ^ q3 ^ q5; q[5] = q7 ^ q2 ^ q4; q[4] = q6 ^ q1 ^ q3; q[3] = q5 ^ q0 ^ q2; q[2] = q4 ^ q7 ^ q1; q[1] = q3 ^ q6 ^ q0; q[0] = q2 ^ q5 ^ q7; aes_ct_bitslice_Sbox(q); q0 = ~q[0]; q1 = ~q[1]; q2 = q[2]; q3 = q[3]; q4 = q[4]; q5 = ~q[5]; q6 = ~q[6]; q7 = q[7]; q[7] = q1 ^ q4 ^ q6; q[6] = q0 ^ q3 ^ q5; q[5] = q7 ^ q2 ^ q4; q[4] = q6 ^ q1 ^ q3; q[3] = q5 ^ q0 ^ q2; q[2] = q4 ^ q7 ^ q1; q[1] = q3 ^ q6 ^ q0; q[0] = q2 ^ q5 ^ q7; } static inline void inv_shift_rows(uint32_t *q) { int i; for (i = 0; i < 8; i ++) { uint32_t x; x = q[i]; q[i] = (x & 0x000000FF) | ((x & 0x00003F00) << 2) | ((x & 0x0000C000) >> 6) | ((x & 0x000F0000) << 4) | ((x & 0x00F00000) >> 4) | ((x & 0x03000000) << 6) | ((x & 0xFC000000) >> 2); } } static void inv_mix_columns(uint32_t *q) { uint32_t q0, q1, q2, q3, q4, q5, q6, q7; uint32_t r0, r1, r2, r3, r4, r5, r6, r7; q0 = q[0]; q1 = q[1]; q2 = q[2]; q3 = q[3]; q4 = q[4]; q5 = q[5]; q6 = q[6]; q7 = q[7]; r0 = (q0 >> 8) | (q0 << 24); r1 = (q1 >> 8) | (q1 << 24); r2 = (q2 >> 8) | (q2 << 24); r3 = (q3 >> 8) | (q3 << 24); r4 = (q4 >> 8) | (q4 << 24); r5 = (q5 >> 8) | (q5 << 24); r6 = (q6 >> 8) | (q6 << 24); r7 = (q7 >> 8) | (q7 << 24); q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ rotr16(q0 ^ q5 ^ q6 ^ r0 ^ r5); q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6); q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ rotr16(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7); q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ rotr16(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7); q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6); q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7); q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ rotr16(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7); q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ rotr16(q4 ^ q5 ^ q7 ^ r4 ^ r7); } /* * Compute AES decryption on bitsliced data. Since input is stored on * eight 32-bit words, two block decryptions are actually performed * in parallel. */ void aes_ct_bitslice_decrypt(unsigned num_rounds, const uint32_t *skey, uint32_t *q) { unsigned u; add_round_key(q, skey + (num_rounds << 3)); for (u = num_rounds - 1; u > 0; u --) { inv_shift_rows(q); aes_ct_bitslice_invSbox(q); add_round_key(q, skey + (u << 3)); inv_mix_columns(q); } inv_shift_rows(q); aes_ct_bitslice_invSbox(q); add_round_key(q, skey); } int AES_Setkey(AES_CTX *ctx, const uint8_t *key, int len) { ctx->num_rounds = aes_ct_keysched(ctx->sk, key, len); if (ctx->num_rounds == 0) return -1; aes_ct_skey_expand(ctx->sk_exp, ctx->num_rounds, ctx->sk); return 0; } void AES_Encrypt_ECB(AES_CTX *ctx, const uint8_t *src, uint8_t *dst, size_t num_blocks) { while (num_blocks > 0) { uint32_t q[8]; q[0] = dec32le(src); q[2] = dec32le(src + 4); q[4] = dec32le(src + 8); q[6] = dec32le(src + 12); if (num_blocks > 1) { q[1] = dec32le(src + 16); q[3] = dec32le(src + 20); q[5] = dec32le(src + 24); q[7] = dec32le(src + 28); } else { q[1] = 0; q[3] = 0; q[5] = 0; q[7] = 0; } aes_ct_ortho(q); aes_ct_bitslice_encrypt(ctx->num_rounds, ctx->sk_exp, q); aes_ct_ortho(q); enc32le(dst, q[0]); enc32le(dst + 4, q[2]); enc32le(dst + 8, q[4]); enc32le(dst + 12, q[6]); if (num_blocks > 1) { enc32le(dst + 16, q[1]); enc32le(dst + 20, q[3]); enc32le(dst + 24, q[5]); enc32le(dst + 28, q[7]); src += 32; dst += 32; num_blocks -= 2; } else { break; } } } void AES_Decrypt_ECB(AES_CTX *ctx, const uint8_t *src, uint8_t *dst, size_t num_blocks) { while (num_blocks > 0) { uint32_t q[8]; q[0] = dec32le(src); q[2] = dec32le(src + 4); q[4] = dec32le(src + 8); q[6] = dec32le(src + 12); if (num_blocks > 1) { q[1] = dec32le(src + 16); q[3] = dec32le(src + 20); q[5] = dec32le(src + 24); q[7] = dec32le(src + 28); } else { q[1] = 0; q[3] = 0; q[5] = 0; q[7] = 0; } aes_ct_ortho(q); aes_ct_bitslice_decrypt(ctx->num_rounds, ctx->sk_exp, q); aes_ct_ortho(q); enc32le(dst, q[0]); enc32le(dst + 4, q[2]); enc32le(dst + 8, q[4]); enc32le(dst + 12, q[6]); if (num_blocks > 1) { enc32le(dst + 16, q[1]); enc32le(dst + 20, q[3]); enc32le(dst + 24, q[5]); enc32le(dst + 28, q[7]); src += 32; dst += 32; num_blocks -= 2; } else { break; } } } void AES_Encrypt(AES_CTX *ctx, const uint8_t *src, uint8_t *dst) { AES_Encrypt_ECB(ctx, src, dst, 1); } void AES_Decrypt(AES_CTX *ctx, const uint8_t *src, uint8_t *dst) { AES_Decrypt_ECB(ctx, src, dst, 1); } int AES_KeySetup_Encrypt(uint32_t *skey, const uint8_t *key, int len) { unsigned r, u; uint32_t tkey[60]; r = aes_keysched_base(tkey, key, len); if (r == 0) { return 0; } for (u = 0; u < ((r + 1) << 2); u ++) { uint32_t w; w = tkey[u]; skey[u] = (w << 24) | ((w & 0x0000FF00) << 8) | ((w & 0x00FF0000) >> 8) | (w >> 24); } return r; } /* * Reduce value x modulo polynomial x^8+x^4+x^3+x+1. This works as * long as x fits on 12 bits at most. */ static inline uint32_t redgf256(uint32_t x) { uint32_t h; h = x >> 8; return (x ^ h ^ (h << 1) ^ (h << 3) ^ (h << 4)) & 0xFF; } /* * Multiplication by 0x09 in GF(256). */ static inline uint32_t mul9(uint32_t x) { return redgf256(x ^ (x << 3)); } /* * Multiplication by 0x0B in GF(256). */ static inline uint32_t mulb(uint32_t x) { return redgf256(x ^ (x << 1) ^ (x << 3)); } /* * Multiplication by 0x0D in GF(256). */ static inline uint32_t muld(uint32_t x) { return redgf256(x ^ (x << 2) ^ (x << 3)); } /* * Multiplication by 0x0E in GF(256). */ static inline uint32_t mule(uint32_t x) { return redgf256((x << 1) ^ (x << 2) ^ (x << 3)); } int AES_KeySetup_Decrypt(uint32_t *skey, const uint8_t *key, int len) { unsigned r, u; uint32_t tkey[60]; /* * Compute encryption subkeys. We get them in big-endian * notation. */ r = AES_KeySetup_Encrypt(tkey, key, len); if (r == 0) { return 0; } /* * Copy the subkeys in reverse order. Also, apply InvMixColumns() * on the subkeys (except first and last). */ memcpy(skey + (r << 2), tkey, 4 * sizeof(uint32_t)); memcpy(skey, tkey + (r << 2), 4 * sizeof(uint32_t)); for (u = 4; u < (r << 2); u ++) { uint32_t sk, sk0, sk1, sk2, sk3; uint32_t tk, tk0, tk1, tk2, tk3; sk = tkey[u]; sk0 = sk >> 24; sk1 = (sk >> 16) & 0xFF; sk2 = (sk >> 8) & 0xFF; sk3 = sk & 0xFF; tk0 = mule(sk0) ^ mulb(sk1) ^ muld(sk2) ^ mul9(sk3); tk1 = mul9(sk0) ^ mule(sk1) ^ mulb(sk2) ^ muld(sk3); tk2 = muld(sk0) ^ mul9(sk1) ^ mule(sk2) ^ mulb(sk3); tk3 = mulb(sk0) ^ muld(sk1) ^ mul9(sk2) ^ mule(sk3); tk = (tk0 << 24) ^ (tk1 << 16) ^ (tk2 << 8) ^ tk3; skey[((r - (u >> 2)) << 2) + (u & 3)] = tk; } return r; } ================================================ FILE: itl80211/openbsd/crypto/aes.h ================================================ /* * Copyright (c) 2016 Thomas Pornin * Copyright (c) 2016 Mike Belopuhov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef _AES_H_ #define _AES_H_ #ifndef AES_MAXROUNDS #define AES_MAXROUNDS (14) #endif typedef struct aes_ctx { uint32_t sk[60]; uint32_t sk_exp[120]; unsigned num_rounds; } AES_CTX; int AES_Setkey(AES_CTX *, const uint8_t *, int); void AES_Encrypt(AES_CTX *, const uint8_t *, uint8_t *); void AES_Decrypt(AES_CTX *, const uint8_t *, uint8_t *); void AES_Encrypt_ECB(AES_CTX *, const uint8_t *, uint8_t *, size_t); void AES_Decrypt_ECB(AES_CTX *, const uint8_t *, uint8_t *, size_t); int AES_KeySetup_Encrypt(uint32_t *, const uint8_t *, int); int AES_KeySetup_Decrypt(uint32_t *, const uint8_t *, int); #endif /* _AES_H_ */ ================================================ FILE: itl80211/openbsd/crypto/arc4.c ================================================ /* $OpenBSD: arc4.c,v 1.3 2007/09/11 12:07:05 djm Exp $ */ /* * Copyright (c) 2003 Markus Friedl * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #define RC4SWAP(x,y) \ do { \ u_int8_t t = ctx->state[x]; \ ctx->state[x] = ctx->state[y]; \ ctx->state[y] = t; \ } while(0) void rc4_keysetup(struct rc4_ctx *ctx, u_char *key, u_int32_t klen) { u_int8_t x, y; u_int32_t i; x = y = 0; for (i = 0; i < RC4STATE; i++) ctx->state[i] = i; for (i = 0; i < RC4STATE; i++) { y = (key[x] + ctx->state[i] + y) & (RC4STATE - 1); RC4SWAP(i, y); x = (x + 1) % klen; } ctx->x = ctx->y = 0; } void rc4_crypt(struct rc4_ctx *ctx, u_char *src, u_char *dst, u_int32_t len) { u_int32_t i; for (i = 0; i < len; i++) { ctx->x = (ctx->x + 1) & (RC4STATE - 1); ctx->y = (ctx->state[ctx->x] + ctx->y) & (RC4STATE - 1); RC4SWAP(ctx->x, ctx->y); dst[i] = src[i] ^ ctx->state[ (ctx->state[ctx->x] + ctx->state[ctx->y]) & (RC4STATE - 1)]; } } void rc4_getbytes(struct rc4_ctx *ctx, u_char *dst, u_int32_t len) { u_int32_t i; for (i = 0; i < len; i++) { ctx->x = (ctx->x + 1) & (RC4STATE - 1); ctx->y = (ctx->state[ctx->x] + ctx->y) & (RC4STATE - 1); RC4SWAP(ctx->x, ctx->y); dst[i] = ctx->state[ (ctx->state[ctx->x] + ctx->state[ctx->y]) & (RC4STATE - 1)]; } } void rc4_skip(struct rc4_ctx *ctx, u_int32_t len) { for (; len > 0; len--) { ctx->x = (ctx->x + 1) & (RC4STATE - 1); ctx->y = (ctx->state[ctx->x] + ctx->y) & (RC4STATE - 1); RC4SWAP(ctx->x, ctx->y); } } ================================================ FILE: itl80211/openbsd/crypto/arc4.h ================================================ /* $OpenBSD: arc4.h,v 1.3 2007/09/11 12:07:05 djm Exp $ */ /* * Copyright (c) 2003 Markus Friedl * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define RC4STATE 256 #define RC4KEYLEN 16 struct rc4_ctx { u_int8_t x, y; u_int8_t state[RC4STATE]; }; void rc4_keysetup(struct rc4_ctx *, u_char *, u_int32_t) __attribute__((__bounded__(__buffer__,2,3))); void rc4_crypt(struct rc4_ctx *, u_char *, u_char *, u_int32_t) __attribute__((__bounded__(__buffer__,2,4))) __attribute__((__bounded__(__buffer__,3,4))); void rc4_getbytes(struct rc4_ctx *, u_char *, u_int32_t) __attribute__((__bounded__(__buffer__,2,3))); void rc4_skip(struct rc4_ctx *, u_int32_t); ================================================ FILE: itl80211/openbsd/crypto/blf.c ================================================ /* $OpenBSD: blf.c,v 1.7 2007/11/26 09:28:34 martynas Exp $ */ /* * Blowfish block cipher for OpenBSD * Copyright 1997 Niels Provos * All rights reserved. * * Implementation advice by David Mazieres . * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Niels Provos. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This code is derived from section 14.3 and the given source * in section V of Applied Cryptography, second edition. * Blowfish is an unpatented fast block cipher designed by * Bruce Schneier. */ #include #include #include #undef inline #ifdef __GNUC__ #define inline __inline #else /* !__GNUC__ */ #define inline #endif /* !__GNUC__ */ /* Function for Feistel Networks */ #define F(s, x) ((((s)[ (((x)>>24)&0xFF)] \ + (s)[0x100 + (((x)>>16)&0xFF)]) \ ^ (s)[0x200 + (((x)>> 8)&0xFF)]) \ + (s)[0x300 + ( (x) &0xFF)]) #define BLFRND(s,p,i,j,n) (i ^= F(s,j) ^ (p)[n]) void Blowfish_encipher(blf_ctx *c, u_int32_t *x) { u_int32_t Xl; u_int32_t Xr; u_int32_t *s = c->S[0]; u_int32_t *p = c->P; Xl = x[0]; Xr = x[1]; Xl ^= p[0]; BLFRND(s, p, Xr, Xl, 1); BLFRND(s, p, Xl, Xr, 2); BLFRND(s, p, Xr, Xl, 3); BLFRND(s, p, Xl, Xr, 4); BLFRND(s, p, Xr, Xl, 5); BLFRND(s, p, Xl, Xr, 6); BLFRND(s, p, Xr, Xl, 7); BLFRND(s, p, Xl, Xr, 8); BLFRND(s, p, Xr, Xl, 9); BLFRND(s, p, Xl, Xr, 10); BLFRND(s, p, Xr, Xl, 11); BLFRND(s, p, Xl, Xr, 12); BLFRND(s, p, Xr, Xl, 13); BLFRND(s, p, Xl, Xr, 14); BLFRND(s, p, Xr, Xl, 15); BLFRND(s, p, Xl, Xr, 16); x[0] = Xr ^ p[17]; x[1] = Xl; } void Blowfish_decipher(blf_ctx *c, u_int32_t *x) { u_int32_t Xl; u_int32_t Xr; u_int32_t *s = c->S[0]; u_int32_t *p = c->P; Xl = x[0]; Xr = x[1]; Xl ^= p[17]; BLFRND(s, p, Xr, Xl, 16); BLFRND(s, p, Xl, Xr, 15); BLFRND(s, p, Xr, Xl, 14); BLFRND(s, p, Xl, Xr, 13); BLFRND(s, p, Xr, Xl, 12); BLFRND(s, p, Xl, Xr, 11); BLFRND(s, p, Xr, Xl, 10); BLFRND(s, p, Xl, Xr, 9); BLFRND(s, p, Xr, Xl, 8); BLFRND(s, p, Xl, Xr, 7); BLFRND(s, p, Xr, Xl, 6); BLFRND(s, p, Xl, Xr, 5); BLFRND(s, p, Xr, Xl, 4); BLFRND(s, p, Xl, Xr, 3); BLFRND(s, p, Xr, Xl, 2); BLFRND(s, p, Xl, Xr, 1); x[0] = Xr ^ p[0]; x[1] = Xl; } void Blowfish_initstate(blf_ctx *c) { /* P-box and S-box tables initialized with digits of Pi */ static const blf_ctx initstate = { { { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a}, { 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7}, { 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0}, { 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6} }, { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b } }; *c = initstate; } u_int32_t Blowfish_stream2word(const u_int8_t *data, u_int16_t databytes, u_int16_t *current) { u_int8_t i; u_int16_t j; u_int32_t temp; temp = 0x00000000; j = *current; for (i = 0; i < 4; i++, j++) { if (j >= databytes) j = 0; temp = (temp << 8) | data[j]; } *current = j; return temp; } void Blowfish_expand0state(blf_ctx *c, const u_int8_t *key, u_int16_t keybytes) { u_int16_t i; u_int16_t j; u_int16_t k; u_int32_t temp; u_int32_t data[2]; j = 0; for (i = 0; i < BLF_N + 2; i++) { /* Extract 4 int8 to 1 int32 from keystream */ temp = Blowfish_stream2word(key, keybytes, &j); c->P[i] = c->P[i] ^ temp; } j = 0; data[0] = 0x00000000; data[1] = 0x00000000; for (i = 0; i < BLF_N + 2; i += 2) { Blowfish_encipher(c, data); c->P[i] = data[0]; c->P[i + 1] = data[1]; } for (i = 0; i < 4; i++) { for (k = 0; k < 256; k += 2) { Blowfish_encipher(c, data); c->S[i][k] = data[0]; c->S[i][k + 1] = data[1]; } } } void Blowfish_expandstate(blf_ctx *c, const u_int8_t *data, u_int16_t databytes, const u_int8_t *key, u_int16_t keybytes) { u_int16_t i; u_int16_t j; u_int16_t k; u_int32_t temp; u_int32_t d[2]; j = 0; for (i = 0; i < BLF_N + 2; i++) { /* Extract 4 int8 to 1 int32 from keystream */ temp = Blowfish_stream2word(key, keybytes, &j); c->P[i] = c->P[i] ^ temp; } j = 0; d[0] = 0x00000000; d[1] = 0x00000000; for (i = 0; i < BLF_N + 2; i += 2) { d[0] ^= Blowfish_stream2word(data, databytes, &j); d[1] ^= Blowfish_stream2word(data, databytes, &j); Blowfish_encipher(c, d); c->P[i] = d[0]; c->P[i + 1] = d[1]; } for (i = 0; i < 4; i++) { for (k = 0; k < 256; k += 2) { d[0]^= Blowfish_stream2word(data, databytes, &j); d[1] ^= Blowfish_stream2word(data, databytes, &j); Blowfish_encipher(c, d); c->S[i][k] = d[0]; c->S[i][k + 1] = d[1]; } } } void blf_key(blf_ctx *c, const u_int8_t *k, u_int16_t len) { /* Initialize S-boxes and subkeys with Pi */ Blowfish_initstate(c); /* Transform S-boxes and subkeys with key */ Blowfish_expand0state(c, k, len); } void blf_enc(blf_ctx *c, u_int32_t *data, u_int16_t blocks) { u_int32_t *d; u_int16_t i; d = data; for (i = 0; i < blocks; i++) { Blowfish_encipher(c, d); d += 2; } } void blf_dec(blf_ctx *c, u_int32_t *data, u_int16_t blocks) { u_int32_t *d; u_int16_t i; d = data; for (i = 0; i < blocks; i++) { Blowfish_decipher(c, d); d += 2; } } void blf_ecb_encrypt(blf_ctx *c, u_int8_t *data, u_int32_t len) { u_int32_t l, r, d[2]; u_int32_t i; for (i = 0; i < len; i += 8) { l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; d[0] = l; d[1] = r; Blowfish_encipher(c, d); l = d[0]; r = d[1]; data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; data += 8; } } void blf_ecb_decrypt(blf_ctx *c, u_int8_t *data, u_int32_t len) { u_int32_t l, r, d[2]; u_int32_t i; for (i = 0; i < len; i += 8) { l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; d[0] = l; d[1] = r; Blowfish_decipher(c, d); l = d[0]; r = d[1]; data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; data += 8; } } void blf_cbc_encrypt(blf_ctx *c, u_int8_t *iv, u_int8_t *data, u_int32_t len) { u_int32_t l, r, d[2]; u_int32_t i, j; for (i = 0; i < len; i += 8) { for (j = 0; j < 8; j++) data[j] ^= iv[j]; l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; d[0] = l; d[1] = r; Blowfish_encipher(c, d); l = d[0]; r = d[1]; data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; iv = data; data += 8; } } void blf_cbc_decrypt(blf_ctx *c, u_int8_t *iva, u_int8_t *data, u_int32_t len) { u_int32_t l, r, d[2]; u_int8_t *iv; u_int32_t i, j; iv = data + len - 16; data = data + len - 8; for (i = len - 8; i >= 8; i -= 8) { l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; d[0] = l; d[1] = r; Blowfish_decipher(c, d); l = d[0]; r = d[1]; data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; for (j = 0; j < 8; j++) data[j] ^= iv[j]; iv -= 8; data -= 8; } l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; d[0] = l; d[1] = r; Blowfish_decipher(c, d); l = d[0]; r = d[1]; data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; for (j = 0; j < 8; j++) data[j] ^= iva[j]; } ================================================ FILE: itl80211/openbsd/crypto/blf.h ================================================ /* $OpenBSD: blf.h,v 1.6 2007/02/21 19:25:40 grunk Exp $ */ /* * Blowfish - a fast block cipher designed by Bruce Schneier * * Copyright 1997 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Niels Provos. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _BLF_H_ #define _BLF_H_ /* Schneier states the maximum key length to be 56 bytes. * The way how the subkeys are initialized by the key up * to (N+2)*4 i.e. 72 bytes are utilized. * Warning: For normal blowfish encryption only 56 bytes * of the key affect all cipherbits. */ #define BLF_N 16 /* Number of Subkeys */ #define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */ #define BLF_MAXUTILIZED ((BLF_N+2)*4) /* 576 bits */ /* Blowfish context */ typedef struct BlowfishContext { u_int32_t S[4][256]; /* S-Boxes */ u_int32_t P[BLF_N + 2]; /* Subkeys */ } blf_ctx; /* Raw access to customized Blowfish * blf_key is just: * Blowfish_initstate( state ) * Blowfish_expand0state( state, key, keylen ) */ void Blowfish_encipher(blf_ctx *, u_int32_t *); void Blowfish_decipher(blf_ctx *, u_int32_t *); void Blowfish_initstate(blf_ctx *); void Blowfish_expand0state(blf_ctx *, const u_int8_t *, u_int16_t); void Blowfish_expandstate(blf_ctx *, const u_int8_t *, u_int16_t, const u_int8_t *, u_int16_t); /* Standard Blowfish */ void blf_key(blf_ctx *, const u_int8_t *, u_int16_t); void blf_enc(blf_ctx *, u_int32_t *, u_int16_t); void blf_dec(blf_ctx *, u_int32_t *, u_int16_t); /* Converts u_int8_t to u_int32_t */ u_int32_t Blowfish_stream2word(const u_int8_t *, u_int16_t , u_int16_t *); void blf_ecb_encrypt(blf_ctx *, u_int8_t *, u_int32_t); void blf_ecb_decrypt(blf_ctx *, u_int8_t *, u_int32_t); void blf_cbc_encrypt(blf_ctx *, u_int8_t *, u_int8_t *, u_int32_t); void blf_cbc_decrypt(blf_ctx *, u_int8_t *, u_int8_t *, u_int32_t); #endif ================================================ FILE: itl80211/openbsd/crypto/cast.c ================================================ /* $OpenBSD: cast.c,v 1.4 2012/04/25 04:12:27 matthew Exp $ */ /* * CAST-128 in C * Written by Steve Reid * 100% Public Domain - no warranty * Released 1997.10.11 */ #include #include #include #include /* Macros to access 8-bit bytes out of a 32-bit word */ #define U_INT8_Ta(x) ( (u_int8_t) (x>>24) ) #define U_INT8_Tb(x) ( (u_int8_t) ((x>>16)&255) ) #define U_INT8_Tc(x) ( (u_int8_t) ((x>>8)&255) ) #define U_INT8_Td(x) ( (u_int8_t) ((x)&255) ) /* Circular left shift */ #define ROL(x, n) ( ((x)<<(n)) | ((x)>>(32-(n))) ) /* CAST-128 uses three different round functions */ #define F1(l, r, i) \ t = ROL(key->xkey[i] + r, key->xkey[i+16]); \ l ^= ((cast_sbox1[U_INT8_Ta(t)] ^ cast_sbox2[U_INT8_Tb(t)]) - \ cast_sbox3[U_INT8_Tc(t)]) + cast_sbox4[U_INT8_Td(t)]; #define F2(l, r, i) \ t = ROL(key->xkey[i] ^ r, key->xkey[i+16]); \ l ^= ((cast_sbox1[U_INT8_Ta(t)] - cast_sbox2[U_INT8_Tb(t)]) + \ cast_sbox3[U_INT8_Tc(t)]) ^ cast_sbox4[U_INT8_Td(t)]; #define F3(l, r, i) \ t = ROL(key->xkey[i] - r, key->xkey[i+16]); \ l ^= ((cast_sbox1[U_INT8_Ta(t)] + cast_sbox2[U_INT8_Tb(t)]) ^ \ cast_sbox3[U_INT8_Tc(t)]) - cast_sbox4[U_INT8_Td(t)]; /***** Encryption Function *****/ void cast_encrypt(cast_key *key, u_int8_t *inblock, u_int8_t *outblock) { u_int32_t t, l, r; /* Get inblock into l,r */ l = ((u_int32_t)inblock[0] << 24) | ((u_int32_t)inblock[1] << 16) | ((u_int32_t)inblock[2] << 8) | (u_int32_t)inblock[3]; r = ((u_int32_t)inblock[4] << 24) | ((u_int32_t)inblock[5] << 16) | ((u_int32_t)inblock[6] << 8) | (u_int32_t)inblock[7]; /* Do the work */ F1(l, r, 0); F2(r, l, 1); F3(l, r, 2); F1(r, l, 3); F2(l, r, 4); F3(r, l, 5); F1(l, r, 6); F2(r, l, 7); F3(l, r, 8); F1(r, l, 9); F2(l, r, 10); F3(r, l, 11); /* Only do full 16 rounds if key length > 80 bits */ if (key->rounds > 12) { F1(l, r, 12); F2(r, l, 13); F3(l, r, 14); F1(r, l, 15); } /* Put l,r into outblock */ outblock[0] = U_INT8_Ta(r); outblock[1] = U_INT8_Tb(r); outblock[2] = U_INT8_Tc(r); outblock[3] = U_INT8_Td(r); outblock[4] = U_INT8_Ta(l); outblock[5] = U_INT8_Tb(l); outblock[6] = U_INT8_Tc(l); outblock[7] = U_INT8_Td(l); /* Wipe clean */ t = l = r = 0; } /***** Decryption Function *****/ void cast_decrypt(cast_key *key, u_int8_t *inblock, u_int8_t *outblock) { u_int32_t t, l, r; /* Get inblock into l,r */ r = ((u_int32_t)inblock[0] << 24) | ((u_int32_t)inblock[1] << 16) | ((u_int32_t)inblock[2] << 8) | (u_int32_t)inblock[3]; l = ((u_int32_t)inblock[4] << 24) | ((u_int32_t)inblock[5] << 16) | ((u_int32_t)inblock[6] << 8) | (u_int32_t)inblock[7]; /* Do the work */ /* Only do full 16 rounds if key length > 80 bits */ if (key->rounds > 12) { F1(r, l, 15); F3(l, r, 14); F2(r, l, 13); F1(l, r, 12); } F3(r, l, 11); F2(l, r, 10); F1(r, l, 9); F3(l, r, 8); F2(r, l, 7); F1(l, r, 6); F3(r, l, 5); F2(l, r, 4); F1(r, l, 3); F3(l, r, 2); F2(r, l, 1); F1(l, r, 0); /* Put l,r into outblock */ outblock[0] = U_INT8_Ta(l); outblock[1] = U_INT8_Tb(l); outblock[2] = U_INT8_Tc(l); outblock[3] = U_INT8_Td(l); outblock[4] = U_INT8_Ta(r); outblock[5] = U_INT8_Tb(r); outblock[6] = U_INT8_Tc(r); outblock[7] = U_INT8_Td(r); /* Wipe clean */ t = l = r = 0; } /***** Key Schedule *****/ void cast_setkey(cast_key *key, u_int8_t *rawkey, int keybytes) { u_int32_t t[4], z[4], x[4]; int i; /* Set number of rounds to 12 or 16, depending on key length */ key->rounds = (keybytes <= 10 ? 12 : 16); /* Copy key to workspace x */ for (i = 0; i < 4; i++) { x[i] = 0; if ((i*4+0) < keybytes) x[i] = (u_int32_t)rawkey[i*4+0] << 24; if ((i*4+1) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+1] << 16; if ((i*4+2) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+2] << 8; if ((i*4+3) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+3]; } /* Generate 32 subkeys, four at a time */ for (i = 0; i < 32; i+=4) { switch (i & 4) { case 0: t[0] = z[0] = x[0] ^ cast_sbox5[U_INT8_Tb(x[3])] ^ cast_sbox6[U_INT8_Td(x[3])] ^ cast_sbox7[U_INT8_Ta(x[3])] ^ cast_sbox8[U_INT8_Tc(x[3])] ^ cast_sbox7[U_INT8_Ta(x[2])]; t[1] = z[1] = x[2] ^ cast_sbox5[U_INT8_Ta(z[0])] ^ cast_sbox6[U_INT8_Tc(z[0])] ^ cast_sbox7[U_INT8_Tb(z[0])] ^ cast_sbox8[U_INT8_Td(z[0])] ^ cast_sbox8[U_INT8_Tc(x[2])]; t[2] = z[2] = x[3] ^ cast_sbox5[U_INT8_Td(z[1])] ^ cast_sbox6[U_INT8_Tc(z[1])] ^ cast_sbox7[U_INT8_Tb(z[1])] ^ cast_sbox8[U_INT8_Ta(z[1])] ^ cast_sbox5[U_INT8_Tb(x[2])]; t[3] = z[3] = x[1] ^ cast_sbox5[U_INT8_Tc(z[2])] ^ cast_sbox6[U_INT8_Tb(z[2])] ^ cast_sbox7[U_INT8_Td(z[2])] ^ cast_sbox8[U_INT8_Ta(z[2])] ^ cast_sbox6[U_INT8_Td(x[2])]; break; case 4: t[0] = x[0] = z[2] ^ cast_sbox5[U_INT8_Tb(z[1])] ^ cast_sbox6[U_INT8_Td(z[1])] ^ cast_sbox7[U_INT8_Ta(z[1])] ^ cast_sbox8[U_INT8_Tc(z[1])] ^ cast_sbox7[U_INT8_Ta(z[0])]; t[1] = x[1] = z[0] ^ cast_sbox5[U_INT8_Ta(x[0])] ^ cast_sbox6[U_INT8_Tc(x[0])] ^ cast_sbox7[U_INT8_Tb(x[0])] ^ cast_sbox8[U_INT8_Td(x[0])] ^ cast_sbox8[U_INT8_Tc(z[0])]; t[2] = x[2] = z[1] ^ cast_sbox5[U_INT8_Td(x[1])] ^ cast_sbox6[U_INT8_Tc(x[1])] ^ cast_sbox7[U_INT8_Tb(x[1])] ^ cast_sbox8[U_INT8_Ta(x[1])] ^ cast_sbox5[U_INT8_Tb(z[0])]; t[3] = x[3] = z[3] ^ cast_sbox5[U_INT8_Tc(x[2])] ^ cast_sbox6[U_INT8_Tb(x[2])] ^ cast_sbox7[U_INT8_Td(x[2])] ^ cast_sbox8[U_INT8_Ta(x[2])] ^ cast_sbox6[U_INT8_Td(z[0])]; break; } switch (i & 12) { case 0: case 12: key->xkey[i+0] = cast_sbox5[U_INT8_Ta(t[2])] ^ cast_sbox6[U_INT8_Tb(t[2])] ^ cast_sbox7[U_INT8_Td(t[1])] ^ cast_sbox8[U_INT8_Tc(t[1])]; key->xkey[i+1] = cast_sbox5[U_INT8_Tc(t[2])] ^ cast_sbox6[U_INT8_Td(t[2])] ^ cast_sbox7[U_INT8_Tb(t[1])] ^ cast_sbox8[U_INT8_Ta(t[1])]; key->xkey[i+2] = cast_sbox5[U_INT8_Ta(t[3])] ^ cast_sbox6[U_INT8_Tb(t[3])] ^ cast_sbox7[U_INT8_Td(t[0])] ^ cast_sbox8[U_INT8_Tc(t[0])]; key->xkey[i+3] = cast_sbox5[U_INT8_Tc(t[3])] ^ cast_sbox6[U_INT8_Td(t[3])] ^ cast_sbox7[U_INT8_Tb(t[0])] ^ cast_sbox8[U_INT8_Ta(t[0])]; break; case 4: case 8: key->xkey[i+0] = cast_sbox5[U_INT8_Td(t[0])] ^ cast_sbox6[U_INT8_Tc(t[0])] ^ cast_sbox7[U_INT8_Ta(t[3])] ^ cast_sbox8[U_INT8_Tb(t[3])]; key->xkey[i+1] = cast_sbox5[U_INT8_Tb(t[0])] ^ cast_sbox6[U_INT8_Ta(t[0])] ^ cast_sbox7[U_INT8_Tc(t[3])] ^ cast_sbox8[U_INT8_Td(t[3])]; key->xkey[i+2] = cast_sbox5[U_INT8_Td(t[1])] ^ cast_sbox6[U_INT8_Tc(t[1])] ^ cast_sbox7[U_INT8_Ta(t[2])] ^ cast_sbox8[U_INT8_Tb(t[2])]; key->xkey[i+3] = cast_sbox5[U_INT8_Tb(t[1])] ^ cast_sbox6[U_INT8_Ta(t[1])] ^ cast_sbox7[U_INT8_Tc(t[2])] ^ cast_sbox8[U_INT8_Td(t[2])]; break; } switch (i & 12) { case 0: key->xkey[i+0] ^= cast_sbox5[U_INT8_Tc(z[0])]; key->xkey[i+1] ^= cast_sbox6[U_INT8_Tc(z[1])]; key->xkey[i+2] ^= cast_sbox7[U_INT8_Tb(z[2])]; key->xkey[i+3] ^= cast_sbox8[U_INT8_Ta(z[3])]; break; case 4: key->xkey[i+0] ^= cast_sbox5[U_INT8_Ta(x[2])]; key->xkey[i+1] ^= cast_sbox6[U_INT8_Tb(x[3])]; key->xkey[i+2] ^= cast_sbox7[U_INT8_Td(x[0])]; key->xkey[i+3] ^= cast_sbox8[U_INT8_Td(x[1])]; break; case 8: key->xkey[i+0] ^= cast_sbox5[U_INT8_Tb(z[2])]; key->xkey[i+1] ^= cast_sbox6[U_INT8_Ta(z[3])]; key->xkey[i+2] ^= cast_sbox7[U_INT8_Tc(z[0])]; key->xkey[i+3] ^= cast_sbox8[U_INT8_Tc(z[1])]; break; case 12: key->xkey[i+0] ^= cast_sbox5[U_INT8_Td(x[0])]; key->xkey[i+1] ^= cast_sbox6[U_INT8_Td(x[1])]; key->xkey[i+2] ^= cast_sbox7[U_INT8_Ta(x[2])]; key->xkey[i+3] ^= cast_sbox8[U_INT8_Tb(x[3])]; break; } if (i >= 16) { key->xkey[i+0] &= 31; key->xkey[i+1] &= 31; key->xkey[i+2] &= 31; key->xkey[i+3] &= 31; } } /* Wipe clean */ memset(t, 0, sizeof(t)); memset(x, 0, sizeof(x)); memset(z, 0, sizeof(z)); } /* Made in Canada */ ================================================ FILE: itl80211/openbsd/crypto/cast.h ================================================ /* $OpenBSD: cast.h,v 1.2 2002/03/14 01:26:51 millert Exp $ */ /* * CAST-128 in C * Written by Steve Reid * 100% Public Domain - no warranty * Released 1997.10.11 */ #ifndef _CAST_H_ #define _CAST_H_ typedef struct { u_int32_t xkey[32]; /* Key, after expansion */ int rounds; /* Number of rounds to use, 12 or 16 */ } cast_key; void cast_setkey(cast_key * key, u_int8_t * rawkey, int keybytes); void cast_encrypt(cast_key * key, u_int8_t * inblock, u_int8_t * outblock); void cast_decrypt(cast_key * key, u_int8_t * inblock, u_int8_t * outblock); #endif /* ifndef _CAST_H_ */ ================================================ FILE: itl80211/openbsd/crypto/castsb.h ================================================ /* $OpenBSD: castsb.h,v 1.1 2000/02/28 23:13:04 deraadt Exp $ */ /* * CAST-128 in C * Written by Steve Reid * 100% Public Domain - no warranty * Released 1997.10.11 */ static const u_int32_t cast_sbox1[256] = { 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3, 0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059, 0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B, 0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159, 0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F, 0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38, 0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493, 0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB, 0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14, 0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8, 0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495, 0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426, 0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98, 0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD, 0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464, 0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153, 0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274, 0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1, 0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1, 0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C, 0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF, 0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF }; static const u_int32_t cast_sbox2[256] = { 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A, 0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605, 0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B, 0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083, 0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F, 0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E, 0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366, 0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064, 0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6, 0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364, 0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B, 0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C, 0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741, 0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B, 0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA, 0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028, 0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6, 0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1, 0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB, 0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D, 0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E, 0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 }; static const u_int32_t cast_sbox3[256] = { 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B, 0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9, 0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD, 0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264, 0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E, 0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E, 0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790, 0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E, 0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8, 0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240, 0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C, 0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788, 0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA, 0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F, 0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE, 0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9, 0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888, 0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2, 0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2, 0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D, 0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00, 0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 }; static const u_int32_t cast_sbox4[256] = { 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57, 0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD, 0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE, 0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801, 0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1, 0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3, 0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C, 0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16, 0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7, 0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002, 0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7, 0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF, 0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035, 0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC, 0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E, 0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6, 0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F, 0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6, 0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2, 0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA, 0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6, 0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 }; static const u_int32_t cast_sbox5[256] = { 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5, 0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD, 0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB, 0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040, 0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2, 0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399, 0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966, 0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9, 0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616, 0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419, 0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9, 0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C, 0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715, 0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D, 0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA, 0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4, 0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C, 0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87, 0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110, 0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3, 0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D, 0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 }; static const u_int32_t cast_sbox6[256] = { 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4, 0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD, 0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F, 0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0, 0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941, 0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223, 0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6, 0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7, 0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89, 0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0, 0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4, 0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87, 0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585, 0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75, 0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283, 0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF, 0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0, 0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200, 0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF, 0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869, 0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB, 0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F }; static const u_int32_t cast_sbox7[256] = { 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912, 0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9, 0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4, 0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE, 0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7, 0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E, 0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9, 0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3, 0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C, 0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778, 0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE, 0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310, 0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476, 0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70, 0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A, 0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C, 0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E, 0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E, 0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301, 0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4, 0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021, 0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 }; static const u_int32_t cast_sbox8[256] = { 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B, 0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C, 0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7, 0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D, 0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8, 0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04, 0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38, 0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354, 0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160, 0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2, 0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98, 0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4, 0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5, 0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5, 0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B, 0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084, 0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A, 0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77, 0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F, 0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3, 0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1, 0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E }; ================================================ FILE: itl80211/openbsd/crypto/chacha_private.h ================================================ /* chacha-merged.c version 20080118 D. J. Bernstein Public domain. */ typedef unsigned char u8; typedef unsigned int u32; typedef struct { u32 input[16]; /* could be compressed */ } chacha_ctx; #define U8C(v) (v##U) #define U32C(v) (v##U) #define U8V(v) ((u8)(v) & U8C(0xFF)) #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) #define ROTL32(v, n) \ (U32V((v) << (n)) | ((v) >> (32 - (n)))) #define U8TO32_LITTLE(p) \ (((u32)((p)[0]) ) | \ ((u32)((p)[1]) << 8) | \ ((u32)((p)[2]) << 16) | \ ((u32)((p)[3]) << 24)) #define U32TO8_LITTLE(p, v) \ do { \ (p)[0] = U8V((v) ); \ (p)[1] = U8V((v) >> 8); \ (p)[2] = U8V((v) >> 16); \ (p)[3] = U8V((v) >> 24); \ } while (0) #define ROTATE(v,c) (ROTL32(v,c)) #define XOR(v,w) ((v) ^ (w)) #define PLUS(v,w) (U32V((v) + (w))) #define PLUSONE(v) (PLUS((v),1)) #define QUARTERROUND(a,b,c,d) \ a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); static const char sigma[32] = "expand 32-byte k"; static const char tau[32] = "expand 16-byte k"; static void chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) { const char *constants; x->input[4] = U8TO32_LITTLE(k + 0); x->input[5] = U8TO32_LITTLE(k + 4); x->input[6] = U8TO32_LITTLE(k + 8); x->input[7] = U8TO32_LITTLE(k + 12); if (kbits == 256) { /* recommended */ k += 16; constants = sigma; } else { /* kbits == 128 */ constants = tau; } x->input[8] = U8TO32_LITTLE(k + 0); x->input[9] = U8TO32_LITTLE(k + 4); x->input[10] = U8TO32_LITTLE(k + 8); x->input[11] = U8TO32_LITTLE(k + 12); x->input[0] = U8TO32_LITTLE(constants + 0); x->input[1] = U8TO32_LITTLE(constants + 4); x->input[2] = U8TO32_LITTLE(constants + 8); x->input[3] = U8TO32_LITTLE(constants + 12); } static void chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) { x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); x->input[14] = U8TO32_LITTLE(iv + 0); x->input[15] = U8TO32_LITTLE(iv + 4); } static void chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) { u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; u8 *ctarget = NULL; u8 tmp[64]; u_int i; if (!bytes) return; j0 = x->input[0]; j1 = x->input[1]; j2 = x->input[2]; j3 = x->input[3]; j4 = x->input[4]; j5 = x->input[5]; j6 = x->input[6]; j7 = x->input[7]; j8 = x->input[8]; j9 = x->input[9]; j10 = x->input[10]; j11 = x->input[11]; j12 = x->input[12]; j13 = x->input[13]; j14 = x->input[14]; j15 = x->input[15]; for (;;) { if (bytes < 64) { for (i = 0;i < bytes;++i) tmp[i] = m[i]; m = tmp; ctarget = c; c = tmp; } x0 = j0; x1 = j1; x2 = j2; x3 = j3; x4 = j4; x5 = j5; x6 = j6; x7 = j7; x8 = j8; x9 = j9; x10 = j10; x11 = j11; x12 = j12; x13 = j13; x14 = j14; x15 = j15; for (i = 20;i > 0;i -= 2) { QUARTERROUND( x0, x4, x8,x12) QUARTERROUND( x1, x5, x9,x13) QUARTERROUND( x2, x6,x10,x14) QUARTERROUND( x3, x7,x11,x15) QUARTERROUND( x0, x5,x10,x15) QUARTERROUND( x1, x6,x11,x12) QUARTERROUND( x2, x7, x8,x13) QUARTERROUND( x3, x4, x9,x14) } x0 = PLUS(x0,j0); x1 = PLUS(x1,j1); x2 = PLUS(x2,j2); x3 = PLUS(x3,j3); x4 = PLUS(x4,j4); x5 = PLUS(x5,j5); x6 = PLUS(x6,j6); x7 = PLUS(x7,j7); x8 = PLUS(x8,j8); x9 = PLUS(x9,j9); x10 = PLUS(x10,j10); x11 = PLUS(x11,j11); x12 = PLUS(x12,j12); x13 = PLUS(x13,j13); x14 = PLUS(x14,j14); x15 = PLUS(x15,j15); #ifndef KEYSTREAM_ONLY x0 = XOR(x0,U8TO32_LITTLE(m + 0)); x1 = XOR(x1,U8TO32_LITTLE(m + 4)); x2 = XOR(x2,U8TO32_LITTLE(m + 8)); x3 = XOR(x3,U8TO32_LITTLE(m + 12)); x4 = XOR(x4,U8TO32_LITTLE(m + 16)); x5 = XOR(x5,U8TO32_LITTLE(m + 20)); x6 = XOR(x6,U8TO32_LITTLE(m + 24)); x7 = XOR(x7,U8TO32_LITTLE(m + 28)); x8 = XOR(x8,U8TO32_LITTLE(m + 32)); x9 = XOR(x9,U8TO32_LITTLE(m + 36)); x10 = XOR(x10,U8TO32_LITTLE(m + 40)); x11 = XOR(x11,U8TO32_LITTLE(m + 44)); x12 = XOR(x12,U8TO32_LITTLE(m + 48)); x13 = XOR(x13,U8TO32_LITTLE(m + 52)); x14 = XOR(x14,U8TO32_LITTLE(m + 56)); x15 = XOR(x15,U8TO32_LITTLE(m + 60)); #endif j12 = PLUSONE(j12); if (!j12) { j13 = PLUSONE(j13); /* stopping at 2^70 bytes per nonce is user's responsibility */ } U32TO8_LITTLE(c + 0,x0); U32TO8_LITTLE(c + 4,x1); U32TO8_LITTLE(c + 8,x2); U32TO8_LITTLE(c + 12,x3); U32TO8_LITTLE(c + 16,x4); U32TO8_LITTLE(c + 20,x5); U32TO8_LITTLE(c + 24,x6); U32TO8_LITTLE(c + 28,x7); U32TO8_LITTLE(c + 32,x8); U32TO8_LITTLE(c + 36,x9); U32TO8_LITTLE(c + 40,x10); U32TO8_LITTLE(c + 44,x11); U32TO8_LITTLE(c + 48,x12); U32TO8_LITTLE(c + 52,x13); U32TO8_LITTLE(c + 56,x14); U32TO8_LITTLE(c + 60,x15); if (bytes <= 64) { if (bytes < 64) { for (i = 0;i < bytes;++i) ctarget[i] = c[i]; } x->input[12] = j12; x->input[13] = j13; return; } bytes -= 64; c += 64; #ifndef KEYSTREAM_ONLY m += 64; #endif } } ================================================ FILE: itl80211/openbsd/crypto/chachapoly.c ================================================ /* * Copyright (c) 2015 Mike Belopuhov * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include int chacha20_setkey(void *sched, u_int8_t *key, int len) { struct chacha20_ctx *ctx = (struct chacha20_ctx *)sched; if (len != CHACHA20_KEYSIZE + CHACHA20_SALT) return (-1); /* initial counter is 1 */ ctx->nonce[0] = 1; memcpy(ctx->nonce + CHACHA20_CTR, key + CHACHA20_KEYSIZE, CHACHA20_SALT); chacha_keysetup((chacha_ctx *)&ctx->block, key, CHACHA20_KEYSIZE * 8); return (0); } void chacha20_reinit(caddr_t key, u_int8_t *iv) { struct chacha20_ctx *ctx = (struct chacha20_ctx *)key; chacha_ivsetup((chacha_ctx *)ctx->block, iv, ctx->nonce); } void chacha20_crypt(caddr_t key, u_int8_t *data) { struct chacha20_ctx *ctx = (struct chacha20_ctx *)key; chacha_encrypt_bytes((chacha_ctx *)ctx->block, data, data, CHACHA20_BLOCK_LEN); } void Chacha20_Poly1305_Init(void *xctx) { CHACHA20_POLY1305_CTX *ctx = (CHACHA20_POLY1305_CTX *)xctx; memset(ctx, 0, sizeof(*ctx)); } void Chacha20_Poly1305_Setkey(void *xctx, const uint8_t *key, uint16_t klen) { CHACHA20_POLY1305_CTX *ctx = (CHACHA20_POLY1305_CTX *)xctx; /* salt is provided with the key material */ memcpy(ctx->nonce + CHACHA20_CTR, key + CHACHA20_KEYSIZE, CHACHA20_SALT); chacha_keysetup((chacha_ctx *)&ctx->chacha, key, CHACHA20_KEYSIZE * 8); } void Chacha20_Poly1305_Reinit(void *xctx, const uint8_t *iv, uint16_t ivlen) { CHACHA20_POLY1305_CTX *ctx = (CHACHA20_POLY1305_CTX *)xctx; /* initial counter is 0 */ chacha_ivsetup((chacha_ctx *)&ctx->chacha, iv, ctx->nonce); chacha_encrypt_bytes((chacha_ctx *)&ctx->chacha, ctx->key, ctx->key, POLY1305_KEYLEN); poly1305_init((poly1305_state *)&ctx->poly, ctx->key); } int Chacha20_Poly1305_Update(void *xctx, const uint8_t *data, uint16_t len) { static const char zeroes[POLY1305_BLOCK_LEN] = {0}; CHACHA20_POLY1305_CTX *ctx = (CHACHA20_POLY1305_CTX *)xctx; size_t rem; poly1305_update((poly1305_state *)&ctx->poly, data, len); /* number of bytes in the last 16 byte block */ rem = (len + POLY1305_BLOCK_LEN) & (POLY1305_BLOCK_LEN - 1); if (rem > 0) poly1305_update((poly1305_state *)&ctx->poly, (const unsigned char *)zeroes, (size_t)(POLY1305_BLOCK_LEN - rem)); return (0); } void Chacha20_Poly1305_Final(uint8_t tag[POLY1305_TAGLEN], void *xctx) { CHACHA20_POLY1305_CTX *ctx = (CHACHA20_POLY1305_CTX *)xctx; poly1305_finish((poly1305_state *)&ctx->poly, tag); memset(ctx, 0, sizeof(*ctx)); } ================================================ FILE: itl80211/openbsd/crypto/chachapoly.h ================================================ /* * Copyright (c) 2015 Mike Belopuhov * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _CHACHAPOLY_H_ #define _CHACHAPOLY_H_ #define CHACHA20_KEYSIZE 32 #define CHACHA20_CTR 4 #define CHACHA20_SALT 4 #define CHACHA20_NONCE 8 #define CHACHA20_BLOCK_LEN 64 struct chacha20_ctx { uint8_t block[CHACHA20_BLOCK_LEN]; uint8_t nonce[CHACHA20_NONCE]; }; int chacha20_setkey(void *, u_int8_t *, int); void chacha20_reinit(caddr_t, u_int8_t *); void chacha20_crypt(caddr_t, u_int8_t *); #define POLY1305_KEYLEN 32 #define POLY1305_TAGLEN 16 #define POLY1305_BLOCK_LEN 16 struct poly1305_ctx { /* r, h, pad, leftover */ unsigned long state[5+5+4]; size_t leftover; unsigned char buffer[POLY1305_BLOCK_LEN]; unsigned char final; }; typedef struct { uint8_t key[POLY1305_KEYLEN]; /* counter, salt */ uint8_t nonce[CHACHA20_NONCE]; struct chacha20_ctx chacha; struct poly1305_ctx poly; } CHACHA20_POLY1305_CTX; void Chacha20_Poly1305_Init(void *); void Chacha20_Poly1305_Setkey(void *, const uint8_t *, uint16_t); void Chacha20_Poly1305_Reinit(void *, const uint8_t *, uint16_t); int Chacha20_Poly1305_Update(void *, const uint8_t *, uint16_t); void Chacha20_Poly1305_Final(uint8_t[POLY1305_TAGLEN], void *); #endif /* _CHACHAPOLY_H_ */ ================================================ FILE: itl80211/openbsd/crypto/cmac.c ================================================ /* $OpenBSD: cmac.c,v 1.3 2017/05/02 17:07:06 mikeb Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the CMAC (Cipher-based Message Authentication) * algorithm described in FIPS SP800-38B using the AES-128 cipher. */ #include #include #include #include #define LSHIFT(v, r) do { \ int i; \ for (i = 0; i < 15; i++) \ (r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7; \ (r)[15] = (v)[15] << 1; \ } while (0) #define XOR(v, r) do { \ int i; \ for (i = 0; i < 16; i++) \ (r)[i] ^= (v)[i]; \ } while (0) void AES_CMAC_Init(AES_CMAC_CTX *ctx) { memset(ctx->X, 0, sizeof ctx->X); ctx->M_n = 0; } void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const u_int8_t key[AES_CMAC_KEY_LENGTH]) { AES_Setkey(&ctx->aesctx, key, 16); } void AES_CMAC_Update(AES_CMAC_CTX *ctx, const u_int8_t *data, u_int len) { u_int mlen; if (ctx->M_n > 0) { mlen = MIN(16 - ctx->M_n, len); memcpy(ctx->M_last + ctx->M_n, data, mlen); ctx->M_n += mlen; if (ctx->M_n < 16 || len == mlen) return; XOR(ctx->M_last, ctx->X); AES_Encrypt(&ctx->aesctx, ctx->X, ctx->X); data += mlen; len -= mlen; } while (len > 16) { /* not last block */ XOR(data, ctx->X); AES_Encrypt(&ctx->aesctx, ctx->X, ctx->X); data += 16; len -= 16; } /* potential last block, save it */ memcpy(ctx->M_last, data, len); ctx->M_n = len; } void AES_CMAC_Final(u_int8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx) { u_int8_t K[16]; /* generate subkey K1 */ memset(K, 0, sizeof K); AES_Encrypt(&ctx->aesctx, K, K); if (K[0] & 0x80) { LSHIFT(K, K); K[15] ^= 0x87; } else LSHIFT(K, K); if (ctx->M_n == 16) { /* last block was a complete block */ XOR(K, ctx->M_last); } else { /* generate subkey K2 */ if (K[0] & 0x80) { LSHIFT(K, K); K[15] ^= 0x87; } else LSHIFT(K, K); /* padding(M_last) */ ctx->M_last[ctx->M_n] = 0x80; while (++ctx->M_n < 16) ctx->M_last[ctx->M_n] = 0; XOR(K, ctx->M_last); } XOR(ctx->M_last, ctx->X); AES_Encrypt(&ctx->aesctx, ctx->X, digest); memset(K, 0, sizeof K); } ================================================ FILE: itl80211/openbsd/crypto/cmac.h ================================================ /* $OpenBSD: cmac.h,v 1.3 2017/05/02 17:07:06 mikeb Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _CMAC_H_ #define _CMAC_H_ #define AES_CMAC_KEY_LENGTH 16 #define AES_CMAC_DIGEST_LENGTH 16 typedef struct _AES_CMAC_CTX { AES_CTX aesctx; u_int8_t X[16]; u_int8_t M_last[16]; u_int M_n; } AES_CMAC_CTX; //__BEGIN_DECLS void AES_CMAC_Init(AES_CMAC_CTX *); void AES_CMAC_SetKey(AES_CMAC_CTX *, const u_int8_t [AES_CMAC_KEY_LENGTH]); void AES_CMAC_Update(AES_CMAC_CTX *, const u_int8_t *, u_int) __attribute__((__bounded__(__string__,2,3))); void AES_CMAC_Final(u_int8_t [AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *) __attribute__((__bounded__(__minbytes__,1,AES_CMAC_DIGEST_LENGTH))); //__END_DECLS #endif /* _CMAC_H_ */ ================================================ FILE: itl80211/openbsd/crypto/cryptodev.h ================================================ /* $OpenBSD: cryptodev.h,v 1.71 2017/08/10 18:57:20 tedu Exp $ */ /* * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) * * This code was written by Angelos D. Keromytis in Athens, Greece, in * February 2000. Network Security Technologies Inc. (NSTI) kindly * supported the development of this code. * * Copyright (c) 2000 Angelos D. Keromytis * * Permission to use, copy, and modify this software with or without fee * is hereby granted, provided that this entire notice is included in * all source code copies of any software which is or includes a copy or * modification of this software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR * PURPOSE. * * Copyright (c) 2001 Theo de Raadt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Effort sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F30602-01-2-0537. * */ #ifndef _CRYPTO_CRYPTO_H_ #define _CRYPTO_CRYPTO_H_ #include /* Some initial values */ #define CRYPTO_DRIVERS_INITIAL 4 #define CRYPTO_DRIVERS_MAX 128 #define CRYPTO_SW_SESSIONS 32 /* HMAC values */ #define HMAC_MD5_BLOCK_LEN 64 #define HMAC_SHA1_BLOCK_LEN 64 #define HMAC_RIPEMD160_BLOCK_LEN 64 #define HMAC_SHA2_256_BLOCK_LEN 64 #define HMAC_SHA2_384_BLOCK_LEN 128 #define HMAC_SHA2_512_BLOCK_LEN 128 #define HMAC_MAX_BLOCK_LEN HMAC_SHA2_512_BLOCK_LEN /* keep in sync */ #define HMAC_IPAD_VAL 0x36 #define HMAC_OPAD_VAL 0x5C /* Encryption algorithm block sizes */ #define DES3_BLOCK_LEN 8 #define BLOWFISH_BLOCK_LEN 8 #define CAST128_BLOCK_LEN 8 #define RIJNDAEL128_BLOCK_LEN 16 #define CHACHA20_BLOCK_LEN 64 #define EALG_MAX_BLOCK_LEN 64 /* Keep this updated */ /* Maximum hash algorithm result length */ #define AALG_MAX_RESULT_LEN 64 /* Keep this updated */ #define CRYPTO_3DES_CBC 1 #define CRYPTO_BLF_CBC 2 #define CRYPTO_CAST_CBC 3 #define CRYPTO_MD5_HMAC 4 #define CRYPTO_SHA1_HMAC 5 #define CRYPTO_RIPEMD160_HMAC 6 #define CRYPTO_RIJNDAEL128_CBC 7 /* 128 bit blocksize */ #define CRYPTO_AES_CBC 7 /* 128 bit blocksize -- the same as above */ #define CRYPTO_DEFLATE_COMP 8 /* Deflate compression algorithm */ #define CRYPTO_NULL 9 #define CRYPTO_LZS_COMP 10 /* LZS compression algorithm */ #define CRYPTO_SHA2_256_HMAC 11 #define CRYPTO_SHA2_384_HMAC 12 #define CRYPTO_SHA2_512_HMAC 13 #define CRYPTO_AES_CTR 14 #define CRYPTO_AES_XTS 15 #define CRYPTO_AES_GCM_16 16 #define CRYPTO_AES_128_GMAC 17 #define CRYPTO_AES_192_GMAC 18 #define CRYPTO_AES_256_GMAC 19 #define CRYPTO_AES_GMAC 20 #define CRYPTO_CHACHA20_POLY1305 21 #define CRYPTO_CHACHA20_POLY1305_MAC 22 #define CRYPTO_ESN 23 /* Support for Extended Sequence Numbers */ #define CRYPTO_ALGORITHM_MAX 23 /* Keep updated */ /* Algorithm flags */ #define CRYPTO_ALG_FLAG_SUPPORTED 0x01 /* Algorithm is supported */ /* Standard initialization structure beginning */ struct cryptoini { int cri_alg; /* Algorithm to use */ int cri_klen; /* Key length, in bits */ int cri_rnd; /* Algorithm rounds, where relevant */ caddr_t cri_key; /* key to use */ union { u_int8_t iv[EALG_MAX_BLOCK_LEN]; /* IV to use */ u_int8_t esn[4]; /* high-order ESN */ } u; #define cri_iv u.iv #define cri_esn u.esn struct cryptoini *cri_next; }; /* Describe boundaries of a single crypto operation */ struct cryptodesc { int crd_skip; /* How many bytes to ignore from start */ int crd_len; /* How many bytes to process */ int crd_inject; /* Where to inject results, if applicable */ int crd_flags; #define CRD_F_ENCRYPT 0x01 /* Set when doing encryption */ #define CRD_F_IV_PRESENT 0x02 /* When encrypting, IV is already in place, so don't copy. */ #define CRD_F_IV_EXPLICIT 0x04 /* IV explicitly provided */ #define CRD_F_COMP 0x10 /* Set when doing compression */ #define CRD_F_ESN 0x20 /* Set when ESN field is provided */ struct cryptoini CRD_INI; /* Initialization/context data */ #define crd_esn CRD_INI.cri_esn #define crd_iv CRD_INI.cri_iv #define crd_key CRD_INI.cri_key #define crd_rnd CRD_INI.cri_rnd #define crd_alg CRD_INI.cri_alg #define crd_klen CRD_INI.cri_klen }; /* Structure describing complete operation */ struct cryptop { struct task crp_task; u_int64_t crp_sid; /* Session ID */ int crp_ilen; /* Input data total length */ int crp_olen; /* Result total length */ int crp_alloctype; /* Type of buf to allocate if needed */ int crp_etype; /* * Error type (zero means no error). * All error codes except EAGAIN * indicate possible data corruption (as in, * the data have been touched). On all * errors, the crp_sid may have changed * (reset to a new one), so the caller * should always check and use the new * value on future requests. */ int crp_flags; #define CRYPTO_F_IMBUF 0x0001 /* Input/output are mbuf chains, otherwise contig */ #define CRYPTO_F_IOV 0x0002 /* Input/output are uio */ #define CRYPTO_F_NOQUEUE 0x0008 /* Don't use crypto queue/thread */ #define CRYPTO_F_DONE 0x0010 /* request completed */ void *crp_buf; /* Data to be processed */ void *crp_opaque; /* Opaque pointer, passed along */ struct cryptodesc *crp_desc; /* List of processing descriptors */ struct cryptodesc crp_sdesc[2]; /* Static array for small ops */ int crp_ndesc; /* Amount of descriptors to use */ int crp_ndescalloc;/* Amount of descriptors allocated */ void (*crp_callback)(struct cryptop *); /* Callback function */ caddr_t crp_mac; }; #define CRYPTO_BUF_IOV 0x1 #define CRYPTO_BUF_MBUF 0x2 #define CRYPTO_OP_DECRYPT 0x0 #define CRYPTO_OP_ENCRYPT 0x1 /* Crypto capabilities structure */ struct cryptocap { u_int64_t cc_operations; /* Counter of how many ops done */ u_int64_t cc_bytes; /* Counter of how many bytes done */ u_int64_t cc_koperations; /* How many PK ops done */ u_int32_t cc_sessions; /* How many sessions allocated */ /* Symmetric/hash algorithms supported */ int cc_alg[CRYPTO_ALGORITHM_MAX + 1]; int cc_queued; /* Operations queued */ u_int8_t cc_flags; #define CRYPTOCAP_F_CLEANUP 0x01 #define CRYPTOCAP_F_SOFTWARE 0x02 #define CRYPTOCAP_F_MPSAFE 0x04 int (*cc_newsession) (u_int32_t *, struct cryptoini *); int (*cc_process) (struct cryptop *); int (*cc_freesession) (u_int64_t); }; int crypto_newsession(u_int64_t *, struct cryptoini *, int); int crypto_freesession(u_int64_t); int crypto_dispatch(struct cryptop *); int crypto_register(u_int32_t, int *, int (*)(u_int32_t *, struct cryptoini *), int (*)(u_int64_t), int (*)(struct cryptop *)); int crypto_unregister(u_int32_t, int); int32_t crypto_get_driverid(u_int8_t); int crypto_invoke(struct cryptop *); void crypto_done(struct cryptop *); void cuio_copydata(struct uio *, int, int, caddr_t); void cuio_copyback(struct uio *, int, int, const void *); int cuio_getptr(struct uio *, int, int *); int cuio_apply(struct uio *, int, int, int (*f)(caddr_t, caddr_t, unsigned int), caddr_t); struct cryptop *crypto_getreq(int); void crypto_freereq(struct cryptop *); #endif /* _CRYPTO_CRYPTO_H_ */ ================================================ FILE: itl80211/openbsd/crypto/des_locl.h ================================================ /* $OpenBSD: des_locl.h,v 1.7 2015/12/10 21:00:51 naddy Exp $ */ /* lib/des/des_locl.h */ /* Copyright (C) 1995 Eric Young (eay@mincom.oz.au) * All rights reserved. * * This file is part of an SSL implementation written * by Eric Young (eay@mincom.oz.au). * The implementation was written so as to conform with Netscapes SSL * specification. This library and applications are * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE * as long as the following conditions are aheared to. * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. If this code is used in a product, * Eric Young should be given attribution as the author of the parts used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Eric Young (eay@mincom.oz.au) * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #ifndef HEADER_DES_LOCL_H #define HEADER_DES_LOCL_H #include #include typedef unsigned char des_cblock[8]; typedef struct des_ks_struct { union { des_cblock cblock; /* make sure things are correct size on machines with * 8 byte longs */ int32_t pad[2]; } ks; } des_key_schedule[16]; #define DES_KEY_SZ (sizeof(des_cblock)) #define DES_SCHEDULE_SZ (sizeof(des_key_schedule)) void des_encrypt2(u_int32_t *data,des_key_schedule ks, int enc); #define ITERATIONS 16 #define HALF_ITERATIONS 8 #define c2l(c,l) (l =((u_int32_t)(*((c)++))) , \ l|=((u_int32_t)(*((c)++)))<< 8L, \ l|=((u_int32_t)(*((c)++)))<<16L, \ l|=((u_int32_t)(*((c)++)))<<24L) #define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ *((c)++)=(unsigned char)(((l)>>24L)&0xff)) #define D_ENCRYPT(Q,R,S) {\ u=(R^s[S ]); \ t=R^s[S+1]; \ t=((t>>4L)+(t<<28L)); \ Q^= des_SPtrans[1][(t )&0x3f]| \ des_SPtrans[3][(t>> 8L)&0x3f]| \ des_SPtrans[5][(t>>16L)&0x3f]| \ des_SPtrans[7][(t>>24L)&0x3f]| \ des_SPtrans[0][(u )&0x3f]| \ des_SPtrans[2][(u>> 8L)&0x3f]| \ des_SPtrans[4][(u>>16L)&0x3f]| \ des_SPtrans[6][(u>>24L)&0x3f]; } /* IP and FP * The problem is more of a geometric problem that random bit fiddling. 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1 The output has been subject to swaps of the form 0 1 -> 3 1 but the odd and even bits have been put into 2 3 2 0 different words. The main trick is to remember that t=((l>>size)^r)&(mask); r^=t; l^=(t<>(n))^(b))&(m)),\ (b)^=(t),\ (a)^=((t)<<(n))) #define IP(l,r) \ { \ register u_int32_t tt; \ PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \ PERM_OP(l,r,tt,16,0x0000ffffL); \ PERM_OP(r,l,tt, 2,0x33333333L); \ PERM_OP(l,r,tt, 8,0x00ff00ffL); \ PERM_OP(r,l,tt, 1,0x55555555L); \ } #define FP(l,r) \ { \ register u_int32_t tt; \ PERM_OP(l,r,tt, 1,0x55555555L); \ PERM_OP(r,l,tt, 8,0x00ff00ffL); \ PERM_OP(l,r,tt, 2,0x33333333L); \ PERM_OP(r,l,tt,16,0x0000ffffL); \ PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \ } #endif ================================================ FILE: itl80211/openbsd/crypto/ecb3_enc.c ================================================ /* $OpenBSD: ecb3_enc.c,v 1.3 2013/11/18 18:49:53 brad Exp $ */ /* lib/des/ecb3_enc.c */ /* Copyright (C) 1995 Eric Young (eay@mincom.oz.au) * All rights reserved. * * This file is part of an SSL implementation written * by Eric Young (eay@mincom.oz.au). * The implementation was written so as to conform with Netscapes SSL * specification. This library and applications are * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE * as long as the following conditions are aheared to. * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. If this code is used in a product, * Eric Young should be given attribution as the author of the parts used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Eric Young (eay@mincom.oz.au) * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include "des_locl.h" void des_ecb3_encrypt(des_cblock (*input), des_cblock (*output), des_key_schedule ks1, des_key_schedule ks2, des_key_schedule ks3, int encrypt) { register u_int32_t l0, l1; register unsigned char *in, *out; u_int32_t ll[2]; in = (unsigned char *) input; out = (unsigned char *) output; c2l(in, l0); c2l(in, l1); IP(l0, l1); ll[0] = l0; ll[1] = l1; des_encrypt2(ll, ks1, encrypt); des_encrypt2(ll, ks2, !encrypt); des_encrypt2(ll, ks3, encrypt); l0 = ll[0]; l1 = ll[1]; FP(l1, l0); l2c(l0, out); l2c(l1, out); } ================================================ FILE: itl80211/openbsd/crypto/ecb_enc.c ================================================ /* $OpenBSD: ecb_enc.c,v 1.6 2015/12/10 21:00:51 naddy Exp $ */ /* lib/des/ecb_enc.c */ /* Copyright (C) 1995 Eric Young (eay@mincom.oz.au) * All rights reserved. * * This file is part of an SSL implementation written * by Eric Young (eay@mincom.oz.au). * The implementation was written so as to conform with Netscapes SSL * specification. This library and applications are * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE * as long as the following conditions are aheared to. * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. If this code is used in a product, * Eric Young should be given attribution as the author of the parts used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Eric Young (eay@mincom.oz.au) * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include "des_locl.h" #include "spr.h" void des_encrypt2(u_int32_t *data, des_key_schedule ks, int encrypt) { register u_int32_t l, r, t, u; #ifdef DES_USE_PTR register unsigned char *des_SP=(unsigned char *)des_SPtrans; #endif register int i; register u_int32_t *s; u = data[0]; r = data[1]; /* Things have been modified so that the initial rotate is * done outside the loop. This required the * des_SPtrans values in sp.h to be rotated 1 bit to the right. * One perl script later and things have a 5% speed up on a sparc2. * Thanks to Richard Outerbridge <71755.204@CompuServe.COM> * for pointing this out. */ l = (r << 1) | (r >> 31); r = (u << 1) | (u >> 31); /* clear the top bits on machines with 8byte longs */ l &= 0xffffffffL; r &= 0xffffffffL; s = (u_int32_t *) ks; /* I don't know if it is worth the effort of loop unrolling the * inner loop */ if (encrypt) { for (i = 0; i < 32; i += 4) { D_ENCRYPT(l, r, i + 0); /* 1 */ D_ENCRYPT(r, l, i + 2); /* 2 */ } } else { for (i = 30; i > 0; i -= 4) { D_ENCRYPT(l, r, i - 0); /* 16 */ D_ENCRYPT(r, l, i - 2); /* 15 */ } } l = (l >> 1) | (l << 31); r = (r >> 1) | (r << 31); /* clear the top bits on machines with 8byte longs */ l &= 0xffffffffL; r &= 0xffffffffL; data[0] = l; data[1] = r; l = r = t = u = 0; } ================================================ FILE: itl80211/openbsd/crypto/gmac.c ================================================ /* $OpenBSD: gmac.c,v 1.10 2017/05/02 11:44:32 mikeb Exp $ */ /* * Copyright (c) 2010 Mike Belopuhov * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the Message Authentication part of the * Galois/Counter Mode (as being described in the RFC 4543) using * the AES cipher. FIPS SP 800-38D describes the algorithm details. */ #include #include #include #include #include void ghash_gfmul(uint32_t *, uint32_t *, uint32_t *); void ghash_update_mi(GHASH_CTX *, uint8_t *, size_t); /* Allow overriding with optimized MD function */ void (*ghash_update)(GHASH_CTX *, uint8_t *, size_t) = ghash_update_mi; /* Computes a block multiplication in the GF(2^128) */ void ghash_gfmul(uint32_t *X, uint32_t *Y, uint32_t *product) { uint32_t v[4]; uint32_t z[4] = { 0, 0, 0, 0}; uint8_t *x = (uint8_t *)X; uint32_t mask; int i; v[0] = betoh32(Y[0]); v[1] = betoh32(Y[1]); v[2] = betoh32(Y[2]); v[3] = betoh32(Y[3]); for (i = 0; i < GMAC_BLOCK_LEN * 8; i++) { /* update Z */ mask = !!(x[i >> 3] & (1 << (~i & 7))); mask = ~(mask - 1); z[0] ^= v[0] & mask; z[1] ^= v[1] & mask; z[2] ^= v[2] & mask; z[3] ^= v[3] & mask; /* update V */ mask = ~((v[3] & 1) - 1); v[3] = (v[2] << 31) | (v[3] >> 1); v[2] = (v[1] << 31) | (v[2] >> 1); v[1] = (v[0] << 31) | (v[1] >> 1); v[0] = (v[0] >> 1) ^ (0xe1000000 & mask); } product[0] = htobe32(z[0]); product[1] = htobe32(z[1]); product[2] = htobe32(z[2]); product[3] = htobe32(z[3]); } void ghash_update_mi(GHASH_CTX *ctx, uint8_t *X, size_t len) { uint32_t *x = (uint32_t *)X; uint32_t *s = (uint32_t *)ctx->S; uint32_t *y = (uint32_t *)ctx->Z; int i; for (i = 0; i < len / GMAC_BLOCK_LEN; i++) { s[0] = y[0] ^ x[0]; s[1] = y[1] ^ x[1]; s[2] = y[2] ^ x[2]; s[3] = y[3] ^ x[3]; ghash_gfmul((uint32_t *)ctx->S, (uint32_t *)ctx->H, (uint32_t *)ctx->S); y = s; x += 4; } bcopy(ctx->S, ctx->Z, GMAC_BLOCK_LEN); } #define AESCTR_NONCESIZE 4 void AES_GMAC_Init(void *xctx) { AES_GMAC_CTX *ctx = (AES_GMAC_CTX *)xctx; bzero(ctx->ghash.H, GMAC_BLOCK_LEN); bzero(ctx->ghash.S, GMAC_BLOCK_LEN); bzero(ctx->ghash.Z, GMAC_BLOCK_LEN); bzero(ctx->J, GMAC_BLOCK_LEN); } void AES_GMAC_Setkey(void *xctx, const uint8_t *key, uint16_t klen) { AES_GMAC_CTX *ctx = (AES_GMAC_CTX *)xctx; AES_Setkey(&ctx->K, key, klen - AESCTR_NONCESIZE); /* copy out salt to the counter block */ bcopy(key + klen - AESCTR_NONCESIZE, ctx->J, AESCTR_NONCESIZE); /* prepare a hash subkey */ AES_Encrypt(&ctx->K, ctx->ghash.H, ctx->ghash.H); } void AES_GMAC_Reinit(void *xctx, const uint8_t *iv, uint16_t ivlen) { AES_GMAC_CTX *ctx = (AES_GMAC_CTX *)xctx; /* copy out IV to the counter block */ bcopy(iv, ctx->J + AESCTR_NONCESIZE, ivlen); } int AES_GMAC_Update(void *xctx, const uint8_t *data, uint16_t len) { AES_GMAC_CTX *ctx = (AES_GMAC_CTX *)xctx; uint32_t blk[4] = { 0, 0, 0, 0 }; int plen; if (len > 0) { plen = len % GMAC_BLOCK_LEN; if (len >= GMAC_BLOCK_LEN) (*ghash_update)(&ctx->ghash, (uint8_t *)data, len - plen); if (plen) { memcpy((uint8_t *)blk, (uint8_t *)data + (len - plen), plen); (*ghash_update)(&ctx->ghash, (uint8_t *)blk, GMAC_BLOCK_LEN); } } return (0); } void AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN], void *xctx) { AES_GMAC_CTX *ctx = (AES_GMAC_CTX *)xctx; uint8_t keystream[GMAC_BLOCK_LEN]; int i; /* do one round of GCTR */ ctx->J[GMAC_BLOCK_LEN - 1] = 1; AES_Encrypt(&ctx->K, ctx->J, keystream); for (i = 0; i < GMAC_DIGEST_LEN; i++) digest[i] = ctx->ghash.S[i] ^ keystream[i]; memset(keystream, 0, sizeof(keystream)); } ================================================ FILE: itl80211/openbsd/crypto/gmac.h ================================================ /* $OpenBSD: gmac.h,v 1.6 2017/05/02 11:44:32 mikeb Exp $ */ /* * Copyright (c) 2010 Mike Belopuhov * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _GMAC_H_ #define _GMAC_H_ #include #define GMAC_BLOCK_LEN 16 #define GMAC_DIGEST_LEN 16 typedef struct _GHASH_CTX { uint8_t H[GMAC_BLOCK_LEN]; /* hash subkey */ uint8_t S[GMAC_BLOCK_LEN]; /* state */ uint8_t Z[GMAC_BLOCK_LEN]; /* initial state */ } GHASH_CTX; typedef struct _AES_GMAC_CTX { GHASH_CTX ghash; AES_CTX K; uint8_t J[GMAC_BLOCK_LEN]; /* counter block */ } AES_GMAC_CTX; //__BEGIN_DECLS extern void (*ghash_update)(GHASH_CTX *, uint8_t *, size_t); void AES_GMAC_Init(void *); void AES_GMAC_Setkey(void *, const uint8_t *, uint16_t); void AES_GMAC_Reinit(void *, const uint8_t *, uint16_t); int AES_GMAC_Update(void *, const uint8_t *, uint16_t); void AES_GMAC_Final(uint8_t [GMAC_DIGEST_LEN], void *); //__END_DECLS #endif /* _GMAC_H_ */ ================================================ FILE: itl80211/openbsd/crypto/hmac.c ================================================ /* $OpenBSD: hmac.c,v 1.4 2016/09/19 18:09:40 tedu Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the HMAC algorithm described in RFC 2104 using * the MD5, SHA1 and SHA-256 hash functions. */ #include #include #include #include #include #include void HMAC_MD5_Init(HMAC_MD5_CTX *ctx, const u_int8_t *key, u_int key_len) { u_int8_t k_ipad[MD5_BLOCK_LENGTH]; int i; if (key_len > MD5_BLOCK_LENGTH) { MD5Init(&ctx->ctx); MD5Update(&ctx->ctx, key, key_len); MD5Final(ctx->key, &ctx->ctx); ctx->key_len = MD5_DIGEST_LENGTH; } else { bcopy(key, ctx->key, key_len); ctx->key_len = key_len; } bzero(k_ipad, MD5_BLOCK_LENGTH); memcpy(k_ipad, ctx->key, ctx->key_len); for (i = 0; i < MD5_BLOCK_LENGTH; i++) k_ipad[i] ^= 0x36; MD5Init(&ctx->ctx); MD5Update(&ctx->ctx, k_ipad, MD5_BLOCK_LENGTH); memset(k_ipad, 0, sizeof k_ipad); } void HMAC_MD5_Update(HMAC_MD5_CTX *ctx, const u_int8_t *data, u_int len) { MD5Update(&ctx->ctx, data, len); } void HMAC_MD5_Final(u_int8_t digest[MD5_DIGEST_LENGTH], HMAC_MD5_CTX *ctx) { u_int8_t k_opad[MD5_BLOCK_LENGTH]; int i; MD5Final(digest, &ctx->ctx); bzero(k_opad, MD5_BLOCK_LENGTH); memcpy(k_opad, ctx->key, ctx->key_len); for (i = 0; i < MD5_BLOCK_LENGTH; i++) k_opad[i] ^= 0x5c; MD5Init(&ctx->ctx); MD5Update(&ctx->ctx, k_opad, MD5_BLOCK_LENGTH); MD5Update(&ctx->ctx, digest, MD5_DIGEST_LENGTH); MD5Final(digest, &ctx->ctx); memset(k_opad, 0, sizeof k_opad); } void HMAC_SHA1_Init(HMAC_SHA1_CTX *ctx, const u_int8_t *key, u_int key_len) { u_int8_t k_ipad[SHA1_BLOCK_LENGTH]; int i; if (key_len > SHA1_BLOCK_LENGTH) { SHA1Init(&ctx->ctx); SHA1Update(&ctx->ctx, key, key_len); SHA1Final(ctx->key, &ctx->ctx); ctx->key_len = SHA1_DIGEST_LENGTH; } else { bcopy(key, ctx->key, key_len); ctx->key_len = key_len; } bzero(k_ipad, SHA1_BLOCK_LENGTH); memcpy(k_ipad, ctx->key, ctx->key_len); for (i = 0; i < SHA1_BLOCK_LENGTH; i++) k_ipad[i] ^= 0x36; SHA1Init(&ctx->ctx); SHA1Update(&ctx->ctx, k_ipad, SHA1_BLOCK_LENGTH); memset(k_ipad, 0, sizeof k_ipad); } void HMAC_SHA1_Update(HMAC_SHA1_CTX *ctx, const u_int8_t *data, u_int len) { SHA1Update(&ctx->ctx, data, len); } void HMAC_SHA1_Final(u_int8_t digest[SHA1_DIGEST_LENGTH], HMAC_SHA1_CTX *ctx) { u_int8_t k_opad[SHA1_BLOCK_LENGTH]; int i; SHA1Final(digest, &ctx->ctx); bzero(k_opad, SHA1_BLOCK_LENGTH); memcpy(k_opad, ctx->key, ctx->key_len); for (i = 0; i < SHA1_BLOCK_LENGTH; i++) k_opad[i] ^= 0x5c; SHA1Init(&ctx->ctx); SHA1Update(&ctx->ctx, k_opad, SHA1_BLOCK_LENGTH); SHA1Update(&ctx->ctx, digest, SHA1_DIGEST_LENGTH); SHA1Final(digest, &ctx->ctx); memset(k_opad, 0, sizeof k_opad); } void HMAC_SHA256_Init(HMAC_SHA256_CTX *ctx, const u_int8_t *key, u_int key_len) { u_int8_t k_ipad[SHA256_BLOCK_LENGTH]; int i; if (key_len > SHA256_BLOCK_LENGTH) { SHA256Init(&ctx->ctx); SHA256Update(&ctx->ctx, key, key_len); SHA256Final(ctx->key, &ctx->ctx); ctx->key_len = SHA256_DIGEST_LENGTH; } else { bcopy(key, ctx->key, key_len); ctx->key_len = key_len; } bzero(k_ipad, SHA256_BLOCK_LENGTH); memcpy(k_ipad, ctx->key, ctx->key_len); for (i = 0; i < SHA256_BLOCK_LENGTH; i++) k_ipad[i] ^= 0x36; SHA256Init(&ctx->ctx); SHA256Update(&ctx->ctx, k_ipad, SHA256_BLOCK_LENGTH); memset(k_ipad, 0, sizeof k_ipad); } void HMAC_SHA256_Update(HMAC_SHA256_CTX *ctx, const u_int8_t *data, u_int len) { SHA256Update(&ctx->ctx, data, len); } void HMAC_SHA256_Final(u_int8_t digest[SHA256_DIGEST_LENGTH], HMAC_SHA256_CTX *ctx) { u_int8_t k_opad[SHA256_BLOCK_LENGTH]; int i; SHA256Final(digest, &ctx->ctx); bzero(k_opad, SHA256_BLOCK_LENGTH); memcpy(k_opad, ctx->key, ctx->key_len); for (i = 0; i < SHA256_BLOCK_LENGTH; i++) k_opad[i] ^= 0x5c; SHA256Init(&ctx->ctx); SHA256Update(&ctx->ctx, k_opad, SHA256_BLOCK_LENGTH); SHA256Update(&ctx->ctx, digest, SHA256_DIGEST_LENGTH); SHA256Final(digest, &ctx->ctx); memset(k_opad, 0, sizeof k_opad); } ================================================ FILE: itl80211/openbsd/crypto/hmac.h ================================================ /* $OpenBSD: hmac.h,v 1.3 2012/12/05 23:20:15 deraadt Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _HMAC_H_ #define _HMAC_H_ #include "sha2.h" #include "md5.h" typedef struct _HMAC_MD5_CTX { MD5_CTX ctx; u_int8_t key[MD5_BLOCK_LENGTH]; u_int key_len; } HMAC_MD5_CTX; typedef struct _HMAC_SHA1_CTX { SHA1_CTX ctx; u_int8_t key[SHA1_BLOCK_LENGTH]; u_int key_len; } HMAC_SHA1_CTX; typedef struct _HMAC_SHA256_CTX { SHA2_CTX ctx; u_int8_t key[SHA256_BLOCK_LENGTH]; u_int key_len; } HMAC_SHA256_CTX; //__BEGIN_DECLS void HMAC_MD5_Init(HMAC_MD5_CTX *, const u_int8_t *, u_int) __attribute__((__bounded__(__string__,2,3))); void HMAC_MD5_Update(HMAC_MD5_CTX *, const u_int8_t *, u_int) __attribute__((__bounded__(__string__,2,3))); void HMAC_MD5_Final(u_int8_t [MD5_DIGEST_LENGTH], HMAC_MD5_CTX *) __attribute__((__bounded__(__minbytes__,1,MD5_DIGEST_LENGTH))); void HMAC_SHA1_Init(HMAC_SHA1_CTX *, const u_int8_t *, u_int) __attribute__((__bounded__(__string__,2,3))); void HMAC_SHA1_Update(HMAC_SHA1_CTX *, const u_int8_t *, u_int) __attribute__((__bounded__(__string__,2,3))); void HMAC_SHA1_Final(u_int8_t [SHA1_DIGEST_LENGTH], HMAC_SHA1_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA1_DIGEST_LENGTH))); void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const u_int8_t *, u_int) __attribute__((__bounded__(__string__,2,3))); void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const u_int8_t *, u_int) __attribute__((__bounded__(__string__,2,3))); void HMAC_SHA256_Final(u_int8_t [SHA256_DIGEST_LENGTH], HMAC_SHA256_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA256_DIGEST_LENGTH))); //__END_DECLS #endif /* _HMAC_H_ */ ================================================ FILE: itl80211/openbsd/crypto/idgen.c ================================================ /* * Copyright (c) 2008 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * IDGEN32: non-repeating ID generation covering an almost maximal 32-bit * range. * * IDGEN32 is based on public domain SKIP32 by Greg Rose. */ #include #include #include #include #include #define time_second 20 static const u_int8_t idgen32_ftable[256] = { 0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9, 0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28, 0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53, 0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2, 0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8, 0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90, 0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76, 0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d, 0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18, 0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4, 0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40, 0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5, 0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2, 0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8, 0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac, 0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46 }; static u_int16_t idgen32_g(u_int8_t *key, int k, u_int16_t w) { u_int8_t g1, g2, g3, g4, g5, g6; u_int o = k * 4; g1 = (w >> 8) & 0xff; g2 = w & 0xff; g3 = idgen32_ftable[g2 ^ key[o++ & (IDGEN32_KEYLEN - 1)]] ^ g1; g4 = idgen32_ftable[g3 ^ key[o++ & (IDGEN32_KEYLEN - 1)]] ^ g2; g5 = idgen32_ftable[g4 ^ key[o++ & (IDGEN32_KEYLEN - 1)]] ^ g3; g6 = idgen32_ftable[g5 ^ key[o++ & (IDGEN32_KEYLEN - 1)]] ^ g4; return (g5 << 8) | g6; } static u_int32_t idgen32_permute(struct idgen32_ctx *ctx, u_int32_t in) { u_int i, r; u_int16_t wl, wr; wl = (in >> 16) & 0x7fff; wr = in & 0xffff; /* Doubled up rounds, with an odd round at the end to swap */ for (i = r = 0; i < IDGEN32_ROUNDS / 2; ++i) { wr ^= (idgen32_g(ctx->id32_key, r, wl) ^ r); r++; wl ^= (idgen32_g(ctx->id32_key, r, wr) ^ r) & 0x7fff; r++; } wr ^= (idgen32_g(ctx->id32_key, r, wl) ^ r); return (wl << 16) | wr; } static void idgen32_rekey(struct idgen32_ctx *ctx) { ctx->id32_counter = 0; ctx->id32_hibit ^= 0x80000000; ctx->id32_offset = arc4random(); arc4random_buf(ctx->id32_key, sizeof(ctx->id32_key)); ctx->id32_rekey_time = time_second + IDGEN32_REKEY_TIME; } void idgen32_init(struct idgen32_ctx *ctx) { bzero(ctx, sizeof(*ctx)); ctx->id32_hibit = arc4random() & 0x80000000; idgen32_rekey(ctx); } u_int32_t idgen32(struct idgen32_ctx *ctx) { u_int32_t ret; do { /* Rekey a little early to avoid "card counting" attack */ if (ctx->id32_counter > IDGEN32_REKEY_LIMIT || ctx->id32_rekey_time < time_second) idgen32_rekey(ctx); ret = ctx->id32_hibit | idgen32_permute(ctx, (ctx->id32_offset + ctx->id32_counter++) & 0x7fffffff); } while (ret == 0); /* Zero IDs are often special, so avoid */ return ret; } ================================================ FILE: itl80211/openbsd/crypto/idgen.h ================================================ /* $OpenBSD: idgen.h,v 1.3 2013/06/05 05:45:54 djm Exp $ */ /* * Copyright (c) 2008 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define IDGEN32_ROUNDS 31 #define IDGEN32_KEYLEN 32 #define IDGEN32_REKEY_LIMIT 0x60000000 #define IDGEN32_REKEY_TIME 600 struct idgen32_ctx { u_int32_t id32_counter; u_int32_t id32_offset; u_int32_t id32_hibit; u_int8_t id32_key[IDGEN32_KEYLEN]; time_t id32_rekey_time; }; void idgen32_init(struct idgen32_ctx *); u_int32_t idgen32(struct idgen32_ctx *); ================================================ FILE: itl80211/openbsd/crypto/key_wrap.c ================================================ /* $OpenBSD: key_wrap.c,v 1.5 2017/05/02 17:07:06 mikeb Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the AES Key Wrap algorithm described in RFC 3394. */ #include #include #include #include #include static const u_int8_t IV[8] = { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 }; void aes_key_wrap_set_key(aes_key_wrap_ctx *ctx, const u_int8_t *K, size_t K_len) { AES_Setkey(&ctx->ctx, K, K_len); } void aes_key_wrap_set_key_wrap_only(aes_key_wrap_ctx *ctx, const u_int8_t *K, size_t K_len) { AES_Setkey(&ctx->ctx, K, K_len); } void aes_key_wrap(aes_key_wrap_ctx *ctx, const u_int8_t *P, size_t n, u_int8_t *C) { u_int64_t B[2], t; u_int8_t *A, *R; size_t i; int j; memmove(C + 8, P, n * 8); /* P and C may overlap */ A = C; /* A points to C[0] */ memcpy(A, IV, 8); /* A = IV, an initial value */ for (j = 0, t = 1; j <= 5; j++) { R = C + 8; for (i = 1; i <= n; i++, t++) { /* B = A | R[i] */ memcpy(&B[0], A, 8); memcpy(&B[1], R, 8); /* B = AES(K, B) */ AES_Encrypt(&ctx->ctx, (const uint8_t *)(caddr_t)B, (uint8_t *)(caddr_t)B); /* MSB(64, B) = MSB(64, B) ^ t */ B[0] ^= htobe64(t); /* A = MSB(64, B) */ memcpy(A, &B[0], 8); /* R[i] = LSB(64, B) */ memcpy(R, &B[1], 8); R += 8; } } memset(B, 0, sizeof B); } int aes_key_unwrap(aes_key_wrap_ctx *ctx, const u_int8_t *C, u_int8_t *P, size_t n) { u_int64_t B[2], t; u_int8_t A[8], *R; size_t i; int j; memcpy(A, C, 8); /* A = C[0] */ memmove(P, C + 8, n * 8); /* P and C may overlap */ for (j = 5, t = 6 * n; j >= 0; j--) { R = P + (n - 1) * 8; for (i = n; i >= 1; i--, t--) { /* MSB(64, B) = A */ memcpy(&B[0], A, 8); /* MSB(64, B) = MSB(64, B) ^ t */ B[0] ^= htobe64(t); /* B = MSB(64, B) | R[i] */ memcpy(&B[1], R, 8); /* B = AES-1(K, B) */ AES_Decrypt(&ctx->ctx, (const uint8_t *)(caddr_t)B, (uint8_t *)(caddr_t)B); /* A = MSB(64, B) */ memcpy(A, &B[0], 8); /* R[i] = LSB(64, B) */ memcpy(R, &B[1], 8); R -= 8; } } memset(B, 0, sizeof B); /* check that A is an appropriate initial value */ return timingsafe_bcmp(A, IV, 8) != 0; } ================================================ FILE: itl80211/openbsd/crypto/key_wrap.h ================================================ /* $OpenBSD: key_wrap.h,v 1.3 2017/05/02 17:07:06 mikeb Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _KEY_WRAP_H_ #define _KEY_WRAP_H_ extern int timingsafe_bcmp(const void *b1, const void *b2, size_t n); typedef struct _aes_key_wrap_ctx { AES_CTX ctx; } aes_key_wrap_ctx; //__BEGIN_DECLS void aes_key_wrap_set_key(aes_key_wrap_ctx *, const u_int8_t *, size_t); void aes_key_wrap_set_key_wrap_only(aes_key_wrap_ctx *, const u_int8_t *, size_t); void aes_key_wrap(aes_key_wrap_ctx *, const u_int8_t *, size_t, u_int8_t *); int aes_key_unwrap(aes_key_wrap_ctx *, const u_int8_t *, u_int8_t *, size_t); //__END_DECLS #endif /* _KEY_WRAP_H_ */ ================================================ FILE: itl80211/openbsd/crypto/md5.c ================================================ /* $OpenBSD: md5.c,v 1.4 2014/12/28 10:04:35 tedu Exp $ */ /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include #include #include #define PUT_64BIT_LE(cp, value) do { \ (cp)[7] = (value) >> 56; \ (cp)[6] = (value) >> 48; \ (cp)[5] = (value) >> 40; \ (cp)[4] = (value) >> 32; \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) #define PUT_32BIT_LE(cp, value) do { \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) static u_int8_t PADDING[MD5_BLOCK_LENGTH] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(MD5_CTX *ctx) { ctx->count = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89; ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(MD5_CTX *ctx, const void *inputptr, size_t len) { const uint8_t *input = (const uint8_t *)inputptr; size_t have, need; /* Check how many bytes we already have and how many more we need. */ have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); need = MD5_BLOCK_LENGTH - have; /* Update bitcount */ ctx->count += (u_int64_t)len << 3; if (len >= need) { if (have != 0) { memcpy(ctx->buffer + have, input, need); MD5Transform(ctx->state, ctx->buffer); input += need; len -= need; have = 0; } /* Process data in MD5_BLOCK_LENGTH-byte chunks. */ while (len >= MD5_BLOCK_LENGTH) { MD5Transform(ctx->state, input); input += MD5_BLOCK_LENGTH; len -= MD5_BLOCK_LENGTH; } } /* Handle any remaining bytes of data. */ if (len != 0) memcpy(ctx->buffer + have, input, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) { u_int8_t count[8]; size_t padlen; int i; /* Convert count to 8 bytes in little endian order. */ PUT_64BIT_LE(count, ctx->count); /* Pad out to 56 mod 64. */ padlen = MD5_BLOCK_LENGTH - ((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); if (padlen < 1 + 8) padlen += MD5_BLOCK_LENGTH; MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ MD5Update(ctx, count, 8); for (i = 0; i < 4; i++) PUT_32BIT_LE(digest + i * 4, ctx->state[i]); memset(ctx, 0, sizeof(*ctx)); /* in case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH]) { u_int32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4]; #if BYTE_ORDER == LITTLE_ENDIAN memcpy(in, block, sizeof(in)); #else for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) { in[a] = (u_int32_t)( (u_int32_t)(block[a * 4 + 0]) | (u_int32_t)(block[a * 4 + 1]) << 8 | (u_int32_t)(block[a * 4 + 2]) << 16 | (u_int32_t)(block[a * 4 + 3]) << 24); } #endif a = state[0]; b = state[1]; c = state[2]; d = state[3]; MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21); state[0] += a; state[1] += b; state[2] += c; state[3] += d; } ================================================ FILE: itl80211/openbsd/crypto/md5.h ================================================ /* $OpenBSD: md5.h,v 1.3 2014/11/16 17:39:09 tedu Exp $ */ /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. */ #ifndef _MD5_H_ #define _MD5_H_ #define MD5_BLOCK_LENGTH 64 #define MD5_DIGEST_LENGTH 16 typedef struct MD5Context { u_int32_t state[4]; /* state */ u_int64_t count; /* number of bits, mod 2^64 */ u_int8_t buffer[MD5_BLOCK_LENGTH]; /* input buffer */ } MD5_CTX; //__BEGIN_DECLS void MD5Init(MD5_CTX *); void MD5Update(MD5_CTX *, const void *, size_t) __attribute__((__bounded__(__string__,2,3))); void MD5Final(u_int8_t [MD5_DIGEST_LENGTH], MD5_CTX *) __attribute__((__bounded__(__minbytes__,1,MD5_DIGEST_LENGTH))); void MD5Transform(u_int32_t [4], const u_int8_t [MD5_BLOCK_LENGTH]) __attribute__((__bounded__(__minbytes__,1,4))) __attribute__((__bounded__(__minbytes__,2,MD5_BLOCK_LENGTH))); //__END_DECLS #endif /* _MD5_H_ */ ================================================ FILE: itl80211/openbsd/crypto/michael.c ================================================ /* $OpenBSD: michael.c,v 1.2 2008/07/21 19:52:45 damien Exp $ */ /* * Copyright (c) 2005, 2006 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Implementation of the Michael MIC as defined in IEEE 802.11i for TKIP. * The MIC generates a 64bit digest, which shouldn't be used for any other * applications except TKIP. */ #include #include #include #define ROL(n, x) (((x) << (n)) | ((x) >> (32 - (n)))) #define ROR(n, x) (((x) >> (n)) | ((x) << (32 - (n)))) #define XSWAP(x) (((x) & 0xff00ff00UL) >> 8 | ((x) & 0x00ff00ffUL) << 8) #if defined(__STRICT_ALIGNMENT) || _BYTE_ORDER != _LITTLE_ENDIAN #define GETLE32(x) ((x)[0] | (x)[1] << 8 | (x)[2] << 16 | (x)[3] << 24) #define PUTLE32(x, v) ((x)[0] = (u_int8_t)(v), \ (x)[1] = (u_int8_t)((v) >> 8), \ (x)[2] = (u_int8_t)((v) >> 16), \ (x)[3] = (u_int8_t)((v) >> 24)) #else #define GETLE32(x) (*((u_int32_t *)(x))) #define PUTLE32(x, v) (*((u_int32_t *)(x)) = (v)) #endif #define MICHAEL_BLOCK(l, r) do { \ r ^= ROL(17, l); \ l += r; \ r ^= XSWAP(l); \ l += r; \ r ^= ROL(3, l); \ l += r; \ r ^= ROR(2, l); \ l += r; \ } while (0) void michael_init(MICHAEL_CTX *ctx) { bzero(ctx, sizeof(MICHAEL_CTX)); } void michael_update(MICHAEL_CTX *ctx, const u_int8_t *data, u_int len) { int i; for (i = 0; i < len; i++) { ctx->michael_state |= data[i] << (ctx->michael_count << 3); ctx->michael_count++; if (ctx->michael_count >= MICHAEL_RAW_BLOCK_LENGTH) { ctx->michael_l ^= ctx->michael_state; MICHAEL_BLOCK(ctx->michael_l, ctx->michael_r); ctx->michael_state = ctx->michael_count = 0; } } } void michael_final(u_int8_t digest[MICHAEL_DIGEST_LENGTH], MICHAEL_CTX *ctx) { static const u_int8_t pad[] = { 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; michael_update(ctx, pad, sizeof(pad)); PUTLE32(digest, ctx->michael_l); PUTLE32(digest + MICHAEL_RAW_BLOCK_LENGTH, ctx->michael_r); } void michael_key(const u_int8_t *key, MICHAEL_CTX *ctx) { ctx->michael_l = ctx->michael_key[0] = GETLE32(key); ctx->michael_r = ctx->michael_key[1] = GETLE32(key + MICHAEL_RAW_BLOCK_LENGTH); } ================================================ FILE: itl80211/openbsd/crypto/michael.h ================================================ /* $OpenBSD: michael.h,v 1.2 2012/12/05 23:20:15 deraadt Exp $ */ /* * Copyright (c) 2005, 2006 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _MICHAEL_H_ #define _MICHAEL_H_ #define MICHAEL_BLOCK_LENGTH 8 #define MICHAEL_RAW_BLOCK_LENGTH 4 #define MICHAEL_DIGEST_LENGTH 8 typedef struct michael_context { u_int32_t michael_key[2]; u_int32_t michael_l, michael_r; u_int32_t michael_state; u_int michael_count; } MICHAEL_CTX; //__BEGIN_DECLS void michael_init(MICHAEL_CTX *); void michael_update(MICHAEL_CTX *, const u_int8_t *, u_int) __attribute__((__bounded__(__buffer__, 2, 3))); void michael_final(u_int8_t [MICHAEL_DIGEST_LENGTH], MICHAEL_CTX *) __attribute__((__bounded__(__minbytes__, 1, MICHAEL_DIGEST_LENGTH))); void michael_key(const u_int8_t *, MICHAEL_CTX *) __attribute__((__bounded__(__minbytes__, 1, MICHAEL_BLOCK_LENGTH))); //__END_DECLS #endif /* _MICHAEL_H_ */ ================================================ FILE: itl80211/openbsd/crypto/podd.h ================================================ /* $OpenBSD: podd.h,v 1.1 2000/02/28 23:13:05 deraadt Exp $ */ /* lib/des/podd.h */ /* Copyright (C) 1995 Eric Young (eay@mincom.oz.au) * All rights reserved. * * This file is part of an SSL implementation written * by Eric Young (eay@mincom.oz.au). * The implementation was written so as to conform with Netscapes SSL * specification. This library and applications are * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE * as long as the following conditions are aheared to. * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. If this code is used in a product, * Eric Young should be given attribution as the author of the parts used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Eric Young (eay@mincom.oz.au) * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ static const unsigned char odd_parity[256]={ 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254}; ================================================ FILE: itl80211/openbsd/crypto/poly1305.c ================================================ /* * Public Domain poly1305 from Andrew Moon * Based on poly1305-donna.c, poly1305-donna-32.h and poly1305-donna.h from: * https://github.com/floodyberry/poly1305-donna */ #include #include #include "poly1305.h" /* * poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication * and 64 bit addition. */ /* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ static unsigned long U8TO32(const unsigned char *p) { return (((unsigned long)(p[0] & 0xff)) | ((unsigned long)(p[1] & 0xff) << 8) | ((unsigned long)(p[2] & 0xff) << 16) | ((unsigned long)(p[3] & 0xff) << 24)); } /* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ static void U32TO8(unsigned char *p, unsigned long v) { p[0] = (v) & 0xff; p[1] = (v >> 8) & 0xff; p[2] = (v >> 16) & 0xff; p[3] = (v >> 24) & 0xff; } void poly1305_init(poly1305_state *st, const unsigned char key[32]) { /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ st->r[0] = (U8TO32(&key[0])) & 0x3ffffff; st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03; st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff; st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff; st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; /* h = 0 */ st->h[0] = 0; st->h[1] = 0; st->h[2] = 0; st->h[3] = 0; st->h[4] = 0; /* save pad for later */ st->pad[0] = U8TO32(&key[16]); st->pad[1] = U8TO32(&key[20]); st->pad[2] = U8TO32(&key[24]); st->pad[3] = U8TO32(&key[28]); st->leftover = 0; st->final = 0; } static void poly1305_blocks(poly1305_state *st, const unsigned char *m, size_t bytes) { const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */ unsigned long r0, r1, r2, r3, r4; unsigned long s1, s2, s3, s4; unsigned long h0, h1, h2, h3, h4; unsigned long long d0, d1, d2, d3, d4; unsigned long c; r0 = st->r[0]; r1 = st->r[1]; r2 = st->r[2]; r3 = st->r[3]; r4 = st->r[4]; s1 = r1 * 5; s2 = r2 * 5; s3 = r3 * 5; s4 = r4 * 5; h0 = st->h[0]; h1 = st->h[1]; h2 = st->h[2]; h3 = st->h[3]; h4 = st->h[4]; while (bytes >= poly1305_block_size) { /* h += m[i] */ h0 += (U8TO32(m + 0)) & 0x3ffffff; h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff; h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff; h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff; h4 += (U8TO32(m + 12) >> 8) | hibit; /* h *= r */ d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); /* (partial) h %= p */ c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; h1 += c; m += poly1305_block_size; bytes -= poly1305_block_size; } st->h[0] = h0; st->h[1] = h1; st->h[2] = h2; st->h[3] = h3; st->h[4] = h4; } void poly1305_update(poly1305_state *st, const unsigned char *m, size_t bytes) { size_t i; /* handle leftover */ if (st->leftover) { size_t want = (poly1305_block_size - st->leftover); if (want > bytes) want = bytes; for (i = 0; i < want; i++) st->buffer[st->leftover + i] = m[i]; bytes -= want; m += want; st->leftover += want; if (st->leftover < poly1305_block_size) return; poly1305_blocks(st, st->buffer, poly1305_block_size); st->leftover = 0; } /* process full blocks */ if (bytes >= poly1305_block_size) { size_t want = (bytes & ~(poly1305_block_size - 1)); poly1305_blocks(st, m, want); m += want; bytes -= want; } /* store leftover */ if (bytes) { for (i = 0; i < bytes; i++) st->buffer[st->leftover + i] = m[i]; st->leftover += bytes; } } void poly1305_finish(poly1305_state *st, unsigned char mac[16]) { unsigned long h0, h1, h2, h3, h4, c; unsigned long g0, g1, g2, g3, g4; unsigned long long f; unsigned long mask; /* process the remaining block */ if (st->leftover) { size_t i = st->leftover; st->buffer[i++] = 1; for (; i < poly1305_block_size; i++) st->buffer[i] = 0; st->final = 1; poly1305_blocks(st, st->buffer, poly1305_block_size); } /* fully carry h */ h0 = st->h[0]; h1 = st->h[1]; h2 = st->h[2]; h3 = st->h[3]; h4 = st->h[4]; c = h1 >> 26; h1 = h1 & 0x3ffffff; h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; h1 += c; /* compute h + -p */ g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; g4 = h4 + c - (1 << 26); /* select h if h < p, or h + -p if h >= p */ mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; g0 &= mask; g1 &= mask; g2 &= mask; g3 &= mask; g4 &= mask; mask = ~mask; h0 = (h0 & mask) | g0; h1 = (h1 & mask) | g1; h2 = (h2 & mask) | g2; h3 = (h3 & mask) | g3; h4 = (h4 & mask) | g4; /* h = h % (2^128) */ h0 = ((h0) | (h1 << 26)) & 0xffffffff; h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; /* mac = (h + pad) % (2^128) */ f = (unsigned long long)h0 + st->pad[0]; h0 = (unsigned long)f; f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; U32TO8(mac + 0, h0); U32TO8(mac + 4, h1); U32TO8(mac + 8, h2); U32TO8(mac + 12, h3); /* zero out the state */ st->h[0] = 0; st->h[1] = 0; st->h[2] = 0; st->h[3] = 0; st->h[4] = 0; st->r[0] = 0; st->r[1] = 0; st->r[2] = 0; st->r[3] = 0; st->r[4] = 0; st->pad[0] = 0; st->pad[1] = 0; st->pad[2] = 0; st->pad[3] = 0; } ================================================ FILE: itl80211/openbsd/crypto/poly1305.h ================================================ /* * Public Domain poly1305 from Andrew Moon * * poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication * and 64 bit addition from https://github.com/floodyberry/poly1305-donna */ #ifndef _POLY1305_H_ #define _POLY1305_H_ #define poly1305_block_size 16 typedef struct poly1305_state { unsigned long r[5]; unsigned long h[5]; unsigned long pad[4]; size_t leftover; unsigned char buffer[poly1305_block_size]; unsigned char final; } poly1305_state; void poly1305_init(poly1305_state *, const unsigned char[32]); void poly1305_update(poly1305_state *, const unsigned char *, size_t); void poly1305_finish(poly1305_state *, unsigned char[16]); #endif /* _POLY1305_H_ */ ================================================ FILE: itl80211/openbsd/crypto/rijndael.c ================================================ /* $OpenBSD: rijndael.c,v 1.20 2014/11/17 12:27:47 mikeb Exp $ */ /** * rijndael-alg-fst.c * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #undef FULL_UNROLL /* Te0[x] = S [x].[02, 01, 01, 03]; Te1[x] = S [x].[03, 02, 01, 01]; Te2[x] = S [x].[01, 03, 02, 01]; Te3[x] = S [x].[01, 01, 03, 02]; Td0[x] = Si[x].[0e, 09, 0d, 0b]; Td1[x] = Si[x].[0b, 0e, 09, 0d]; Td2[x] = Si[x].[0d, 0b, 0e, 09]; Td3[x] = Si[x].[09, 0d, 0b, 0e]; Td4[x] = Si[x].[01]; */ static const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; static const u32 Te1[256] = { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }; static const u32 Te2[256] = { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }; static const u32 Te3[256] = { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }; static const u32 Td0[256] = { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }; static const u32 Td1[256] = { 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, }; static const u32 Td2[256] = { 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, }; static const u32 Td3[256] = { 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }; static const u8 Td4[256] = { 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, }; static const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) #define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } /** * Expand the cipher key into the encryption key schedule. * * @return the number of rounds for the given cipher key size. */ int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int i = 0; u32 temp; rk[0] = GETU32(cipherKey ); rk[1] = GETU32(cipherKey + 4); rk[2] = GETU32(cipherKey + 8); rk[3] = GETU32(cipherKey + 12); if (keyBits == 128) { for (;;) { temp = rk[3]; rk[4] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te0[(temp ) & 0xff] & 0x0000ff00) ^ (Te1[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; if (++i == 10) { return 10; } rk += 4; } } rk[4] = GETU32(cipherKey + 16); rk[5] = GETU32(cipherKey + 20); if (keyBits == 192) { for (;;) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te0[(temp ) & 0xff] & 0x0000ff00) ^ (Te1[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; rk[ 9] = rk[ 3] ^ rk[ 8]; if (++i == 8) { return 12; } rk[10] = rk[ 4] ^ rk[ 9]; rk[11] = rk[ 5] ^ rk[10]; rk += 6; } } rk[6] = GETU32(cipherKey + 24); rk[7] = GETU32(cipherKey + 28); if (keyBits == 256) { for (;;) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te0[(temp ) & 0xff] & 0x0000ff00) ^ (Te1[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) { return 14; } temp = rk[11]; rk[12] = rk[ 4] ^ (Te2[(temp >> 24) ] & 0xff000000) ^ (Te3[(temp >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(temp >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(temp ) & 0xff] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } } return 0; } /** * Expand the cipher key into the decryption key schedule. * * @return the number of rounds for the given cipher key size. */ int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int Nr, i, j; u32 temp; /* expand the cipher key: */ Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); /* invert the order of the round keys: */ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; } /* apply the inverse MixColumn transform to all round keys but the first and the last: */ for (i = 1; i < Nr; i++) { rk += 4; rk[0] = Td0[Te1[(rk[0] >> 24) ] & 0xff] ^ Td1[Te1[(rk[0] >> 16) & 0xff] & 0xff] ^ Td2[Te1[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[0] ) & 0xff] & 0xff]; rk[1] = Td0[Te1[(rk[1] >> 24) ] & 0xff] ^ Td1[Te1[(rk[1] >> 16) & 0xff] & 0xff] ^ Td2[Te1[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[1] ) & 0xff] & 0xff]; rk[2] = Td0[Te1[(rk[2] >> 24) ] & 0xff] ^ Td1[Te1[(rk[2] >> 16) & 0xff] & 0xff] ^ Td2[Te1[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[2] ) & 0xff] & 0xff]; rk[3] = Td0[Te1[(rk[3] >> 24) ] & 0xff] ^ Td1[Te1[(rk[3] >> 16) & 0xff] & 0xff] ^ Td2[Te1[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[3] ) & 0xff] & 0xff]; } return Nr; } void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(pt ) ^ rk[0]; s1 = GETU32(pt + 4) ^ rk[1]; s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; /* round 3: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; /* round 4: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; /* round 5: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; /* round 6: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; /* round 7: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; /* round 8: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; /* round 9: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; /* round 11: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; /* round 13: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Te0[(s0 >> 24) ] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3 ) & 0xff] ^ rk[4]; t1 = Te0[(s1 >> 24) ] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0 ) & 0xff] ^ rk[5]; t2 = Te0[(s2 >> 24) ] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1 ) & 0xff] ^ rk[6]; t3 = Te0[(s3 >> 24) ] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te0[(t0 >> 24) ] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[(t3 ) & 0xff] ^ rk[0]; s1 = Te0[(t1 >> 24) ] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[(t0 ) & 0xff] ^ rk[1]; s2 = Te0[(t2 >> 24) ] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[(t1 ) & 0xff] ^ rk[2]; s3 = Te0[(t3 >> 24) ] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[(t2 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Te2[(t0 >> 24) ] & 0xff000000) ^ (Te3[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t3 ) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(ct , s0); s1 = (Te2[(t1 >> 24) ] & 0xff000000) ^ (Te3[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t0 ) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(ct + 4, s1); s2 = (Te2[(t2 >> 24) ] & 0xff000000) ^ (Te3[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t1 ) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(ct + 8, s2); s3 = (Te2[(t3 >> 24) ] & 0xff000000) ^ (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t2 ) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(ct + 12, s3); } static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(ct ) ^ rk[0]; s1 = GETU32(ct + 4) ^ rk[1]; s2 = GETU32(ct + 8) ^ rk[2]; s3 = GETU32(ct + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; /* round 3: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; /* round 4: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; /* round 5: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; /* round 6: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; /* round 7: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; /* round 8: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; /* round 9: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; /* round 11: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; /* round 13: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Td0[(s0 >> 24) ] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[(s1 ) & 0xff] ^ rk[4]; t1 = Td0[(s1 >> 24) ] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[(s2 ) & 0xff] ^ rk[5]; t2 = Td0[(s2 >> 24) ] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[(s3 ) & 0xff] ^ rk[6]; t3 = Td0[(s3 >> 24) ] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[(s0 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Td0[(t0 >> 24) ] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[(t1 ) & 0xff] ^ rk[0]; s1 = Td0[(t1 >> 24) ] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[(t2 ) & 0xff] ^ rk[1]; s2 = Td0[(t2 >> 24) ] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[(t3 ) & 0xff] ^ rk[2]; s3 = Td0[(t3 >> 24) ] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[(t0 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Td4[(t0 >> 24) ] << 24) ^ (Td4[(t3 >> 16) & 0xff] << 16) ^ (Td4[(t2 >> 8) & 0xff] << 8) ^ (Td4[(t1 ) & 0xff]) ^ rk[0]; PUTU32(pt , s0); s1 = (Td4[(t1 >> 24) ] << 24) ^ (Td4[(t0 >> 16) & 0xff] << 16) ^ (Td4[(t3 >> 8) & 0xff] << 8) ^ (Td4[(t2 ) & 0xff]) ^ rk[1]; PUTU32(pt + 4, s1); s2 = (Td4[(t2 >> 24) ] << 24) ^ (Td4[(t1 >> 16) & 0xff] << 16) ^ (Td4[(t0 >> 8) & 0xff] << 8) ^ (Td4[(t3 ) & 0xff]) ^ rk[2]; PUTU32(pt + 8, s2); s3 = (Td4[(t3 >> 24) ] << 24) ^ (Td4[(t2 >> 16) & 0xff] << 16) ^ (Td4[(t1 >> 8) & 0xff] << 8) ^ (Td4[(t0 ) & 0xff]) ^ rk[3]; PUTU32(pt + 12, s3); } /* setup key context for encryption only */ int rijndael_set_key_enc_only(rijndael_ctx *ctx, const u_char *key, int bits) { int rounds; rounds = rijndaelKeySetupEnc(ctx->ek, key, bits); if (rounds == 0) return -1; ctx->Nr = rounds; ctx->enc_only = 1; return 0; } /* setup key context for both encryption and decryption */ int rijndael_set_key(rijndael_ctx *ctx, const u_char *key, int bits) { int rounds; rounds = rijndaelKeySetupEnc(ctx->ek, key, bits); if (rounds == 0) return -1; if (rijndaelKeySetupDec(ctx->dk, key, bits) != rounds) return -1; ctx->Nr = rounds; ctx->enc_only = 0; return 0; } void rijndael_decrypt(rijndael_ctx *ctx, const u_char *src, u_char *dst) { rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst); } void rijndael_encrypt(rijndael_ctx *ctx, const u_char *src, u_char *dst) { rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst); } ================================================ FILE: itl80211/openbsd/crypto/rijndael.h ================================================ /* $OpenBSD: rijndael.h,v 1.13 2008/06/09 07:49:45 djm Exp $ */ /** * rijndael-alg-fst.h * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __RIJNDAEL_H #define __RIJNDAEL_H #define AES_MAXKEYBITS (256) #define AES_MAXKEYBYTES (AES_MAXKEYBITS/8) /* for 256-bit keys, fewer for less */ #define AES_MAXROUNDS 14 typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; /* The structure for key information */ typedef struct { int enc_only; /* context contains only encrypt schedule */ int Nr; /* key-length-dependent number of rounds */ u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */ u32 dk[4*(AES_MAXROUNDS + 1)]; /* decrypt key schedule */ } rijndael_ctx; int rijndael_set_key(rijndael_ctx *, const u_char *, int); int rijndael_set_key_enc_only(rijndael_ctx *, const u_char *, int); void rijndael_decrypt(rijndael_ctx *, const u_char *, u_char *); void rijndael_encrypt(rijndael_ctx *, const u_char *, u_char *); int rijndaelKeySetupEnc(unsigned int [], const unsigned char [], int); int rijndaelKeySetupDec(unsigned int [], const unsigned char [], int); void rijndaelEncrypt(const unsigned int [], int, const unsigned char [], unsigned char []); #endif /* __RIJNDAEL_H */ ================================================ FILE: itl80211/openbsd/crypto/rmd160.c ================================================ /* $OpenBSD: rmd160.c,v 1.5 2011/01/11 15:42:05 deraadt Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Preneel, Bosselaers, Dobbertin, "The Cryptographic Hash Function RIPEMD-160", * RSA Laboratories, CryptoBytes, Volume 3, Number 2, Autumn 1997, * ftp://ftp.rsasecurity.com/pub/cryptobytes/crypto3n2.pdf */ #include #include #include #include #define PUT_64BIT_LE(cp, value) do { \ (cp)[7] = (value) >> 56; \ (cp)[6] = (value) >> 48; \ (cp)[5] = (value) >> 40; \ (cp)[4] = (value) >> 32; \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) #define PUT_32BIT_LE(cp, value) do { \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) #define H0 0x67452301U #define H1 0xEFCDAB89U #define H2 0x98BADCFEU #define H3 0x10325476U #define H4 0xC3D2E1F0U #define K0 0x00000000U #define K1 0x5A827999U #define K2 0x6ED9EBA1U #define K3 0x8F1BBCDCU #define K4 0xA953FD4EU #define KK0 0x50A28BE6U #define KK1 0x5C4DD124U #define KK2 0x6D703EF3U #define KK3 0x7A6D76E9U #define KK4 0x00000000U /* rotate x left n bits. */ #define ROL(n, x) (((x) << (n)) | ((x) >> (32-(n)))) #define F0(x, y, z) ((x) ^ (y) ^ (z)) #define F1(x, y, z) (((x) & (y)) | ((~x) & (z))) #define F2(x, y, z) (((x) | (~y)) ^ (z)) #define F3(x, y, z) (((x) & (z)) | ((y) & (~z))) #define F4(x, y, z) ((x) ^ ((y) | (~z))) #define R(a, b, c, d, e, Fj, Kj, sj, rj) \ do { \ a = ROL(sj, a + Fj(b,c,d) + X(rj) + Kj) + e; \ c = ROL(10, c); \ } while(0) #define X(i) x[i] static u_char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; void RMD160Init(RMD160_CTX *ctx) { ctx->count = 0; ctx->state[0] = H0; ctx->state[1] = H1; ctx->state[2] = H2; ctx->state[3] = H3; ctx->state[4] = H4; } void RMD160Update(RMD160_CTX *ctx, const u_char *input, u_int32_t len) { u_int32_t have, off, need; have = (ctx->count/8) % 64; need = 64 - have; ctx->count += 8 * len; off = 0; if (len >= need) { if (have) { memcpy(ctx->buffer + have, input, need); RMD160Transform(ctx->state, ctx->buffer); off = need; have = 0; } /* now the buffer is empty */ while (off + 64 <= len) { RMD160Transform(ctx->state, input+off); off += 64; } } if (off < len) memcpy(ctx->buffer + have, input+off, len-off); } void RMD160Final(u_char digest[20], RMD160_CTX *ctx) { int i; u_char size[8]; u_int32_t padlen; PUT_64BIT_LE(size, ctx->count); /* * pad to 64 byte blocks, at least one byte from PADDING plus 8 bytes * for the size */ padlen = 64 - ((ctx->count/8) % 64); if (padlen < 1 + 8) padlen += 64; RMD160Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ RMD160Update(ctx, size, 8); if (digest != NULL) for (i = 0; i < 5; i++) PUT_32BIT_LE(digest + i*4, ctx->state[i]); memset(ctx, 0, sizeof (*ctx)); } void RMD160Transform(u_int32_t state[5], const u_char block[64]) { u_int32_t a, b, c, d, e, aa, bb, cc, dd, ee, t, x[16]; #if BYTE_ORDER == LITTLE_ENDIAN memcpy(x, block, 64); #else int i; for (i = 0; i < 16; i++) x[i] = (u_int32_t)( (u_int32_t)(block[i*4 + 0]) | (u_int32_t)(block[i*4 + 1]) << 8 | (u_int32_t)(block[i*4 + 2]) << 16 | (u_int32_t)(block[i*4 + 3]) << 24); #endif a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* Round 1 */ R(a, b, c, d, e, F0, K0, 11, 0); R(e, a, b, c, d, F0, K0, 14, 1); R(d, e, a, b, c, F0, K0, 15, 2); R(c, d, e, a, b, F0, K0, 12, 3); R(b, c, d, e, a, F0, K0, 5, 4); R(a, b, c, d, e, F0, K0, 8, 5); R(e, a, b, c, d, F0, K0, 7, 6); R(d, e, a, b, c, F0, K0, 9, 7); R(c, d, e, a, b, F0, K0, 11, 8); R(b, c, d, e, a, F0, K0, 13, 9); R(a, b, c, d, e, F0, K0, 14, 10); R(e, a, b, c, d, F0, K0, 15, 11); R(d, e, a, b, c, F0, K0, 6, 12); R(c, d, e, a, b, F0, K0, 7, 13); R(b, c, d, e, a, F0, K0, 9, 14); R(a, b, c, d, e, F0, K0, 8, 15); /* #15 */ /* Round 2 */ R(e, a, b, c, d, F1, K1, 7, 7); R(d, e, a, b, c, F1, K1, 6, 4); R(c, d, e, a, b, F1, K1, 8, 13); R(b, c, d, e, a, F1, K1, 13, 1); R(a, b, c, d, e, F1, K1, 11, 10); R(e, a, b, c, d, F1, K1, 9, 6); R(d, e, a, b, c, F1, K1, 7, 15); R(c, d, e, a, b, F1, K1, 15, 3); R(b, c, d, e, a, F1, K1, 7, 12); R(a, b, c, d, e, F1, K1, 12, 0); R(e, a, b, c, d, F1, K1, 15, 9); R(d, e, a, b, c, F1, K1, 9, 5); R(c, d, e, a, b, F1, K1, 11, 2); R(b, c, d, e, a, F1, K1, 7, 14); R(a, b, c, d, e, F1, K1, 13, 11); R(e, a, b, c, d, F1, K1, 12, 8); /* #31 */ /* Round 3 */ R(d, e, a, b, c, F2, K2, 11, 3); R(c, d, e, a, b, F2, K2, 13, 10); R(b, c, d, e, a, F2, K2, 6, 14); R(a, b, c, d, e, F2, K2, 7, 4); R(e, a, b, c, d, F2, K2, 14, 9); R(d, e, a, b, c, F2, K2, 9, 15); R(c, d, e, a, b, F2, K2, 13, 8); R(b, c, d, e, a, F2, K2, 15, 1); R(a, b, c, d, e, F2, K2, 14, 2); R(e, a, b, c, d, F2, K2, 8, 7); R(d, e, a, b, c, F2, K2, 13, 0); R(c, d, e, a, b, F2, K2, 6, 6); R(b, c, d, e, a, F2, K2, 5, 13); R(a, b, c, d, e, F2, K2, 12, 11); R(e, a, b, c, d, F2, K2, 7, 5); R(d, e, a, b, c, F2, K2, 5, 12); /* #47 */ /* Round 4 */ R(c, d, e, a, b, F3, K3, 11, 1); R(b, c, d, e, a, F3, K3, 12, 9); R(a, b, c, d, e, F3, K3, 14, 11); R(e, a, b, c, d, F3, K3, 15, 10); R(d, e, a, b, c, F3, K3, 14, 0); R(c, d, e, a, b, F3, K3, 15, 8); R(b, c, d, e, a, F3, K3, 9, 12); R(a, b, c, d, e, F3, K3, 8, 4); R(e, a, b, c, d, F3, K3, 9, 13); R(d, e, a, b, c, F3, K3, 14, 3); R(c, d, e, a, b, F3, K3, 5, 7); R(b, c, d, e, a, F3, K3, 6, 15); R(a, b, c, d, e, F3, K3, 8, 14); R(e, a, b, c, d, F3, K3, 6, 5); R(d, e, a, b, c, F3, K3, 5, 6); R(c, d, e, a, b, F3, K3, 12, 2); /* #63 */ /* Round 5 */ R(b, c, d, e, a, F4, K4, 9, 4); R(a, b, c, d, e, F4, K4, 15, 0); R(e, a, b, c, d, F4, K4, 5, 5); R(d, e, a, b, c, F4, K4, 11, 9); R(c, d, e, a, b, F4, K4, 6, 7); R(b, c, d, e, a, F4, K4, 8, 12); R(a, b, c, d, e, F4, K4, 13, 2); R(e, a, b, c, d, F4, K4, 12, 10); R(d, e, a, b, c, F4, K4, 5, 14); R(c, d, e, a, b, F4, K4, 12, 1); R(b, c, d, e, a, F4, K4, 13, 3); R(a, b, c, d, e, F4, K4, 14, 8); R(e, a, b, c, d, F4, K4, 11, 11); R(d, e, a, b, c, F4, K4, 8, 6); R(c, d, e, a, b, F4, K4, 5, 15); R(b, c, d, e, a, F4, K4, 6, 13); /* #79 */ aa = a ; bb = b; cc = c; dd = d; ee = e; a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* Parallel round 1 */ R(a, b, c, d, e, F4, KK0, 8, 5); R(e, a, b, c, d, F4, KK0, 9, 14); R(d, e, a, b, c, F4, KK0, 9, 7); R(c, d, e, a, b, F4, KK0, 11, 0); R(b, c, d, e, a, F4, KK0, 13, 9); R(a, b, c, d, e, F4, KK0, 15, 2); R(e, a, b, c, d, F4, KK0, 15, 11); R(d, e, a, b, c, F4, KK0, 5, 4); R(c, d, e, a, b, F4, KK0, 7, 13); R(b, c, d, e, a, F4, KK0, 7, 6); R(a, b, c, d, e, F4, KK0, 8, 15); R(e, a, b, c, d, F4, KK0, 11, 8); R(d, e, a, b, c, F4, KK0, 14, 1); R(c, d, e, a, b, F4, KK0, 14, 10); R(b, c, d, e, a, F4, KK0, 12, 3); R(a, b, c, d, e, F4, KK0, 6, 12); /* #15 */ /* Parallel round 2 */ R(e, a, b, c, d, F3, KK1, 9, 6); R(d, e, a, b, c, F3, KK1, 13, 11); R(c, d, e, a, b, F3, KK1, 15, 3); R(b, c, d, e, a, F3, KK1, 7, 7); R(a, b, c, d, e, F3, KK1, 12, 0); R(e, a, b, c, d, F3, KK1, 8, 13); R(d, e, a, b, c, F3, KK1, 9, 5); R(c, d, e, a, b, F3, KK1, 11, 10); R(b, c, d, e, a, F3, KK1, 7, 14); R(a, b, c, d, e, F3, KK1, 7, 15); R(e, a, b, c, d, F3, KK1, 12, 8); R(d, e, a, b, c, F3, KK1, 7, 12); R(c, d, e, a, b, F3, KK1, 6, 4); R(b, c, d, e, a, F3, KK1, 15, 9); R(a, b, c, d, e, F3, KK1, 13, 1); R(e, a, b, c, d, F3, KK1, 11, 2); /* #31 */ /* Parallel round 3 */ R(d, e, a, b, c, F2, KK2, 9, 15); R(c, d, e, a, b, F2, KK2, 7, 5); R(b, c, d, e, a, F2, KK2, 15, 1); R(a, b, c, d, e, F2, KK2, 11, 3); R(e, a, b, c, d, F2, KK2, 8, 7); R(d, e, a, b, c, F2, KK2, 6, 14); R(c, d, e, a, b, F2, KK2, 6, 6); R(b, c, d, e, a, F2, KK2, 14, 9); R(a, b, c, d, e, F2, KK2, 12, 11); R(e, a, b, c, d, F2, KK2, 13, 8); R(d, e, a, b, c, F2, KK2, 5, 12); R(c, d, e, a, b, F2, KK2, 14, 2); R(b, c, d, e, a, F2, KK2, 13, 10); R(a, b, c, d, e, F2, KK2, 13, 0); R(e, a, b, c, d, F2, KK2, 7, 4); R(d, e, a, b, c, F2, KK2, 5, 13); /* #47 */ /* Parallel round 4 */ R(c, d, e, a, b, F1, KK3, 15, 8); R(b, c, d, e, a, F1, KK3, 5, 6); R(a, b, c, d, e, F1, KK3, 8, 4); R(e, a, b, c, d, F1, KK3, 11, 1); R(d, e, a, b, c, F1, KK3, 14, 3); R(c, d, e, a, b, F1, KK3, 14, 11); R(b, c, d, e, a, F1, KK3, 6, 15); R(a, b, c, d, e, F1, KK3, 14, 0); R(e, a, b, c, d, F1, KK3, 6, 5); R(d, e, a, b, c, F1, KK3, 9, 12); R(c, d, e, a, b, F1, KK3, 12, 2); R(b, c, d, e, a, F1, KK3, 9, 13); R(a, b, c, d, e, F1, KK3, 12, 9); R(e, a, b, c, d, F1, KK3, 5, 7); R(d, e, a, b, c, F1, KK3, 15, 10); R(c, d, e, a, b, F1, KK3, 8, 14); /* #63 */ /* Parallel round 5 */ R(b, c, d, e, a, F0, KK4, 8, 12); R(a, b, c, d, e, F0, KK4, 5, 15); R(e, a, b, c, d, F0, KK4, 12, 10); R(d, e, a, b, c, F0, KK4, 9, 4); R(c, d, e, a, b, F0, KK4, 12, 1); R(b, c, d, e, a, F0, KK4, 5, 5); R(a, b, c, d, e, F0, KK4, 14, 8); R(e, a, b, c, d, F0, KK4, 6, 7); R(d, e, a, b, c, F0, KK4, 8, 6); R(c, d, e, a, b, F0, KK4, 13, 2); R(b, c, d, e, a, F0, KK4, 6, 13); R(a, b, c, d, e, F0, KK4, 5, 14); R(e, a, b, c, d, F0, KK4, 15, 0); R(d, e, a, b, c, F0, KK4, 13, 3); R(c, d, e, a, b, F0, KK4, 11, 9); R(b, c, d, e, a, F0, KK4, 11, 11); /* #79 */ t = state[1] + cc + d; state[1] = state[2] + dd + e; state[2] = state[3] + ee + a; state[3] = state[4] + aa + b; state[4] = state[0] + bb + c; state[0] = t; } ================================================ FILE: itl80211/openbsd/crypto/rmd160.h ================================================ /* $OpenBSD: rmd160.h,v 1.5 2009/07/05 19:33:46 millert Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _RMD160_H #define _RMD160_H #define RMD160_BLOCK_LENGTH 64 #define RMD160_DIGEST_LENGTH 20 /* RMD160 context. */ typedef struct RMD160Context { u_int32_t state[5]; /* state */ u_int64_t count; /* number of bits, mod 2^64 */ u_char buffer[RMD160_BLOCK_LENGTH]; /* input buffer */ } RMD160_CTX; //__BEGIN_DECLS void RMD160Init(RMD160_CTX *); void RMD160Transform(u_int32_t [5], const u_char [RMD160_BLOCK_LENGTH]) __attribute__((__bounded__(__minbytes__,1,5))) __attribute__((__bounded__(__minbytes__,2,RMD160_BLOCK_LENGTH))); void RMD160Update(RMD160_CTX *, const u_char *, u_int32_t) __attribute__((__bounded__(__string__,2,3))); void RMD160Final(u_char [RMD160_DIGEST_LENGTH], RMD160_CTX *) __attribute__((__bounded__(__minbytes__,1,RMD160_DIGEST_LENGTH))); //__END_DECLS #endif /* _RMD160_H */ ================================================ FILE: itl80211/openbsd/crypto/set_key.c ================================================ /* $OpenBSD: set_key.c,v 1.4 2015/12/10 21:00:51 naddy Exp $ */ /* lib/des/set_key.c */ /* Copyright (C) 1995 Eric Young (eay@mincom.oz.au) * All rights reserved. * * This file is part of an SSL implementation written * by Eric Young (eay@mincom.oz.au). * The implementation was written so as to conform with Netscapes SSL * specification. This library and applications are * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE * as long as the following conditions are aheared to. * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. If this code is used in a product, * Eric Young should be given attribution as the author of the parts used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Eric Young (eay@mincom.oz.au) * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* set_key.c v 1.4 eay 24/9/91 * 1.4 Speed up by 400% :-) * 1.3 added register declarations. * 1.2 unrolled make_key_sched a bit more * 1.1 added norm_expand_bits * 1.0 First working version */ #include "des_locl.h" #include "podd.h" #include "sk.h" static int check_parity(des_cblock (*key)); int des_check_key=0; static int check_parity(des_cblock (*key)) { int i; for (i = 0; i < DES_KEY_SZ; i++) { if ((*key)[i] != odd_parity[(*key)[i]]) return(0); } return (1); } /* Weak and semi week keys as take from * %A D.W. Davies * %A W.L. Price * %T Security for Computer Networks * %I John Wiley & Sons * %D 1984 * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference * (and actual cblock values). */ #define NUM_WEAK_KEY 16 static des_cblock weak_keys[NUM_WEAK_KEY]={ /* weak keys */ {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}, {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE}, {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}, {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0}, /* semi-weak keys */ {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE}, {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01}, {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1}, {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E}, {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1}, {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01}, {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE}, {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E}, {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E}, {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01}, {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE}, {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}}; int des_is_weak_key(des_cblock (*key)) { int i; for (i = 0; i < NUM_WEAK_KEY; i++) { /* Added == 0 to comparision, I obviously don't run * this section very often :-(, thanks to * engineering@MorningStar.Com for the fix * eay 93/06/29 */ if (bcmp(weak_keys[i], key, sizeof(des_cblock)) == 0) return (1); } return (0); } /* NOW DEFINED IN des_local.h * See ecb_encrypt.c for a pseudo description of these macros. * #define PERM_OP(a, b, t, n, m) ((t) = ((((a) >> (n))^(b)) & (m)),\ * (b)^=(t),\ * (a) = ((a)^((t) << (n)))) */ #define HPERM_OP(a, t, n, m) ((t) = ((((a) << (16 - (n)))^(a)) & (m)),\ (a) = (a)^(t)^(t >> (16 - (n)))) static int shifts2[16]={0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0}; /* return 0 if key parity is odd (correct), * return -1 if key parity error, * return -2 if illegal weak key. */ int des_set_key(des_cblock (*key), des_key_schedule schedule) { register u_int32_t c, d, t, s; register unsigned char *in; register u_int32_t *k; register int i; if (des_check_key) { if (!check_parity(key)) return(-1); if (des_is_weak_key(key)) return(-2); } k = (u_int32_t *) schedule; in = (unsigned char *) key; c2l(in, c); c2l(in, d); /* do PC1 in 60 simple operations */ /* PERM_OP(d, c, t, 4, 0x0f0f0f0fL); HPERM_OP(c, t, -2, 0xcccc0000L); HPERM_OP(c, t, -1, 0xaaaa0000L); HPERM_OP(c, t, 8, 0x00ff0000L); HPERM_OP(c, t, -1, 0xaaaa0000L); HPERM_OP(d, t, -8, 0xff000000L); HPERM_OP(d, t, 8, 0x00ff0000L); HPERM_OP(d, t, 2, 0x33330000L); d = ((d & 0x00aa00aaL) << 7L) | ((d & 0x55005500L) >> 7L) | (d & 0xaa55aa55L); d = (d >> 8) | ((c & 0xf0000000L) >> 4); c &= 0x0fffffffL; */ /* I now do it in 47 simple operations :-) * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov) * for the inspiration. :-) */ PERM_OP (d, c, t, 4, 0x0f0f0f0fL); HPERM_OP(c, t, -2, 0xcccc0000L); HPERM_OP(d, t, -2, 0xcccc0000L); PERM_OP (d, c, t, 1, 0x55555555L); PERM_OP (c, d, t, 8, 0x00ff00ffL); PERM_OP (d, c, t, 1, 0x55555555L); d = (((d & 0x000000ffL) << 16L) | (d & 0x0000ff00L) | ((d & 0x00ff0000L) >> 16L) | ((c & 0xf0000000L) >> 4L)); c &= 0x0fffffffL; for (i = 0; i < ITERATIONS; i++) { if (shifts2[i]) { c = ((c >> 2L) | (c << 26L)); d = ((d >> 2L) | (d << 26L)); } else { c = ((c >> 1L) | (c << 27L)); d = ((d >> 1L) | (d << 27L)); } c &= 0x0fffffffL; d &= 0x0fffffffL; /* could be a few less shifts but I am to lazy at this * point in time to investigate */ s = des_skb[0][ (c ) & 0x3f ]| des_skb[1][((c >> 6) & 0x03) | ((c >> 7L) & 0x3c)]| des_skb[2][((c >> 13) & 0x0f) | ((c >> 14L) & 0x30)]| des_skb[3][((c >> 20) & 0x01) | ((c >> 21L) & 0x06) | ((c >> 22L) & 0x38)]; t = des_skb[4][ (d ) & 0x3f ]| des_skb[5][((d >> 7L) & 0x03) | ((d >> 8L) & 0x3c)]| des_skb[6][ (d >> 15L) & 0x3f ]| des_skb[7][((d >> 21L) & 0x0f) | ((d >> 22L) & 0x30)]; /* table contained 0213 4657 */ *(k++) = ((t << 16L) | (s & 0x0000ffffL)) & 0xffffffffL; s = ((s >> 16L) | (t & 0xffff0000L)); s = (s << 4L) | (s >> 28L); *(k++) = s & 0xffffffffL; } return (0); } ================================================ FILE: itl80211/openbsd/crypto/sha1-pbkdf2.c ================================================ /* * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i * Copyright (c) 2003-2005, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "sha1.h" #include "hmac.h" static int openssl_hmac_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac, unsigned int mdlen) { HMAC_SHA1_CTX ctx; size_t i; u_int8_t digest[SHA1_DIGEST_LENGTH]; HMAC_SHA1_Init(&ctx, key, key_len); for (i = 0; i < num_elem; i++) HMAC_SHA1_Update(&ctx, addr[i], len[i]); HMAC_SHA1_Final(digest, &ctx); memcpy(mac, digest, sizeof(digest)); return 0; } int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return openssl_hmac_vector(key, key_len, num_elem, addr, len, mac, 20); } int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); } static int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid, size_t ssid_len, int iterations, unsigned int count, u8 *digest) { unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; int i, j; unsigned char count_buf[4]; const u8 *addr[2]; size_t len[2]; size_t passphrase_len = strlen(passphrase); addr[0] = ssid; len[0] = ssid_len; addr[1] = count_buf; len[1] = 4; /* F(P, S, c, i) = U1 xor U2 xor ... Uc * U1 = PRF(P, S || i) * U2 = PRF(P, U1) * Uc = PRF(P, Uc-1) */ count_buf[0] = (count >> 24) & 0xff; count_buf[1] = (count >> 16) & 0xff; count_buf[2] = (count >> 8) & 0xff; count_buf[3] = count & 0xff; if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, tmp)) return -1; memcpy(digest, tmp, SHA1_MAC_LEN); for (i = 1; i < iterations; i++) { if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp, SHA1_MAC_LEN, tmp2)) return -1; memcpy(tmp, tmp2, SHA1_MAC_LEN); for (j = 0; j < SHA1_MAC_LEN; j++) digest[j] ^= tmp2[j]; } return 0; } /** * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i * @passphrase: ASCII passphrase * @ssid: SSID * @ssid_len: SSID length in bytes * @iterations: Number of iterations to run * @buf: Buffer for the generated key * @buflen: Length of the buffer in bytes * Returns: 0 on success, -1 of failure * * This function is used to derive PSK for WPA-PSK. For this protocol, * iterations is set to 4096 and buflen to 32. This function is described in * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. */ int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, int iterations, u8 *buf, size_t buflen) { unsigned int count = 0; unsigned char *pos = buf; size_t left = buflen, plen; unsigned char digest[SHA1_MAC_LEN]; while (left > 0) { count++; if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, count, digest)) return -1; plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; memcpy(pos, digest, plen); pos += plen; left -= plen; } return 0; } ================================================ FILE: itl80211/openbsd/crypto/sha1.c ================================================ /* $OpenBSD: sha1.c,v 1.11 2014/12/28 10:04:35 tedu Exp $ */ /* * SHA-1 in C * By Steve Reid * 100% Public Domain * * Test Vectors (from FIPS PUB 180-1) * "abc" * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 * A million repetitions of "a" * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ /* #define SHA1HANDSOFF * Copies data before messing with it. */ #define SHA1HANDSOFF #include #include #include #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ #if BYTE_ORDER == LITTLE_ENDIAN #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ |(rol(block->l[i],8)&0x00FF00FF)) #else #define blk0(i) block->l[i] #endif #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ ^block->l[(i+2)&15]^block->l[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); /* Hash a single 512-bit block. This is the core of the algorithm. */ void SHA1Transform(u_int32_t state[5], const unsigned char buffer[SHA1_BLOCK_LENGTH]) { u_int32_t a, b, c, d, e; typedef union { unsigned char c[64]; unsigned int l[16]; } CHAR64LONG16; CHAR64LONG16* block; #ifdef SHA1HANDSOFF unsigned char workspace[SHA1_BLOCK_LENGTH]; block = (CHAR64LONG16 *)workspace; memcpy(block, buffer, SHA1_BLOCK_LENGTH); #else block = (CHAR64LONG16 *)buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* SHA1Init - Initialize new context */ void SHA1Init(SHA1_CTX *context) { /* SHA1 initialization constants */ context->count = 0; context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; } /* Run your data through this. */ void SHA1Update(SHA1_CTX *context, const void *dataptr, unsigned int len) { const uint8_t *data = (const uint8_t *)dataptr; unsigned int i; unsigned int j; j = (u_int32_t)((context->count >> 3) & 63); context->count += (len << 3); if ((j + len) > 63) { memcpy(&context->buffer[j], data, (i = 64 - j)); SHA1Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { SHA1Transform(context->state, &data[i]); } j = 0; } else i = 0; memcpy(&context->buffer[j], &data[i], len - i); } /* Add padding and return the message digest. */ void SHA1Final(unsigned char digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context) { unsigned int i; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count >> ((7 - (i & 7)) * 8)) & 255); /* Endian independent */ } SHA1Update(context, "\200", 1); while ((context->count & 504) != 448) { SHA1Update(context, "\0", 1); } SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ for (i = 0; i < SHA1_DIGEST_LENGTH; i++) { digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); } memset(&finalcount, 0, sizeof(finalcount)); memset(context, 0, sizeof(*context)); } ================================================ FILE: itl80211/openbsd/crypto/sha1.h ================================================ /* $OpenBSD: sha1.h,v 1.6 2014/11/16 17:39:09 tedu Exp $ */ /* * SHA-1 in C * By Steve Reid * 100% Public Domain */ #ifndef _SHA1_H_ #define _SHA1_H_ #include "types.h" #define SHA1_MAC_LEN 20 #define SHA1_BLOCK_LENGTH 64 #define SHA1_DIGEST_LENGTH 20 typedef struct { u_int32_t state[5]; u_int64_t count; unsigned char buffer[SHA1_BLOCK_LENGTH]; } SHA1_CTX; void SHA1Init(SHA1_CTX * context); void SHA1Transform(u_int32_t state[5], const unsigned char buffer[SHA1_BLOCK_LENGTH]); void SHA1Update(SHA1_CTX *context, const void *data, unsigned int len); void SHA1Final(unsigned char digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context); int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac); int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, int iterations, u8 *buf, size_t buflen); #endif /* _SHA1_H_ */ ================================================ FILE: itl80211/openbsd/crypto/sha2.c ================================================ /* $OpenBSD: sha2.c,v 1.18 2015/03/14 03:38:46 jsg Exp $ */ /* * FILE: sha2.c * AUTHOR: Aaron D. Gifford * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ */ #include #include #include #include /* * UNROLLED TRANSFORM LOOP NOTE: * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform * loop version for the hash transform rounds (defined using macros * later in this file). Either define on the command line, for example: * * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c * * or define below: * * #define SHA2_UNROLL_TRANSFORM * */ #ifndef SMALL_KERNEL #if defined(__amd64__) || defined(__i386__) #define SHA2_UNROLL_TRANSFORM #endif #endif /*** SHA-256/384/512 Machine Architecture Definitions *****************/ /* * BYTE_ORDER NOTE: * * Please make sure that your system defines BYTE_ORDER. If your * architecture is little-endian, make sure it also defines * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are * equivilent. * * If your system does not define the above, then you can do so by * hand like this: * * #define LITTLE_ENDIAN 1234 * #define BIG_ENDIAN 4321 * * And for little-endian machines, add: * * #define BYTE_ORDER LITTLE_ENDIAN * * Or for big-endian machines: * * #define BYTE_ORDER BIG_ENDIAN * * The FreeBSD machine this was written on defines BYTE_ORDER * appropriately by including (which in turn includes * where the appropriate definitions are actually * made). */ #if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) #error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN #endif /*** SHA-256/384/512 Various Length Definitions ***********************/ /* NOTE: Most of these are in sha2.h */ #define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) #define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) #define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) /* * Macro for incrementally adding the unsigned 64-bit integer n to the * unsigned 128-bit integer (represented using a two-element array of * 64-bit words): */ #define ADDINC128(w,n) { \ (w)[0] += (u_int64_t)(n); \ if ((w)[0] < (n)) { \ (w)[1]++; \ } \ } /*** THE SIX LOGICAL FUNCTIONS ****************************************/ /* * Bit shifting and rotation (used by the six SHA-XYZ logical functions: * * NOTE: The naming of R and S appears backwards here (R is a SHIFT and * S is a ROTATION) because the SHA-256/384/512 description document * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this * same "backwards" definition. */ /* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ #define R(b,x) ((x) >> (b)) /* 32-bit Rotate-right (used in SHA-256): */ #define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) /* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ #define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) /* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) /* Four of six logical functions used in SHA-256: */ #define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) #define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) #define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) #define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) /* Four of six logical functions used in SHA-384 and SHA-512: */ #define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) #define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) #define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) #define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) /*** INTERNAL FUNCTION PROTOTYPES *************************************/ /* NOTE: These should not be accessed directly from outside this * library -- they are intended for private internal visibility/use * only. */ void SHA512Last(SHA2_CTX *); void SHA256Transform(u_int32_t *, const u_int8_t *); void SHA512Transform(u_int64_t *, const u_int8_t *); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-256: */ const static u_int32_t K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Initial hash value H for SHA-256: */ const static u_int32_t sha256_initial_hash_value[8] = { 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL }; /* Hash constant words K for SHA-384 and SHA-512: */ const static u_int64_t K512[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; /* Initial hash value H for SHA-384 */ const static u_int64_t sha384_initial_hash_value[8] = { 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL }; /* Initial hash value H for SHA-512 */ const static u_int64_t sha512_initial_hash_value[8] = { 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL }; /*** SHA-256: *********************************************************/ void SHA256Init(SHA2_CTX *context) { memcpy(context->state.st32, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); memset(context->buffer, 0, SHA256_BLOCK_LENGTH); context->bitcount[0] = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-256 round macros: */ #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) do { \ W256[j] = (u_int32_t)data[3] | ((u_int32_t)data[2] << 8) | \ ((u_int32_t)data[1] << 16) | ((u_int32_t)data[0] << 24); \ data += 4; \ T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + W256[j]; \ (d) += T1; \ (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) #define ROUND256(a,b,c,d,e,f,g,h) do { \ s0 = W256[(j+1)&0x0f]; \ s0 = sigma0_256(s0); \ s1 = W256[(j+14)&0x0f]; \ s1 = sigma1_256(s1); \ T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + \ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) void SHA256Transform(u_int32_t *state, const u_int8_t *data) { u_int32_t a, b, c, d, e, f, g, h, s0, s1; u_int32_t T1, W256[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { /* Rounds 0 to 15 (unrolled): */ ROUND256_0_TO_15(a,b,c,d,e,f,g,h); ROUND256_0_TO_15(h,a,b,c,d,e,f,g); ROUND256_0_TO_15(g,h,a,b,c,d,e,f); ROUND256_0_TO_15(f,g,h,a,b,c,d,e); ROUND256_0_TO_15(e,f,g,h,a,b,c,d); ROUND256_0_TO_15(d,e,f,g,h,a,b,c); ROUND256_0_TO_15(c,d,e,f,g,h,a,b); ROUND256_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds to 64: */ do { ROUND256(a,b,c,d,e,f,g,h); ROUND256(h,a,b,c,d,e,f,g); ROUND256(g,h,a,b,c,d,e,f); ROUND256(f,g,h,a,b,c,d,e); ROUND256(e,f,g,h,a,b,c,d); ROUND256(d,e,f,g,h,a,b,c); ROUND256(c,d,e,f,g,h,a,b); ROUND256(b,c,d,e,f,g,h,a); } while (j < 64); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA256Transform(u_int32_t *state, const u_int8_t *data) { u_int32_t a, b, c, d, e, f, g, h, s0, s1; u_int32_t T1, T2, W256[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { W256[j] = (u_int32_t)data[3] | ((u_int32_t)data[2] << 8) | ((u_int32_t)data[1] << 16) | ((u_int32_t)data[0] << 24); data += 4; /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W256[(j+1)&0x0f]; s0 = sigma0_256(s0); s1 = W256[(j+14)&0x0f]; s1 = sigma1_256(s1); /* Apply the SHA-256 compression function to update a..h */ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); T2 = Sigma0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 64); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA256Update(SHA2_CTX *context, const void *dataptr, size_t len) { const uint8_t *data = (const uint8_t *)dataptr; size_t freespace, usedspace; /* Calling with no data is valid (we do nothing) */ if (len == 0) return; usedspace = (context->bitcount[0] >> 3) % SHA256_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA256_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ memcpy(&context->buffer[usedspace], data, freespace); context->bitcount[0] += freespace << 3; len -= freespace; data += freespace; SHA256Transform(context->state.st32, context->buffer); } else { /* The buffer is not yet full */ memcpy(&context->buffer[usedspace], data, len); context->bitcount[0] += len << 3; /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA256_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA256Transform(context->state.st32, data); context->bitcount[0] += SHA256_BLOCK_LENGTH << 3; len -= SHA256_BLOCK_LENGTH; data += SHA256_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ memcpy(context->buffer, data, len); context->bitcount[0] += len << 3; } /* Clean up: */ usedspace = freespace = 0; } void SHA256Final(u_int8_t digest[], SHA2_CTX *context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA256_BLOCK_LENGTH; #if BYTE_ORDER == LITTLE_ENDIAN /* Convert FROM host byte order */ context->bitcount[0] = _OSSwapInt64(context->bitcount[0]); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ memset(&context->buffer[usedspace], 0, SHA256_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA256_BLOCK_LENGTH) { memset(&context->buffer[usedspace], 0, SHA256_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA256Transform(context->state.st32, context->buffer); /* And set-up for the last transform: */ memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH); } } else { /* Set-up for the last transform: */ memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Set the bit count: */ *(u_int64_t *)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount[0]; /* Final transform: */ SHA256Transform(context->state.st32, context->buffer); #if BYTE_ORDER == LITTLE_ENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { context->state.st32[j] = _OSSwapInt32(context->state.st32[j]); } } #endif memcpy(digest, context->state.st32, SHA256_DIGEST_LENGTH); /* Clean up state data: */ memset(context, 0, sizeof(*context)); usedspace = 0; } /*** SHA-512: *********************************************************/ void SHA512Init(SHA2_CTX *context) { memcpy(context->state.st64, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); memset(context->buffer, 0, SHA512_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } #ifdef SHA2_UNROLL_TRANSFORM /* Unrolled SHA-512 round macros: */ #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) do { \ W512[j] = (u_int64_t)data[7] | ((u_int64_t)data[6] << 8) | \ ((u_int64_t)data[5] << 16) | ((u_int64_t)data[4] << 24) | \ ((u_int64_t)data[3] << 32) | ((u_int64_t)data[2] << 40) | \ ((u_int64_t)data[1] << 48) | ((u_int64_t)data[0] << 56); \ data += 8; \ T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + W512[j]; \ (d) += T1; \ (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) #define ROUND512(a,b,c,d,e,f,g,h) do { \ s0 = W512[(j+1)&0x0f]; \ s0 = sigma0_512(s0); \ s1 = W512[(j+14)&0x0f]; \ s1 = sigma1_512(s1); \ T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + \ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ (d) += T1; \ (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c)); \ j++; \ } while(0) void SHA512Transform(u_int64_t *state, const u_int8_t *data) { u_int64_t a, b, c, d, e, f, g, h, s0, s1; u_int64_t T1, W512[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { ROUND512_0_TO_15(a,b,c,d,e,f,g,h); ROUND512_0_TO_15(h,a,b,c,d,e,f,g); ROUND512_0_TO_15(g,h,a,b,c,d,e,f); ROUND512_0_TO_15(f,g,h,a,b,c,d,e); ROUND512_0_TO_15(e,f,g,h,a,b,c,d); ROUND512_0_TO_15(d,e,f,g,h,a,b,c); ROUND512_0_TO_15(c,d,e,f,g,h,a,b); ROUND512_0_TO_15(b,c,d,e,f,g,h,a); } while (j < 16); /* Now for the remaining rounds up to 79: */ do { ROUND512(a,b,c,d,e,f,g,h); ROUND512(h,a,b,c,d,e,f,g); ROUND512(g,h,a,b,c,d,e,f); ROUND512(f,g,h,a,b,c,d,e); ROUND512(e,f,g,h,a,b,c,d); ROUND512(d,e,f,g,h,a,b,c); ROUND512(c,d,e,f,g,h,a,b); ROUND512(b,c,d,e,f,g,h,a); } while (j < 80); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA512Transform(u_int64_t *state, const u_int8_t *data) { u_int64_t a, b, c, d, e, f, g, h, s0, s1; u_int64_t T1, T2, W512[16]; int j; /* Initialize registers with the prev. intermediate value */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; f = state[5]; g = state[6]; h = state[7]; j = 0; do { W512[j] = (u_int64_t)data[7] | ((u_int64_t)data[6] << 8) | ((u_int64_t)data[5] << 16) | ((u_int64_t)data[4] << 24) | ((u_int64_t)data[3] << 32) | ((u_int64_t)data[2] << 40) | ((u_int64_t)data[1] << 48) | ((u_int64_t)data[0] << 56); data += 8; /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 16); do { /* Part of the message block expansion: */ s0 = W512[(j+1)&0x0f]; s0 = sigma0_512(s0); s1 = W512[(j+14)&0x0f]; s1 = sigma1_512(s1); /* Apply the SHA-512 compression function to update a..h */ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); T2 = Sigma0_512(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; j++; } while (j < 80); /* Compute the current intermediate hash value */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; state[5] += f; state[6] += g; state[7] += h; /* Clean up */ a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA512Update(SHA2_CTX *context, const void *dataptr, size_t len) { const uint8_t *data = (const uint8_t *)dataptr; size_t freespace, usedspace; /* Calling with no data is valid (we do nothing) */ if (len == 0) return; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; if (usedspace > 0) { /* Calculate how much free space is available in the buffer */ freespace = SHA512_BLOCK_LENGTH - usedspace; if (len >= freespace) { /* Fill the buffer completely and process it */ memcpy(&context->buffer[usedspace], data, freespace); ADDINC128(context->bitcount, freespace << 3); len -= freespace; data += freespace; SHA512Transform(context->state.st64, context->buffer); } else { /* The buffer is not yet full */ memcpy(&context->buffer[usedspace], data, len); ADDINC128(context->bitcount, len << 3); /* Clean up: */ usedspace = freespace = 0; return; } } while (len >= SHA512_BLOCK_LENGTH) { /* Process as many complete blocks as we can */ SHA512Transform(context->state.st64, data); ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); len -= SHA512_BLOCK_LENGTH; data += SHA512_BLOCK_LENGTH; } if (len > 0) { /* There's left-overs, so save 'em */ memcpy(context->buffer, data, len); ADDINC128(context->bitcount, len << 3); } /* Clean up: */ usedspace = freespace = 0; } void SHA512Last(SHA2_CTX *context) { unsigned int usedspace; usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; #if BYTE_ORDER == LITTLE_ENDIAN /* Convert FROM host byte order */ context->bitcount[0] = _OSSwapInt64(context->bitcount[0]); context->bitcount[1] = _OSSwapInt64(context->bitcount[1]); #endif if (usedspace > 0) { /* Begin padding with a 1 bit: */ context->buffer[usedspace++] = 0x80; if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { /* Set-up for the last transform: */ memset(&context->buffer[usedspace], 0, SHA512_SHORT_BLOCK_LENGTH - usedspace); } else { if (usedspace < SHA512_BLOCK_LENGTH) { memset(&context->buffer[usedspace], 0, SHA512_BLOCK_LENGTH - usedspace); } /* Do second-to-last transform: */ SHA512Transform(context->state.st64, context->buffer); /* And set-up for the last transform: */ memset(context->buffer, 0, SHA512_BLOCK_LENGTH - 2); } } else { /* Prepare for final transform: */ memset(context->buffer, 0, SHA512_SHORT_BLOCK_LENGTH); /* Begin padding with a 1 bit: */ *context->buffer = 0x80; } /* Store the length of input data (in bits): */ *(u_int64_t *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; *(u_int64_t *)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; /* Final transform: */ SHA512Transform(context->state.st64, context->buffer); } void SHA512Final(u_int8_t digest[], SHA2_CTX *context) { SHA512Last(context); /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 8; j++) { context->state.st64[j] = _OSSwapInt64(context->state.st64[j]); } } #endif memcpy(digest, context->state.st64, SHA512_DIGEST_LENGTH); /* Zero out state data */ memset(context, 0, sizeof(*context)); } /*** SHA-384: *********************************************************/ void SHA384Init(SHA2_CTX *context) { memcpy(context->state.st64, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); memset(context->buffer, 0, SHA384_BLOCK_LENGTH); context->bitcount[0] = context->bitcount[1] = 0; } void SHA384Update(SHA2_CTX *context, const void *data, size_t len) { SHA512Update(context, data, len); } void SHA384Final(u_int8_t digest[], SHA2_CTX *context) { SHA512Last(context); /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN { /* Convert TO host byte order */ int j; for (j = 0; j < 6; j++) { context->state.st64[j] = _OSSwapInt64(context->state.st64[j]); } } #endif memcpy(digest, context->state.st64, SHA384_DIGEST_LENGTH); /* Zero out state data */ memset(context, 0, sizeof(*context)); } ================================================ FILE: itl80211/openbsd/crypto/sha2.h ================================================ /* $OpenBSD: sha2.h,v 1.5 2014/11/16 17:39:09 tedu Exp $ */ /* * FILE: sha2.h * AUTHOR: Aaron D. Gifford * * Copyright (c) 2000-2001, Aaron D. Gifford * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ */ #ifndef _SHA2_H #define _SHA2_H /*** SHA-256/384/512 Various Length Definitions ***********************/ #define SHA256_BLOCK_LENGTH 64 #define SHA256_DIGEST_LENGTH 32 #define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) #define SHA384_BLOCK_LENGTH 128 #define SHA384_DIGEST_LENGTH 48 #define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) #define SHA512_BLOCK_LENGTH 128 #define SHA512_DIGEST_LENGTH 64 #define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) /*** SHA-256/384/512 Context Structure *******************************/ typedef struct _SHA2_CTX { union { u_int32_t st32[8]; u_int64_t st64[8]; } state; u_int64_t bitcount[2]; u_int8_t buffer[SHA512_BLOCK_LENGTH]; } SHA2_CTX; //__BEGIN_DECLS void SHA256Init(SHA2_CTX *); void SHA256Update(SHA2_CTX *, const void *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA256Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA256_DIGEST_LENGTH))); void SHA384Init(SHA2_CTX *); void SHA384Update(SHA2_CTX *, const void *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA384Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA384_DIGEST_LENGTH))); void SHA512Init(SHA2_CTX *); void SHA512Update(SHA2_CTX *, const void *, size_t) __attribute__((__bounded__(__string__,2,3))); void SHA512Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA2_CTX *) __attribute__((__bounded__(__minbytes__,1,SHA512_DIGEST_LENGTH))); //__END_DECLS #endif /* _SHA2_H */ ================================================ FILE: itl80211/openbsd/crypto/sk.h ================================================ /* $OpenBSD: sk.h,v 1.2 2002/10/27 13:24:26 miod Exp $ */ /* lib/des/sk.h */ /* Copyright (C) 1995 Eric Young (eay@mincom.oz.au) * All rights reserved. * * This file is part of an SSL implementation written * by Eric Young (eay@mincom.oz.au). * The implementation was written so as to conform with Netscapes SSL * specification. This library and applications are * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE * as long as the following conditions are aheared to. * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. If this code is used in a product, * Eric Young should be given attribution as the author of the parts used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Eric Young (eay@mincom.oz.au) * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ static const u_int32_t des_skb[8][64]={ { /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ 0x00000000L,0x00000010L,0x20000000L,0x20000010L, 0x00010000L,0x00010010L,0x20010000L,0x20010010L, 0x00000800L,0x00000810L,0x20000800L,0x20000810L, 0x00010800L,0x00010810L,0x20010800L,0x20010810L, 0x00000020L,0x00000030L,0x20000020L,0x20000030L, 0x00010020L,0x00010030L,0x20010020L,0x20010030L, 0x00000820L,0x00000830L,0x20000820L,0x20000830L, 0x00010820L,0x00010830L,0x20010820L,0x20010830L, 0x00080000L,0x00080010L,0x20080000L,0x20080010L, 0x00090000L,0x00090010L,0x20090000L,0x20090010L, 0x00080800L,0x00080810L,0x20080800L,0x20080810L, 0x00090800L,0x00090810L,0x20090800L,0x20090810L, 0x00080020L,0x00080030L,0x20080020L,0x20080030L, 0x00090020L,0x00090030L,0x20090020L,0x20090030L, 0x00080820L,0x00080830L,0x20080820L,0x20080830L, 0x00090820L,0x00090830L,0x20090820L,0x20090830L, },{ /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */ 0x00000000L,0x02000000L,0x00002000L,0x02002000L, 0x00200000L,0x02200000L,0x00202000L,0x02202000L, 0x00000004L,0x02000004L,0x00002004L,0x02002004L, 0x00200004L,0x02200004L,0x00202004L,0x02202004L, 0x00000400L,0x02000400L,0x00002400L,0x02002400L, 0x00200400L,0x02200400L,0x00202400L,0x02202400L, 0x00000404L,0x02000404L,0x00002404L,0x02002404L, 0x00200404L,0x02200404L,0x00202404L,0x02202404L, 0x10000000L,0x12000000L,0x10002000L,0x12002000L, 0x10200000L,0x12200000L,0x10202000L,0x12202000L, 0x10000004L,0x12000004L,0x10002004L,0x12002004L, 0x10200004L,0x12200004L,0x10202004L,0x12202004L, 0x10000400L,0x12000400L,0x10002400L,0x12002400L, 0x10200400L,0x12200400L,0x10202400L,0x12202400L, 0x10000404L,0x12000404L,0x10002404L,0x12002404L, 0x10200404L,0x12200404L,0x10202404L,0x12202404L, },{ /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */ 0x00000000L,0x00000001L,0x00040000L,0x00040001L, 0x01000000L,0x01000001L,0x01040000L,0x01040001L, 0x00000002L,0x00000003L,0x00040002L,0x00040003L, 0x01000002L,0x01000003L,0x01040002L,0x01040003L, 0x00000200L,0x00000201L,0x00040200L,0x00040201L, 0x01000200L,0x01000201L,0x01040200L,0x01040201L, 0x00000202L,0x00000203L,0x00040202L,0x00040203L, 0x01000202L,0x01000203L,0x01040202L,0x01040203L, 0x08000000L,0x08000001L,0x08040000L,0x08040001L, 0x09000000L,0x09000001L,0x09040000L,0x09040001L, 0x08000002L,0x08000003L,0x08040002L,0x08040003L, 0x09000002L,0x09000003L,0x09040002L,0x09040003L, 0x08000200L,0x08000201L,0x08040200L,0x08040201L, 0x09000200L,0x09000201L,0x09040200L,0x09040201L, 0x08000202L,0x08000203L,0x08040202L,0x08040203L, 0x09000202L,0x09000203L,0x09040202L,0x09040203L, },{ /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */ 0x00000000L,0x00100000L,0x00000100L,0x00100100L, 0x00000008L,0x00100008L,0x00000108L,0x00100108L, 0x00001000L,0x00101000L,0x00001100L,0x00101100L, 0x00001008L,0x00101008L,0x00001108L,0x00101108L, 0x04000000L,0x04100000L,0x04000100L,0x04100100L, 0x04000008L,0x04100008L,0x04000108L,0x04100108L, 0x04001000L,0x04101000L,0x04001100L,0x04101100L, 0x04001008L,0x04101008L,0x04001108L,0x04101108L, 0x00020000L,0x00120000L,0x00020100L,0x00120100L, 0x00020008L,0x00120008L,0x00020108L,0x00120108L, 0x00021000L,0x00121000L,0x00021100L,0x00121100L, 0x00021008L,0x00121008L,0x00021108L,0x00121108L, 0x04020000L,0x04120000L,0x04020100L,0x04120100L, 0x04020008L,0x04120008L,0x04020108L,0x04120108L, 0x04021000L,0x04121000L,0x04021100L,0x04121100L, 0x04021008L,0x04121008L,0x04021108L,0x04121108L, },{ /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ 0x00000000L,0x10000000L,0x00010000L,0x10010000L, 0x00000004L,0x10000004L,0x00010004L,0x10010004L, 0x20000000L,0x30000000L,0x20010000L,0x30010000L, 0x20000004L,0x30000004L,0x20010004L,0x30010004L, 0x00100000L,0x10100000L,0x00110000L,0x10110000L, 0x00100004L,0x10100004L,0x00110004L,0x10110004L, 0x20100000L,0x30100000L,0x20110000L,0x30110000L, 0x20100004L,0x30100004L,0x20110004L,0x30110004L, 0x00001000L,0x10001000L,0x00011000L,0x10011000L, 0x00001004L,0x10001004L,0x00011004L,0x10011004L, 0x20001000L,0x30001000L,0x20011000L,0x30011000L, 0x20001004L,0x30001004L,0x20011004L,0x30011004L, 0x00101000L,0x10101000L,0x00111000L,0x10111000L, 0x00101004L,0x10101004L,0x00111004L,0x10111004L, 0x20101000L,0x30101000L,0x20111000L,0x30111000L, 0x20101004L,0x30101004L,0x20111004L,0x30111004L, },{ /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */ 0x00000000L,0x08000000L,0x00000008L,0x08000008L, 0x00000400L,0x08000400L,0x00000408L,0x08000408L, 0x00020000L,0x08020000L,0x00020008L,0x08020008L, 0x00020400L,0x08020400L,0x00020408L,0x08020408L, 0x00000001L,0x08000001L,0x00000009L,0x08000009L, 0x00000401L,0x08000401L,0x00000409L,0x08000409L, 0x00020001L,0x08020001L,0x00020009L,0x08020009L, 0x00020401L,0x08020401L,0x00020409L,0x08020409L, 0x02000000L,0x0A000000L,0x02000008L,0x0A000008L, 0x02000400L,0x0A000400L,0x02000408L,0x0A000408L, 0x02020000L,0x0A020000L,0x02020008L,0x0A020008L, 0x02020400L,0x0A020400L,0x02020408L,0x0A020408L, 0x02000001L,0x0A000001L,0x02000009L,0x0A000009L, 0x02000401L,0x0A000401L,0x02000409L,0x0A000409L, 0x02020001L,0x0A020001L,0x02020009L,0x0A020009L, 0x02020401L,0x0A020401L,0x02020409L,0x0A020409L, },{ /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */ 0x00000000L,0x00000100L,0x00080000L,0x00080100L, 0x01000000L,0x01000100L,0x01080000L,0x01080100L, 0x00000010L,0x00000110L,0x00080010L,0x00080110L, 0x01000010L,0x01000110L,0x01080010L,0x01080110L, 0x00200000L,0x00200100L,0x00280000L,0x00280100L, 0x01200000L,0x01200100L,0x01280000L,0x01280100L, 0x00200010L,0x00200110L,0x00280010L,0x00280110L, 0x01200010L,0x01200110L,0x01280010L,0x01280110L, 0x00000200L,0x00000300L,0x00080200L,0x00080300L, 0x01000200L,0x01000300L,0x01080200L,0x01080300L, 0x00000210L,0x00000310L,0x00080210L,0x00080310L, 0x01000210L,0x01000310L,0x01080210L,0x01080310L, 0x00200200L,0x00200300L,0x00280200L,0x00280300L, 0x01200200L,0x01200300L,0x01280200L,0x01280300L, 0x00200210L,0x00200310L,0x00280210L,0x00280310L, 0x01200210L,0x01200310L,0x01280210L,0x01280310L, },{ /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */ 0x00000000L,0x04000000L,0x00040000L,0x04040000L, 0x00000002L,0x04000002L,0x00040002L,0x04040002L, 0x00002000L,0x04002000L,0x00042000L,0x04042000L, 0x00002002L,0x04002002L,0x00042002L,0x04042002L, 0x00000020L,0x04000020L,0x00040020L,0x04040020L, 0x00000022L,0x04000022L,0x00040022L,0x04040022L, 0x00002020L,0x04002020L,0x00042020L,0x04042020L, 0x00002022L,0x04002022L,0x00042022L,0x04042022L, 0x00000800L,0x04000800L,0x00040800L,0x04040800L, 0x00000802L,0x04000802L,0x00040802L,0x04040802L, 0x00002800L,0x04002800L,0x00042800L,0x04042800L, 0x00002802L,0x04002802L,0x00042802L,0x04042802L, 0x00000820L,0x04000820L,0x00040820L,0x04040820L, 0x00000822L,0x04000822L,0x00040822L,0x04040822L, 0x00002820L,0x04002820L,0x00042820L,0x04042820L, 0x00002822L,0x04002822L,0x00042822L,0x04042822L, }}; ================================================ FILE: itl80211/openbsd/crypto/spr.h ================================================ /* $OpenBSD: spr.h,v 1.2 2002/10/27 13:24:26 miod Exp $ */ /* lib/des/spr.h */ /* Copyright (C) 1995 Eric Young (eay@mincom.oz.au) * All rights reserved. * * This file is part of an SSL implementation written * by Eric Young (eay@mincom.oz.au). * The implementation was written so as to conform with Netscapes SSL * specification. This library and applications are * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE * as long as the following conditions are aheared to. * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. If this code is used in a product, * Eric Young should be given attribution as the author of the parts used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Eric Young (eay@mincom.oz.au) * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ static const u_int32_t des_SPtrans[8][64]={ { /* nibble 0 */ 0x00820200L, 0x00020000L, 0x80800000L, 0x80820200L, 0x00800000L, 0x80020200L, 0x80020000L, 0x80800000L, 0x80020200L, 0x00820200L, 0x00820000L, 0x80000200L, 0x80800200L, 0x00800000L, 0x00000000L, 0x80020000L, 0x00020000L, 0x80000000L, 0x00800200L, 0x00020200L, 0x80820200L, 0x00820000L, 0x80000200L, 0x00800200L, 0x80000000L, 0x00000200L, 0x00020200L, 0x80820000L, 0x00000200L, 0x80800200L, 0x80820000L, 0x00000000L, 0x00000000L, 0x80820200L, 0x00800200L, 0x80020000L, 0x00820200L, 0x00020000L, 0x80000200L, 0x00800200L, 0x80820000L, 0x00000200L, 0x00020200L, 0x80800000L, 0x80020200L, 0x80000000L, 0x80800000L, 0x00820000L, 0x80820200L, 0x00020200L, 0x00820000L, 0x80800200L, 0x00800000L, 0x80000200L, 0x80020000L, 0x00000000L, 0x00020000L, 0x00800000L, 0x80800200L, 0x00820200L, 0x80000000L, 0x80820000L, 0x00000200L, 0x80020200L, },{ /* nibble 1 */ 0x10042004L, 0x00000000L, 0x00042000L, 0x10040000L, 0x10000004L, 0x00002004L, 0x10002000L, 0x00042000L, 0x00002000L, 0x10040004L, 0x00000004L, 0x10002000L, 0x00040004L, 0x10042000L, 0x10040000L, 0x00000004L, 0x00040000L, 0x10002004L, 0x10040004L, 0x00002000L, 0x00042004L, 0x10000000L, 0x00000000L, 0x00040004L, 0x10002004L, 0x00042004L, 0x10042000L, 0x10000004L, 0x10000000L, 0x00040000L, 0x00002004L, 0x10042004L, 0x00040004L, 0x10042000L, 0x10002000L, 0x00042004L, 0x10042004L, 0x00040004L, 0x10000004L, 0x00000000L, 0x10000000L, 0x00002004L, 0x00040000L, 0x10040004L, 0x00002000L, 0x10000000L, 0x00042004L, 0x10002004L, 0x10042000L, 0x00002000L, 0x00000000L, 0x10000004L, 0x00000004L, 0x10042004L, 0x00042000L, 0x10040000L, 0x10040004L, 0x00040000L, 0x00002004L, 0x10002000L, 0x10002004L, 0x00000004L, 0x10040000L, 0x00042000L, },{ /* nibble 2 */ 0x41000000L, 0x01010040L, 0x00000040L, 0x41000040L, 0x40010000L, 0x01000000L, 0x41000040L, 0x00010040L, 0x01000040L, 0x00010000L, 0x01010000L, 0x40000000L, 0x41010040L, 0x40000040L, 0x40000000L, 0x41010000L, 0x00000000L, 0x40010000L, 0x01010040L, 0x00000040L, 0x40000040L, 0x41010040L, 0x00010000L, 0x41000000L, 0x41010000L, 0x01000040L, 0x40010040L, 0x01010000L, 0x00010040L, 0x00000000L, 0x01000000L, 0x40010040L, 0x01010040L, 0x00000040L, 0x40000000L, 0x00010000L, 0x40000040L, 0x40010000L, 0x01010000L, 0x41000040L, 0x00000000L, 0x01010040L, 0x00010040L, 0x41010000L, 0x40010000L, 0x01000000L, 0x41010040L, 0x40000000L, 0x40010040L, 0x41000000L, 0x01000000L, 0x41010040L, 0x00010000L, 0x01000040L, 0x41000040L, 0x00010040L, 0x01000040L, 0x00000000L, 0x41010000L, 0x40000040L, 0x41000000L, 0x40010040L, 0x00000040L, 0x01010000L, },{ /* nibble 3 */ 0x00100402L, 0x04000400L, 0x00000002L, 0x04100402L, 0x00000000L, 0x04100000L, 0x04000402L, 0x00100002L, 0x04100400L, 0x04000002L, 0x04000000L, 0x00000402L, 0x04000002L, 0x00100402L, 0x00100000L, 0x04000000L, 0x04100002L, 0x00100400L, 0x00000400L, 0x00000002L, 0x00100400L, 0x04000402L, 0x04100000L, 0x00000400L, 0x00000402L, 0x00000000L, 0x00100002L, 0x04100400L, 0x04000400L, 0x04100002L, 0x04100402L, 0x00100000L, 0x04100002L, 0x00000402L, 0x00100000L, 0x04000002L, 0x00100400L, 0x04000400L, 0x00000002L, 0x04100000L, 0x04000402L, 0x00000000L, 0x00000400L, 0x00100002L, 0x00000000L, 0x04100002L, 0x04100400L, 0x00000400L, 0x04000000L, 0x04100402L, 0x00100402L, 0x00100000L, 0x04100402L, 0x00000002L, 0x04000400L, 0x00100402L, 0x00100002L, 0x00100400L, 0x04100000L, 0x04000402L, 0x00000402L, 0x04000000L, 0x04000002L, 0x04100400L, },{ /* nibble 4 */ 0x02000000L, 0x00004000L, 0x00000100L, 0x02004108L, 0x02004008L, 0x02000100L, 0x00004108L, 0x02004000L, 0x00004000L, 0x00000008L, 0x02000008L, 0x00004100L, 0x02000108L, 0x02004008L, 0x02004100L, 0x00000000L, 0x00004100L, 0x02000000L, 0x00004008L, 0x00000108L, 0x02000100L, 0x00004108L, 0x00000000L, 0x02000008L, 0x00000008L, 0x02000108L, 0x02004108L, 0x00004008L, 0x02004000L, 0x00000100L, 0x00000108L, 0x02004100L, 0x02004100L, 0x02000108L, 0x00004008L, 0x02004000L, 0x00004000L, 0x00000008L, 0x02000008L, 0x02000100L, 0x02000000L, 0x00004100L, 0x02004108L, 0x00000000L, 0x00004108L, 0x02000000L, 0x00000100L, 0x00004008L, 0x02000108L, 0x00000100L, 0x00000000L, 0x02004108L, 0x02004008L, 0x02004100L, 0x00000108L, 0x00004000L, 0x00004100L, 0x02004008L, 0x02000100L, 0x00000108L, 0x00000008L, 0x00004108L, 0x02004000L, 0x02000008L, },{ /* nibble 5 */ 0x20000010L, 0x00080010L, 0x00000000L, 0x20080800L, 0x00080010L, 0x00000800L, 0x20000810L, 0x00080000L, 0x00000810L, 0x20080810L, 0x00080800L, 0x20000000L, 0x20000800L, 0x20000010L, 0x20080000L, 0x00080810L, 0x00080000L, 0x20000810L, 0x20080010L, 0x00000000L, 0x00000800L, 0x00000010L, 0x20080800L, 0x20080010L, 0x20080810L, 0x20080000L, 0x20000000L, 0x00000810L, 0x00000010L, 0x00080800L, 0x00080810L, 0x20000800L, 0x00000810L, 0x20000000L, 0x20000800L, 0x00080810L, 0x20080800L, 0x00080010L, 0x00000000L, 0x20000800L, 0x20000000L, 0x00000800L, 0x20080010L, 0x00080000L, 0x00080010L, 0x20080810L, 0x00080800L, 0x00000010L, 0x20080810L, 0x00080800L, 0x00080000L, 0x20000810L, 0x20000010L, 0x20080000L, 0x00080810L, 0x00000000L, 0x00000800L, 0x20000010L, 0x20000810L, 0x20080800L, 0x20080000L, 0x00000810L, 0x00000010L, 0x20080010L, },{ /* nibble 6 */ 0x00001000L, 0x00000080L, 0x00400080L, 0x00400001L, 0x00401081L, 0x00001001L, 0x00001080L, 0x00000000L, 0x00400000L, 0x00400081L, 0x00000081L, 0x00401000L, 0x00000001L, 0x00401080L, 0x00401000L, 0x00000081L, 0x00400081L, 0x00001000L, 0x00001001L, 0x00401081L, 0x00000000L, 0x00400080L, 0x00400001L, 0x00001080L, 0x00401001L, 0x00001081L, 0x00401080L, 0x00000001L, 0x00001081L, 0x00401001L, 0x00000080L, 0x00400000L, 0x00001081L, 0x00401000L, 0x00401001L, 0x00000081L, 0x00001000L, 0x00000080L, 0x00400000L, 0x00401001L, 0x00400081L, 0x00001081L, 0x00001080L, 0x00000000L, 0x00000080L, 0x00400001L, 0x00000001L, 0x00400080L, 0x00000000L, 0x00400081L, 0x00400080L, 0x00001080L, 0x00000081L, 0x00001000L, 0x00401081L, 0x00400000L, 0x00401080L, 0x00000001L, 0x00001001L, 0x00401081L, 0x00400001L, 0x00401080L, 0x00401000L, 0x00001001L, },{ /* nibble 7 */ 0x08200020L, 0x08208000L, 0x00008020L, 0x00000000L, 0x08008000L, 0x00200020L, 0x08200000L, 0x08208020L, 0x00000020L, 0x08000000L, 0x00208000L, 0x00008020L, 0x00208020L, 0x08008020L, 0x08000020L, 0x08200000L, 0x00008000L, 0x00208020L, 0x00200020L, 0x08008000L, 0x08208020L, 0x08000020L, 0x00000000L, 0x00208000L, 0x08000000L, 0x00200000L, 0x08008020L, 0x08200020L, 0x00200000L, 0x00008000L, 0x08208000L, 0x00000020L, 0x00200000L, 0x00008000L, 0x08000020L, 0x08208020L, 0x00008020L, 0x08000000L, 0x00000000L, 0x00208000L, 0x08200020L, 0x08008020L, 0x08008000L, 0x00200020L, 0x08208000L, 0x00000020L, 0x00200020L, 0x08008000L, 0x08208020L, 0x00200000L, 0x08200000L, 0x08000020L, 0x00208000L, 0x00008020L, 0x08008020L, 0x08200000L, 0x00000020L, 0x08208000L, 0x00208020L, 0x00000000L, 0x08000000L, 0x08200020L, 0x00008000L, 0x00208020L, }}; ================================================ FILE: itl80211/openbsd/net80211/CTimeout.cpp ================================================ // // CTimeout.cpp // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/30. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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 void CTimeout::timeoutOccurred(OSObject* owner, IOTimerEventSource* timer) { // IOLog("itlwm %s\n", __FUNCTION__); if (owner == NULL) { IOLog("itlwm tm owner == NULL!!!\n"); } CTimeout *tm = OSDynamicCast(CTimeout, owner); if (tm == NULL) { IOLog("itlwm tm == NULL!!!\n"); return; } //callback tm->isPending = false; tm->to_func(tm->to_arg); } IOReturn CTimeout::timeout_add_msec(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) { IOWorkLoop *wl = (IOWorkLoop*)arg1; int msecs = *(int*)arg2; CTimeout **ccto = (CTimeout **)arg0; if (ccto == NULL || *ccto == NULL) { return kIOReturnError; } CTimeout *cto = *ccto; if (cto->tm == NULL) { cto->tm = IOTimerEventSource::timerEventSource(cto, &CTimeout::timeoutOccurred); if (cto->tm == NULL) { return kIOReturnError; } cto->tm->enable(); wl->addEventSource(cto->tm); } cto->tm->setTimeoutMS(msecs); cto->isPending = true; return kIOReturnSuccess; } IOReturn CTimeout::timeout_del(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) { CTimeout **ccto = (CTimeout **)arg0; if (ccto == NULL || *ccto == NULL) { return kIOReturnSuccess; } CTimeout *cto = *ccto; if (cto->tm == NULL || !cto->isPending) { return kIOReturnSuccess; } cto->tm->cancelTimeout(); cto->isPending = false; return kIOReturnSuccess; } IOReturn CTimeout::timeout_free(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) { CTimeout **cto = (CTimeout **)arg0; IOWorkLoop *wl = (IOWorkLoop*)arg1; if (cto == NULL || *cto == NULL) { return kIOReturnSuccess; } CTimeout *tm = *cto; if (tm->tm != NULL) { wl->removeEventSource(tm->tm); tm->tm->release(); tm->tm = NULL; } tm->release(); *cto = NULL; return kIOReturnSuccess; } typedef void (*callback)(void *); IOReturn CTimeout::timeout_set(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) { CTimeout *tm; CTimeout **cto = (CTimeout **)arg0; if (cto == NULL) { return kIOReturnError; } if ((*cto) == NULL) { *cto = new CTimeout; } tm = *cto; tm->isPending = false; tm->to_func = (callback)arg1; tm->to_arg = arg2; return kIOReturnSuccess; } IOReturn CTimeout::timeout_pending(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) { CTimeout **cto = (CTimeout **)arg0; CTimeout *tm; if (cto == NULL) { return kIOReturnError; } tm = *cto; if (tm != NULL && tm->isPending) { return kIOReturnSuccess; } return kIOReturnError; } ================================================ FILE: itl80211/openbsd/net80211/_string.c ================================================ // // _string.h // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/30. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef _string_c #define _string_c #include #include #include int timingsafe_bcmp(const void *b1, const void *b2, size_t n) { const unsigned char *p1 = (const unsigned char *)b1, *p2 = (const unsigned char *)b2; int ret = 0; for (; n > 0; n--) ret |= *p1++ ^ *p2++; return (ret != 0); } #endif /* _string_c */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211.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. */ /* $OpenBSD: ieee80211.c,v 1.83 2020/04/08 09:34:29 stsp Exp $ */ /* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * IEEE 802.11 generic handler */ #include #include #include #include #include #include #include #include #include #include #include #include #if NBPFILTER > 0 #include #endif #include #include #include #include #ifdef IEEE80211_DEBUG int ieee80211_debug = 0; #endif ///compat for undefined symbols int _stop(struct kmod_info*, void*) { IOLog("_stop(struct kmod_info*, void*) has been invoked\n"); return 0; }; int _start(struct kmod_info*, void*) { IOLog("_start(struct kmod_info*, void*) has been invoked\n"); return 0; }; /// int ieee80211_cache_size = IEEE80211_CACHE_SIZE; void ieee80211_setbasicrates(struct ieee80211com *); int ieee80211_findrate(struct ieee80211com *, enum ieee80211_phymode, int); void ieee80211_configure_ampdu_tx(struct ieee80211com *, int); void ieee80211_begin_bgscan(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; if (ic->ic_state != IEEE80211_S_RUN || ic->ic_mgt_timer != 0) return; if ((ic->ic_flags & IEEE80211_F_RSNON) && !ic->ic_bss->ni_port_valid) return; if ((ic->ic_flags & IEEE80211_F_BGSCAN)) { //clear disable flag, because we need to switch a better wifi now. ic->ic_flags &= ~IEEE80211_F_DISABLE_BG_AUTO_CONNECT; return; } if (ic->ic_bgscan_start != NULL && ic->ic_bgscan_start(ic) == 0) { /* * Free the nodes table to ensure we get an up-to-date view * of APs around us. In particular, we need to kick out the * AP we are associated to. Otherwise, our current AP might * stay cached if it is turned off while we are scanning, and * we could end up picking a now non-existent AP over and over. */ ieee80211_free_allnodes(ic, 0 /* keep ic->ic_bss */); ic->ic_flags |= IEEE80211_F_BGSCAN; ic->ic_flags &= ~IEEE80211_F_DISABLE_BG_AUTO_CONNECT; if (ifp->if_flags & IFF_DEBUG) XYLog("%s: begin background scan\n", ifp->if_xname); /* Driver calls ieee80211_end_scan() when done. */ } } void ieee80211_begin_cache_bgscan(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; struct timeval tv; if ((ic->ic_flags & IEEE80211_F_BGSCAN) || ic->ic_state != IEEE80211_S_RUN || ic->ic_mgt_timer != 0) return; if ((ic->ic_flags & IEEE80211_F_RSNON) && !ic->ic_bss->ni_port_valid) return; ic->ic_flags |= IEEE80211_F_DISABLE_BG_AUTO_CONNECT; //if last cache scan is 5 minutes ago, clear the nodes and rescan. microtime(&tv); if (ic->ic_last_cache_scan_ts > 0 && tv.tv_sec - ic->ic_last_cache_scan_ts > 5 * 60) { ieee80211_free_allnodes(ic, 0); } ic->ic_last_cache_scan_ts = tv.tv_sec; if (ic->ic_bgscan_start != NULL && ic->ic_bgscan_start(ic) == 0) { ic->ic_flags |= IEEE80211_F_BGSCAN; DPRINTF(("%s: begin cache background scan\n", ifp->if_xname)); } } void ieee80211_bgscan_timeout(void *arg) { struct _ifnet *ifp = (struct _ifnet *)arg; ieee80211_begin_bgscan(ifp); } void ieee80211_channel_init(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ieee80211_channel *c; int i; /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); ic->ic_modecaps |= 1<ic_channels[i]; if (c->ic_flags) { /* * Verify driver passed us valid data. */ if (i != ieee80211_chan2ieee(ic, c)) { XYLog("%s: bad channel ignored; " "freq %u flags %x number %u\n", ifp->if_xname, c->ic_freq, c->ic_flags, i); c->ic_flags = 0; /* NB: remove */ continue; } setbit(ic->ic_chan_avail, i); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) ic->ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_curmode */ if ((ic->ic_modecaps & (1<ic_curmode)) == 0) ic->ic_curmode = IEEE80211_MODE_AUTO; ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ } void ieee80211_ifattach(struct _ifnet *ifp, IOEthernetController *controller) { IOLog("ieee80211_ifattach\n"); struct ieee80211com *ic = (struct ieee80211com *)ifp; ifp->controller = controller; ifq_init(&ifp->if_snd, ifp, 2048); memcpy(((struct arpcom *)ifp)->ac_enaddr, ic->ic_myaddr, ETHER_ADDR_LEN); if (ifp->if_sadl) { ::free(ifp->if_sadl); } ifp->if_sadl = (struct sockaddr_dl *)::malloc(sizeof(struct sockaddr_dl), 0, 0); memcpy(LLADDR(ifp->if_sadl), ic->ic_myaddr, ETHER_ADDR_LEN); ifp->if_output = ieee80211_output; #if NBPFILTER > 0 bpfattach(&ic->ic_rawbpf, ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4)); #endif ieee80211_crypto_attach(ifp); ieee80211_channel_init(ifp); /* IEEE 802.11 defines a MTU >= 2290 */ // ifp->if_capabilities |= IFCAP_VLAN_MTU; ieee80211_setbasicrates(ic); (void)ieee80211_setmode(ic, (enum ieee80211_phymode)ic->ic_curmode); if (ic->ic_lintval == 0) ic->ic_lintval = 100; /* default sleep */ ic->ic_bmissthres = IEEE80211_BEACON_MISS_THRES; ic->ic_dtim_period = 1; /* all TIMs are DTIMs */ ieee80211_node_attach(ifp); ieee80211_proto_attach(ifp); // if_addgroup(ifp, "wlan"); // ifp->if_priority = IF_WIRELESS_DEFAULT_PRIORITY; ieee80211_set_link_state(ic, LINK_STATE_DOWN); timeout_set(&ic->ic_bgscan_timeout, ieee80211_bgscan_timeout, ifp); } void ieee80211_ifdetach(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = (struct ieee80211com *)ifp; timeout_del(&ic->ic_bgscan_timeout); timeout_free(&ic->ic_bgscan_timeout); ieee80211_proto_detach(ifp); ieee80211_crypto_detach(ifp); ieee80211_node_detach(ifp); ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY); ifq_destroy(&ifp->if_snd); if (ifp->if_slowtimo) { ifp->if_slowtimo->release(); ifp->if_slowtimo = NULL; } if (ifp->if_sadl) { ::free(ifp->if_sadl); ifp->if_sadl = NULL; } ifp->netStat = NULL; ifp->controller = NULL; ifp->iface = NULL; } /* * Convert MHz frequency to IEEE channel number. */ u_int ieee80211_mhz2ieee(u_int freq, u_int flags) { if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (freq == 2484) return 14; if (freq < 2484) return (freq - 2407) / 5; else return 15 + ((freq - 2512) / 20); } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5GHz band */ return (freq - 5000) / 5; } else { /* either, guess */ if (freq == 2484) return 14; if (freq < 2484) return (freq - 2407) / 5; if (freq < 5000) return 15 + ((freq - 2512) / 20); return (freq - 5000) / 5; } } /* * Convert channel to IEEE channel number. */ u_int ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c) { struct _ifnet *ifp = &ic->ic_if; if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX]) return c - ic->ic_channels; else if (c == IEEE80211_CHAN_ANYC) return IEEE80211_CHAN_ANY; XYLog("严重%s: bogus channel pointer", ifp->if_xname); return 1; } /* * Convert IEEE channel number to MHz frequency. */ u_int ieee80211_ieee2mhz(u_int chan, u_int flags) { if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ if (chan == 14) return 2484; if (chan < 14) return 2407 + chan*5; else return 2512 + ((chan-15)*20); } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5GHz band */ return 5000 + (chan*5); } else { /* either, guess */ if (chan == 14) return 2484; if (chan < 14) /* 0-13 */ return 2407 + chan*5; if (chan < 27) /* 15-26 */ return 2512 + ((chan-15)*20); return 5000 + (chan*5); } } void ieee80211_configure_ampdu_tx(struct ieee80211com *ic, int enable) { if ((ic->ic_caps & IEEE80211_C_TX_AMPDU) == 0) return; /* Sending AMPDUs requires QoS support. */ if ((ic->ic_caps & IEEE80211_C_QOS) == 0) return; if (enable) ic->ic_flags |= IEEE80211_F_QOS; else ic->ic_flags &= ~IEEE80211_F_QOS; } /* * Setup the media data structures according to the channel and * rate tables. This must be called by the driver after * ieee80211_attach and before most anything else. */ void ieee80211_media_init(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); #define ADD(_ic, _s, _o) \ ifmedia_add(&(_ic)->ic_media, \ IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ifmediareq imr; int i, j, mode, rate, maxrate, r; uint64_t mword, mopt; const struct ieee80211_rateset *rs; struct ieee80211_rateset allrates; /* * Do late attach work that must wait for any subclass * (i.e. driver) work such as overriding methods. */ ieee80211_node_lateattach(ifp); /* * Fill in media characteristics. */ ifmedia_init(&ic->ic_media, 0); maxrate = 0; memset(&allrates, 0, sizeof(allrates)); for (mode = IEEE80211_MODE_AUTO; mode <= IEEE80211_MODE_11G; mode++) { static const uint64_t mopts[] = { IFM_AUTO, IFM_IEEE80211_11A, IFM_IEEE80211_11B, IFM_IEEE80211_11G, }; if ((ic->ic_modecaps & (1<ic_caps & IEEE80211_C_IBSS) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_IBSS); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC); #endif if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR); if (mode == IEEE80211_MODE_AUTO) continue; rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i]; mword = ieee80211_rate2media(ic, rate, (enum ieee80211_phymode)mode); if (mword == 0) continue; ADD(ic, mword, mopt); #ifndef IEEE80211_STA_ONLY if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, mword, mopt | IFM_IEEE80211_IBSS); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC); #endif if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR); /* * Add rate to the collection of all rates. */ r = rate & IEEE80211_RATE_VAL; for (j = 0; j < allrates.rs_nrates; j++) if (allrates.rs_rates[j] == r) break; if (j == allrates.rs_nrates) { /* unique, add to the set */ allrates.rs_rates[j] = r; allrates.rs_nrates++; } rate = (rate & IEEE80211_RATE_VAL) / 2; if (rate > maxrate) maxrate = rate; } } for (i = 0; i < allrates.rs_nrates; i++) { mword = ieee80211_rate2media(ic, allrates.rs_rates[i], IEEE80211_MODE_AUTO); if (mword == 0) continue; mword = IFM_SUBTYPE(mword); /* remove media options */ ADD(ic, mword, 0); #ifndef IEEE80211_STA_ONLY if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, mword, IFM_IEEE80211_IBSS); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, mword, IFM_IEEE80211_HOSTAP); if (ic->ic_caps & IEEE80211_C_AHDEMO) ADD(ic, mword, IFM_IEEE80211_ADHOC); #endif if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, mword, IFM_IEEE80211_MONITOR); } if (ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) { mopt = IFM_IEEE80211_11N; ADD(ic, IFM_AUTO, mopt); #ifndef IEEE80211_STA_ONLY if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_IBSS); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP); #endif if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR); for (i = 0; i < IEEE80211_HT_NUM_MCS; i++) { if (!isset(ic->ic_sup_mcs, i)) continue; ADD(ic, IFM_IEEE80211_HT_MCS0 + i, mopt); #ifndef IEEE80211_STA_ONLY if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, IFM_IEEE80211_HT_MCS0 + i, mopt | IFM_IEEE80211_IBSS); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, IFM_IEEE80211_HT_MCS0 + i, mopt | IFM_IEEE80211_HOSTAP); #endif if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, IFM_IEEE80211_HT_MCS0 + i, mopt | IFM_IEEE80211_MONITOR); } ic->ic_flags |= IEEE80211_F_HTON; /* enable 11n by default */ ieee80211_configure_ampdu_tx(ic, 1); } if (ic->ic_modecaps & (1 << IEEE80211_MODE_11AC)) { mopt = IFM_IEEE80211_11AC; ADD(ic, IFM_AUTO, mopt); #ifndef IEEE80211_STA_ONLY if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_IBSS); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP); #endif if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR); for (i = 0; i < IEEE80211_VHT_NUM_MCS; i++) { #if 0 /* TODO: Obtain VHT MCS information from VHT CAP IE. */ if (!vht_mcs_supported) continue; #endif ADD(ic, IFM_IEEE80211_VHT_MCS0 + i, mopt); #ifndef IEEE80211_STA_ONLY if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, IFM_IEEE80211_VHT_MCS0 + i, mopt | IFM_IEEE80211_IBSS); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, IFM_IEEE80211_VHT_MCS0 + i, mopt | IFM_IEEE80211_HOSTAP); #endif if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, IFM_IEEE80211_VHT_MCS0 + i, mopt | IFM_IEEE80211_MONITOR); } ieee80211_configure_ampdu_tx(ic, 1); } if (ic->ic_modecaps & (1 << IEEE80211_MODE_11AX)) { mopt = IFM_IEEE80211_11AX; ADD(ic, IFM_AUTO, mopt); for (i = 0; i < IEEE80211_VHT_NUM_MCS; i++) { #if 0 /* TODO: Obtain VHT MCS information from VHT CAP IE. */ if (!vht_mcs_supported) continue; #endif ADD(ic, IFM_IEEE80211_VHT_MCS0 + i, mopt); #ifndef IEEE80211_STA_ONLY if (ic->ic_caps & IEEE80211_C_IBSS) ADD(ic, IFM_IEEE80211_VHT_MCS0 + i, mopt | IFM_IEEE80211_IBSS); if (ic->ic_caps & IEEE80211_C_HOSTAP) ADD(ic, IFM_IEEE80211_VHT_MCS0 + i, mopt | IFM_IEEE80211_HOSTAP); #endif if (ic->ic_caps & IEEE80211_C_MONITOR) ADD(ic, IFM_IEEE80211_VHT_MCS0 + i, mopt | IFM_IEEE80211_MONITOR); } ieee80211_configure_ampdu_tx(ic, 1); } ieee80211_media_status(ifp, &imr); ifmedia_set(&ic->ic_media, imr.ifm_active); // if (maxrate) // ifp->if_baudrate = IF_Mbps(maxrate); #undef ADD } int ieee80211_findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) { #define IEEERATE(_ic,_m,_i) \ ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) int i, nrates = ic->ic_sup_rates[mode].rs_nrates; for (i = 0; i < nrates; i++) if (IEEERATE(ic, mode, i) == rate) return i; return -1; #undef IEEERATE } /* * Handle a media change request. */ int ieee80211_media_change(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ifmedia_entry *ime; enum ieee80211_opmode newopmode; enum ieee80211_phymode newphymode; int i, j, newrate, error = 0; ime = ic->ic_media.ifm_cur; /* * First, identify the phy mode. */ switch (IFM_MODE(ime->ifm_media)) { case IFM_IEEE80211_11A: newphymode = IEEE80211_MODE_11A; break; case IFM_IEEE80211_11B: newphymode = IEEE80211_MODE_11B; break; case IFM_IEEE80211_11G: newphymode = IEEE80211_MODE_11G; break; case IFM_IEEE80211_11N: newphymode = IEEE80211_MODE_11N; break; case IFM_IEEE80211_11AC: newphymode = IEEE80211_MODE_11AC; break; case IFM_IEEE80211_11AX: newphymode = IEEE80211_MODE_11AX; break; case IFM_AUTO: newphymode = IEEE80211_MODE_AUTO; break; default: return EINVAL; } /* * Validate requested mode is available. */ if ((ic->ic_modecaps & (1<ifm_media) >= IFM_IEEE80211_VHT_MCS0 && IFM_SUBTYPE(ime->ifm_media) <= IFM_IEEE80211_VHT_MCS9) { if (((ic->ic_modecaps & (1 << IEEE80211_MODE_11AC)) == 0) && ((ic->ic_modecaps & (1 << IEEE80211_MODE_11AX)) == 0)) return EINVAL; if (newphymode != IEEE80211_MODE_AUTO && newphymode != IEEE80211_MODE_11AC && newphymode != IEEE80211_MODE_11AX) return EINVAL; i = ieee80211_media2mcs(ime->ifm_media); /* TODO: Obtain VHT MCS information from VHT CAP IE. */ if (i == -1 /* || !vht_mcs_supported */) return EINVAL; } else if (IFM_SUBTYPE(ime->ifm_media) >= IFM_IEEE80211_HT_MCS0 && IFM_SUBTYPE(ime->ifm_media) <= IFM_IEEE80211_HT_MCS76) { if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) == 0) return EINVAL; if (newphymode != IEEE80211_MODE_AUTO && newphymode != IEEE80211_MODE_11N) return EINVAL; i = ieee80211_media2mcs(ime->ifm_media); if (i == -1 || isclr(ic->ic_sup_mcs, i)) return EINVAL; } else if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) { /* * Convert media subtype to rate. */ newrate = ieee80211_media2rate(ime->ifm_media); if (newrate == 0) return EINVAL; /* * Check the rate table for the specified/current phy. */ if (newphymode == IEEE80211_MODE_AUTO) { /* * In autoselect mode search for the rate. */ for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) { if ((ic->ic_modecaps & (1<ifm_media & IFM_IEEE80211_ADHOC) newopmode = IEEE80211_M_AHDEMO; else if (ime->ifm_media & IFM_IEEE80211_HOSTAP) newopmode = IEEE80211_M_HOSTAP; else if (ime->ifm_media & IFM_IEEE80211_IBSS) newopmode = IEEE80211_M_IBSS; else #endif if (ime->ifm_media & IFM_IEEE80211_MONITOR) newopmode = IEEE80211_M_MONITOR; else newopmode = IEEE80211_M_STA; #ifndef IEEE80211_STA_ONLY /* * Autoselect doesn't make sense when operating as an AP. * If no phy mode has been selected, pick one and lock it * down so rate tables can be used in forming beacon frames * and the like. */ if (newopmode == IEEE80211_M_HOSTAP && newphymode == IEEE80211_MODE_AUTO) { if (ic->ic_modecaps & (1 << IEEE80211_MODE_11AX)) newphymode = IEEE80211_MODE_11AX; if (ic->ic_modecaps & (1 << IEEE80211_MODE_11AC)) newphymode = IEEE80211_MODE_11AC; else if (ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) newphymode = IEEE80211_MODE_11N; else if (ic->ic_modecaps & (1 << IEEE80211_MODE_11A)) newphymode = IEEE80211_MODE_11A; else if (ic->ic_modecaps & (1 << IEEE80211_MODE_11G)) newphymode = IEEE80211_MODE_11G; else newphymode = IEEE80211_MODE_11B; } #endif /* * Handle phy mode change. */ if (ic->ic_curmode != newphymode) { /* change phy mode */ error = ieee80211_setmode(ic, newphymode); if (error != 0) return error; error = ENETRESET; } /* * Committed to changes, install the MCS/rate setting. */ ic->ic_flags &= ~(IEEE80211_F_HTON | IEEE80211_F_VHTON); ieee80211_configure_ampdu_tx(ic, 0); if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11AX)) && (newphymode == IEEE80211_MODE_AUTO || newphymode == IEEE80211_MODE_11AX)) { ic->ic_flags |= IEEE80211_F_HEON; ieee80211_configure_ampdu_tx(ic, 1); } else if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11AC)) && (newphymode == IEEE80211_MODE_AUTO || newphymode == IEEE80211_MODE_11AC)) { ic->ic_flags |= IEEE80211_F_VHTON; ieee80211_configure_ampdu_tx(ic, 1); } else if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) && (newphymode == IEEE80211_MODE_AUTO || newphymode == IEEE80211_MODE_11N)) { ic->ic_flags |= IEEE80211_F_HTON; ieee80211_configure_ampdu_tx(ic, 1); } if ((ic->ic_flags & (IEEE80211_F_HTON | IEEE80211_F_VHTON)) == 0) { ic->ic_fixed_mcs = -1; if (ic->ic_fixed_rate != i) { ic->ic_fixed_rate = i; /* set fixed tx rate */ error = ENETRESET; } } else { ic->ic_fixed_rate = -1; if (ic->ic_fixed_mcs != i) { ic->ic_fixed_mcs = i; /* set fixed mcs */ error = ENETRESET; } } /* * Handle operating mode change. */ if (ic->ic_opmode != newopmode) { ic->ic_opmode = newopmode; #ifndef IEEE80211_STA_ONLY switch (newopmode) { case IEEE80211_M_AHDEMO: case IEEE80211_M_HOSTAP: case IEEE80211_M_STA: case IEEE80211_M_MONITOR: ic->ic_flags &= ~IEEE80211_F_IBSSON; break; case IEEE80211_M_IBSS: ic->ic_flags |= IEEE80211_F_IBSSON; break; } #endif /* * Yech, slot time may change depending on the * operating mode so reset it to be sure everything * is setup appropriately. */ ieee80211_reset_erp(ic); error = ENETRESET; } #ifdef notdef if (error == 0) ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media); #endif return error; } void ieee80211_media_status(struct _ifnet *ifp, struct ifmediareq *imr) { struct ieee80211com *ic = (struct ieee80211com *)ifp; const struct ieee80211_node *ni = NULL; imr->ifm_status = IFM_AVALID; imr->ifm_active = IFM_IEEE80211; if (ic->ic_state == IEEE80211_S_RUN && (ic->ic_opmode != IEEE80211_M_STA || !(ic->ic_flags & IEEE80211_F_RSNON) || ic->ic_bss->ni_port_valid)) imr->ifm_status |= IFM_ACTIVE; imr->ifm_active |= IFM_AUTO; switch (ic->ic_opmode) { case IEEE80211_M_STA: ni = ic->ic_bss; if (ic->ic_curmode == IEEE80211_MODE_11N || ic->ic_curmode == IEEE80211_MODE_11AC || ic->ic_curmode == IEEE80211_MODE_11AX) imr->ifm_active |= ieee80211_mcs2media(ic, ni->ni_txmcs, (enum ieee80211_phymode)ic->ic_curmode); else if (ni->ni_flags & IEEE80211_NODE_HE) /* in MODE_AUTO */ imr->ifm_active |= ieee80211_mcs2media(ic, ni->ni_txmcs, IEEE80211_MODE_11AX); else if (ni->ni_flags & IEEE80211_NODE_VHT) /* in MODE_AUTO */ imr->ifm_active |= ieee80211_mcs2media(ic, ni->ni_txmcs, IEEE80211_MODE_11AC); else if (ni->ni_flags & IEEE80211_NODE_HT) /* in MODE_AUTO */ imr->ifm_active |= ieee80211_mcs2media(ic, ni->ni_txmcs, IEEE80211_MODE_11N); else /* calculate rate subtype */ imr->ifm_active |= ieee80211_rate2media(ic, ni->ni_rates.rs_rates[ni->ni_txrate], (enum ieee80211_phymode)ic->ic_curmode); break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_IBSS: imr->ifm_active |= IFM_IEEE80211_IBSS; break; case IEEE80211_M_AHDEMO: imr->ifm_active |= IFM_IEEE80211_ADHOC; break; case IEEE80211_M_HOSTAP: imr->ifm_active |= IFM_IEEE80211_HOSTAP; break; #endif case IEEE80211_M_MONITOR: imr->ifm_active |= IFM_IEEE80211_MONITOR; break; default: break; } switch (ic->ic_curmode) { case IEEE80211_MODE_11A: imr->ifm_active |= IFM_IEEE80211_11A; break; case IEEE80211_MODE_11B: imr->ifm_active |= IFM_IEEE80211_11B; break; case IEEE80211_MODE_11G: imr->ifm_active |= IFM_IEEE80211_11G; break; case IEEE80211_MODE_11N: imr->ifm_active |= IFM_IEEE80211_11N; break; case IEEE80211_MODE_11AC: imr->ifm_active |= IFM_IEEE80211_11AC; break; case IEEE80211_MODE_11AX: imr->ifm_active |= IFM_IEEE80211_11AX; break; } } void ieee80211_watchdog(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0) { if (ic->ic_opmode == IEEE80211_M_STA && (ic->ic_state == IEEE80211_S_AUTH || ic->ic_state == IEEE80211_S_ASSOC)) { struct ieee80211_node *ni; if (ifp->if_flags & IFF_DEBUG) XYLog("%s: %s timed out for %s\n", ifp->if_xname, ic->ic_state == IEEE80211_S_ASSOC ? "association" : "authentication", ether_sprintf(ic->ic_bss->ni_macaddr)); ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); if (ni) ni->ni_fails++; /* Try more times to join, some drivers will timeout when doing auth/assoc */ if (ic->ic_state == IEEE80211_S_AUTH && ni && ni->ni_fails < 3) { ieee80211_node_join_bss(ic, ni); goto done; } if (ISSET(ic->ic_flags, IEEE80211_F_AUTO_JOIN)) ieee80211_deselect_ess(ic); } ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); } done: if (ic->ic_mgt_timer != 0) ifp->if_timer = 1; } const struct ieee80211_rateset ieee80211_std_rateset_11a = { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; const struct ieee80211_rateset ieee80211_std_rateset_11b = { 4, { 2, 4, 11, 22 } }; const struct ieee80211_rateset ieee80211_std_rateset_11g = { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; const struct ieee80211_ht_rateset ieee80211_std_ratesets_11n[] = { /* MCS 0-7, 20MHz channel, no SGI */ { 8, { 13, 26, 39, 52, 78, 104, 117, 130 }, 0x000000ff, 0, 7, 0}, /* MCS 0-7, 20MHz channel, SGI */ { 8, { 14, 29, 43, 58, 87, 116, 130, 144 }, 0x000000ff, 0, 7, 1 }, /* MCS 8-15, 20MHz channel, no SGI */ { 8, { 26, 52, 78, 104, 156, 208, 234, 260 }, 0x0000ff00, 8, 15, 0 }, /* MCS 8-15, 20MHz channel, SGI */ { 8, { 29, 58, 87, 116, 173, 231, 261, 289 }, 0x0000ff00, 8, 15, 1 }, /* MCS 16-23, 20MHz channel, no SGI */ { 8, { 39, 78, 117, 156, 234, 312, 351, 390 }, 0x00ff0000, 16, 23, 0 }, /* MCS 16-23, 20MHz channel, SGI */ { 8, { 43, 87, 130, 173, 260, 347, 390, 433 }, 0x00ff0000, 16, 23, 1 }, /* MCS 24-31, 20MHz channel, no SGI */ { 8, { 52, 104, 156, 208, 312, 416, 468, 520 }, 0xff000000, 24, 31, 0 }, /* MCS 24-31, 20MHz channel, SGI */ { 8, { 58, 116, 173, 231, 347, 462, 520, 578 }, 0xff000000, 24, 31, 1 }, /* MCS 0-7, 40MHz channel, no SGI */ { 8, { 27, 54, 81, 108, 162, 216, 243, 270 }, 0x000000ff, 0, 7, 0}, /* MCS 0-7, 40MHz channel, SGI */ { 8, { 30, 60, 90, 120, 180, 240, 270, 300 }, 0x000000ff, 0, 7, 1 }, /* MCS 8-15, 40MHz channel, no SGI */ { 8, { 54, 108, 162, 216, 324, 432, 486, 540 }, 0x0000ff00, 8, 15, 0 }, /* MCS 8-15, 40MHz channel, SGI */ { 8, { 60, 120, 180, 240, 360, 480, 540, 600 }, 0x0000ff00, 8, 15, 1 }, /* MCS 16-23, 40MHz channel, no SGI */ { 8, { 81, 162, 243, 324, 486, 648, 729, 810 }, 0x00ff0000, 16, 23, 0 }, /* MCS 16-23, 40MHz channel, SGI */ { 8, { 90, 180, 270, 360, 540, 720, 810, 900 }, 0x00ff0000, 16, 23, 1 }, /* MCS 24-31, 40MHz channel, no SGI */ { 8, { 108, 216, 324, 432, 648, 864, 972, 1080 }, 0xff000000, 24, 31, 0 }, /* MCS 24-31, 40MHz channel, SGI */ { 8, { 120, 240, 360, 480, 720, 960, 1080, 1200 }, 0xff000000, 24, 31, 1 }, }; const struct ieee80211_vht_rateset ieee80211_std_ratesets_11ac[] = { /* MCS 0-8 (MCS 9 N/A), 1 SS, 20MHz channel, no SGI */ { 9, { 13, 26, 39, 52, 78, 104, 117, 130, 156 }, 1, 0 }, /* MCS 0-8 (MCS 9 N/A), 1 SS, 20MHz channel, SGI */ { 9, { 14, 29, 43, 58, 87, 116, 130, 144, 174 }, 1, 1 }, /* MCS 0-8 (MCS 9 N/A), 2 SS, 20MHz channel, no SGI */ { 9, { 26, 52, 78, 104, 156, 208, 234, 260, 312 }, 2, 0 }, /* MCS 0-8 (MCS 9 N/A), 2 SS, 20MHz channel, SGI */ { 9, { 29, 58, 87, 116, 173, 231, 261, 289, 347 }, 2, 1 }, /* MCS 0-9, 1 SS, 40MHz channel, no SGI */ { 10, { 27, 54, 81, 108, 162, 216, 243, 270, 324, 360 }, 1, 0 }, /* MCS 0-9, 1 SS, 40MHz channel, SGI */ { 10, { 30, 60, 90, 120, 180, 240, 270, 300, 360, 400 }, 1, 1 }, /* MCS 0-9, 2 SS, 40MHz channel, no SGI */ { 10, { 54, 108, 162, 216, 324, 432, 486, 540, 648, 720 }, 2, 0 }, /* MCS 0-9, 2 SS, 40MHz channel, SGI */ { 10, { 60, 120, 180, 240, 360, 480, 540, 600, 720, 800 }, 2, 1 }, /* MCS 0-9, 1 SS, 80MHz channel, no SGI */ { 10, { 59, 117, 176, 234, 351, 468, 527, 585, 702, 780 }, 1, 0 }, /* MCS 0-9, 1 SS, 80MHz channel, SGI */ { 10, { 65, 130, 195, 260, 390, 520, 585, 650, 780, 867 }, 1, 1 }, /* MCS 0-9, 2 SS, 80MHz channel, no SGI */ { 10, { 117, 234, 351, 468, 702, 936, 1053, 1404, 1560 }, 2, 0 }, /* MCS 0-9, 2 SS, 80MHz channel, SGI */ { 10, { 130, 260, 390, 520, 780, 1040, 1170, 1300, 1560, 1734 }, 2, 1 }, /* MCS 0-9, 1 SS, 160MHz channel, no SGI */ { 10, { 117, 234, 351, 468, 702, 936, 1053, 1170, 1404, 1560 }, 1, 0 }, /* MCS 0-9, 1 SS, 160MHz channel, SGI */ { 10, { 130, 260, 390, 520, 780, 1040, 1170, 1300, 1560, 1734 }, 1, 1 }, /* MCS 0-9, 2 SS, 160MHz channel, no SGI */ { 10, { 234, 468, 702, 936, 1404, 1872, 2106, 2340, 2808 }, 2, 0 }, /* MCS 0-9, 2 SS, 160MHz channel, SGI */ { 10, { 260, 520, 780, 1040, 1560, 2080, 2340, 2600, 3120, 3464 }, 2, 1 }, }; const struct ieee80211_he_rateset ieee80211_std_ratesets_11ax[] = { /* MCS 0-11 1 SS, 20MHz channel */ { 12, { 17, 34, 52, 69, 103, 138, 155, 172, 206, 230, 258, 287 }, 1 }, /* MCS 0-11 2 SS, 20MHz channel */ { 12, { 34, 69, 103, 138, 206, 275, 310, 344, 413, 459, 516, 574 }, 2 }, /* MCS 0-11 1 SS, 40MHz channel */ { 12, { 34, 69, 103, 138, 206, 275, 310, 344, 413, 459, 516, 574 }, 1 }, /* MCS 0-11 2 SS, 40MHz channel */ { 12, { 69, 138, 206, 275, 413, 551, 619, 688, 826, 918, 1032, 1147 }, 2 }, /* MCS 0-11 1 SS, 80MHz channel */ { 12, { 72, 144, 216, 288, 432, 577, 649, 721, 865, 961, 1081, 1201 }, 1 }, /* MCS 0-11 2 SS, 80MHz channel */ { 12, { 288, 577, 865, 1153, 1729, 2306, 2594, 2882, 3459, 3843, 4324, 4804 }, 2}, /* MCS 0-11 1 SS, 160MHz channel */ { 12, { 144, 288, 432, 564, 865, 1152, 1298, 1442, 1730, 1922, 2162, 2402 }, 1 }, /* MCS 0-11 2 SS, 160MHz channel */ { 12, { 576, 1154, 1730, 2306, 3458, 4612, 5188, 5764, 6918, 7686, 8648, 9608 }, 2 }, }; /* * Mark the basic rates for the 11g rate table based on the * operating mode. For real 11g we mark all the 11b rates * and 6, 12, and 24 OFDM. For 11b compatibility we mark only * 11b rates. There's also a pseudo 11a-mode used to mark only * the basic OFDM rates. */ void ieee80211_setbasicrates(struct ieee80211com *ic) { static const struct ieee80211_rateset basic[] = { { 0 }, /* IEEE80211_MODE_AUTO */ { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G */ { 0 }, /* IEEE80211_MODE_11N */ { 0 }, /* IEEE80211_MODE_11AC */ { 0 }, /* IEEE80211_MODE_11AX */ }; int mode; struct ieee80211_rateset *rs; int i, j; for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) { rs = &ic->ic_sup_rates[mode]; for (i = 0; i < rs->rs_nrates; i++) { rs->rs_rates[i] &= IEEE80211_RATE_VAL; for (j = 0; j < basic[mode].rs_nrates; j++) { if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { rs->rs_rates[i] |= IEEE80211_RATE_BASIC; break; } } } } } int ieee80211_min_basic_rate(struct ieee80211com *ic) { struct ieee80211_rateset *rs = &ic->ic_bss->ni_rates; int i, min, rval; min = -1; for (i = 0; i < rs->rs_nrates; i++) { if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0) continue; rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL); if (min == -1) min = rval; else if (rval < min) min = rval; } /* Default to 1 Mbit/s on 2GHz and 6 Mbit/s on 5GHz. */ if (min == -1) min = IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan) ? 2 : 12; return min; } int ieee80211_max_basic_rate(struct ieee80211com *ic) { struct ieee80211_rateset *rs = &ic->ic_bss->ni_rates; int i, max, rval; /* Default to 1 Mbit/s on 2GHz and 6 Mbit/s on 5GHz. */ max = IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan) ? 2 : 12; for (i = 0; i < rs->rs_nrates; i++) { if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0) continue; rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL); if (rval > max) max = rval; } return max; } /* * Set the current phy mode and recalculate the active channel * set based on the available channels for this mode. Also * select a new default/current channel if the current one is * inappropriate for this mode. */ int ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) { struct _ifnet *ifp = &ic->ic_if; static const u_int chanflags[] = { 0, /* IEEE80211_MODE_AUTO */ IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ IEEE80211_CHAN_HT, /* IEEE80211_MODE_11N */ IEEE80211_CHAN_VHT | IEEE80211_CHAN_HT, /* IEEE80211_MODE_11AC */ IEEE80211_CHAN_VHT | IEEE80211_CHAN_HT, /* IEEE80211_MODE_11AX */ }; const struct ieee80211_channel *c; u_int modeflags; int i; /* validate new mode */ if ((ic->ic_modecaps & (1<ic_modecaps)); return EINVAL; } /* * Verify at least one channel is present in the available * channel list before committing to the new mode. */ if (mode >= nitems(chanflags)) panic("%s: unexpected mode %u", __func__, mode); modeflags = chanflags[mode]; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (mode == IEEE80211_MODE_AUTO) { if (c->ic_flags != 0) break; } else if ((c->ic_flags & modeflags) != 0) break; } if (i > IEEE80211_CHAN_MAX) { DPRINTF(("no channels found for mode %u\n", mode)); return EINVAL; } /* * Calculate the active channel set. */ memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active)); for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (mode == IEEE80211_MODE_AUTO) { if (c->ic_flags != 0) setbit(ic->ic_chan_active, i); } else if ((c->ic_flags & modeflags) != 0) setbit(ic->ic_chan_active, i); } /* * If no current/default channel is setup or the current * channel is wrong for the mode then pick the first * available channel from the active list. This is likely * not the right one. */ if (ic->ic_ibss_chan == NULL || isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { for (i = 0; i <= IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i)) { ic->ic_ibss_chan = &ic->ic_channels[i]; break; } if ((ic->ic_ibss_chan == NULL) || isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) panic("Bad IBSS channel %u", ieee80211_chan2ieee(ic, ic->ic_ibss_chan)); } /* * Reset the scan state for the new mode. This avoids scanning * of invalid channels, ie. 5GHz channels in 11b mode. */ ieee80211_reset_scan(ifp); ic->ic_curmode = mode; ieee80211_reset_erp(ic); /* reset ERP state */ return 0; } enum ieee80211_phymode ieee80211_next_mode(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; uint16_t mode; /* * Indicate a wrap-around if we're running in a fixed, user-specified * phy mode. */ if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) != IFM_AUTO) return (IEEE80211_MODE_AUTO); /* * Always scan in AUTO mode if the driver scans all bands. * The current mode might have changed during association * so we must reset it here. */ if (ic->ic_caps & IEEE80211_C_SCANALLBAND) { ieee80211_setmode(ic, IEEE80211_MODE_AUTO); return (enum ieee80211_phymode)(ic->ic_curmode); } /* * Get the next supported mode; effectively, this alternates between * the 11a (5GHz) and 11b/g (2GHz) modes. What matters is that each * supported channel gets scanned. */ for (mode = ic->ic_curmode + 1; mode <= IEEE80211_MODE_MAX; mode++) { /* * Skip over 11n mode. Its set of channels is the superset * of all channels supported by the other modes. */ if (mode == IEEE80211_MODE_11N) continue; /* * Skip over 11ac mode. Its set of channels is the set * of all channels supported by 11a. */ if (mode == IEEE80211_MODE_11AC) continue; /* * Skip over 11ax mode. Its set of channels is the set * of all channels supported by 11a. */ if (mode == IEEE80211_MODE_11AX) continue; /* Start over if we have already tried all modes. */ if (mode == IEEE80211_MODE_MAX) { mode = IEEE80211_MODE_AUTO; break; } if (ic->ic_modecaps & (1 << mode)) break; } if (mode != ic->ic_curmode) ieee80211_setmode(ic, (enum ieee80211_phymode)mode); return (enum ieee80211_phymode)(ic->ic_curmode); } /* * Return the phy mode for with the specified channel so the * caller can select a rate set. This is problematic and the * work here assumes how things work elsewhere in this code. * * Because the result of this function is ultimately used to select a * rate from the rate set of the returned mode, it must return one of the * legacy 11a/b/g modes; 11n and 11ac modes use MCS instead of rate sets. */ enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *ic, const struct ieee80211_channel *chan) { /* * Are we fixed in 11a/b/g mode? * NB: this assumes the channel would not be supplied to us * unless it was already compatible with the current mode. */ if (ic->ic_curmode == IEEE80211_MODE_11A || ic->ic_curmode == IEEE80211_MODE_11B || ic->ic_curmode == IEEE80211_MODE_11G) return (enum ieee80211_phymode)ic->ic_curmode; /* If no channel was provided, return the most suitable legacy mode. */ if (chan == IEEE80211_CHAN_ANYC) { switch (ic->ic_curmode) { case IEEE80211_MODE_AUTO: case IEEE80211_MODE_11N: if (ic->ic_modecaps & (1 << IEEE80211_MODE_11A)) return IEEE80211_MODE_11A; if (ic->ic_modecaps & (1 << IEEE80211_MODE_11G)) return IEEE80211_MODE_11G; return IEEE80211_MODE_11B; case IEEE80211_MODE_11AC: case IEEE80211_MODE_11AX: return IEEE80211_MODE_11A; default: return (enum ieee80211_phymode)ic->ic_curmode; } } /* Deduce a legacy mode based on the channel characteristics. */ if (IEEE80211_IS_CHAN_5GHZ(chan)) return IEEE80211_MODE_11A; else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) return IEEE80211_MODE_11G; else return IEEE80211_MODE_11B; } /* * Convert IEEE80211 MCS index to ifmedia subtype. */ uint64_t ieee80211_mcs2media(struct ieee80211com *ic, int mcs, enum ieee80211_phymode mode) { switch (mode) { case IEEE80211_MODE_11A: case IEEE80211_MODE_11B: case IEEE80211_MODE_11G: /* these modes use rates, not MCS */ panic("%s: unexpected mode %d", __func__, mode); break; case IEEE80211_MODE_11N: if (mcs >= 0 && mcs < IEEE80211_HT_NUM_MCS) return (IFM_IEEE80211_11N | (IFM_IEEE80211_HT_MCS0 + mcs)); break; case IEEE80211_MODE_11AC: if (mcs >= 0 && mcs < IEEE80211_VHT_NUM_MCS) return (IFM_IEEE80211_11AC | (IFM_IEEE80211_VHT_MCS0 + mcs)); break; case IEEE80211_MODE_11AX: if (mcs >= 0 && mcs < IEEE80211_VHT_NUM_MCS) return (IFM_IEEE80211_11AX | (IFM_IEEE80211_VHT_MCS0 + mcs)); break; case IEEE80211_MODE_AUTO: break; } return IFM_AUTO; } /* * Convert ifmedia subtype to IEEE80211 MCS index. */ int ieee80211_media2mcs(uint64_t mword) { uint64_t subtype; subtype = IFM_SUBTYPE(mword); if (subtype == IFM_AUTO) return -1; else if (subtype == IFM_MANUAL || subtype == IFM_NONE) return 0; if (subtype >= IFM_IEEE80211_HT_MCS0 && subtype <= IFM_IEEE80211_HT_MCS76) return (int)(subtype - IFM_IEEE80211_HT_MCS0); if (subtype >= IFM_IEEE80211_VHT_MCS0 && subtype <= IFM_IEEE80211_VHT_MCS9) return (int)(subtype - IFM_IEEE80211_VHT_MCS0); return -1; } /* * convert IEEE80211 rate value to ifmedia subtype. * ieee80211 rate is in unit of 0.5Mbps. */ uint64_t ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode) { static const struct { uint64_t m; /* rate + mode */ uint64_t r; /* if_media rate */ } rates[] = { { 2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 }, { 4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 }, { 11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 }, { 22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 }, { 44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 }, { 12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 }, { 18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 }, { 24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 }, { 36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 }, { 48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 }, { 72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 }, { 96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 }, { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 }, { 2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 }, { 4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 }, { 11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 }, { 22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 }, { 12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 }, { 18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 }, { 24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 }, { 36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 }, { 48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 }, { 72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 }, { 96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 }, { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 }, /* NB: OFDM72 doesn't really exist so we don't handle it */ }; uint64_t mask; int i; mask = rate & IEEE80211_RATE_VAL; switch (mode) { case IEEE80211_MODE_11A: mask |= IFM_IEEE80211_11A; break; case IEEE80211_MODE_11B: mask |= IFM_IEEE80211_11B; break; case IEEE80211_MODE_AUTO: /* NB: hack, 11g matches both 11b+11a rates */ /* FALLTHROUGH */ case IEEE80211_MODE_11G: mask |= IFM_IEEE80211_11G; break; case IEEE80211_MODE_11N: case IEEE80211_MODE_11AC: case IEEE80211_MODE_11AX: /* 11n/11ac/11ax uses MCS, not rates. */ panic("%s: unexpected mode %d", __func__, mode); break; } for (i = 0; i < nitems(rates); i++) if (rates[i].m == mask) return rates[i].r; return IFM_AUTO; } int ieee80211_media2rate(uint64_t mword) { int i; static const struct { uint64_t subtype; int rate; } ieeerates[] = { { IFM_AUTO, -1 }, { IFM_MANUAL, 0 }, { IFM_NONE, 0 }, { IFM_IEEE80211_DS1, 2 }, { IFM_IEEE80211_DS2, 4 }, { IFM_IEEE80211_DS5, 11 }, { IFM_IEEE80211_DS11, 22 }, { IFM_IEEE80211_DS22, 44 }, { IFM_IEEE80211_OFDM6, 12 }, { IFM_IEEE80211_OFDM9, 18 }, { IFM_IEEE80211_OFDM12, 24 }, { IFM_IEEE80211_OFDM18, 36 }, { IFM_IEEE80211_OFDM24, 48 }, { IFM_IEEE80211_OFDM36, 72 }, { IFM_IEEE80211_OFDM48, 96 }, { IFM_IEEE80211_OFDM54, 108 }, { IFM_IEEE80211_OFDM72, 144 }, }; for (i = 0; i < nitems(ieeerates); i++) { if (ieeerates[i].subtype == IFM_SUBTYPE(mword)) return ieeerates[i].rate; } return 0; } /* * Convert bit rate (in 0.5Mbps units) to PLCP signal (R4-R1) and vice versa. */ u_int8_t ieee80211_rate2plcp(u_int8_t rate, enum ieee80211_phymode mode) { rate &= IEEE80211_RATE_VAL; if (mode == IEEE80211_MODE_11B) { /* IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3 */ switch (rate) { case 2: return 10; case 4: return 20; case 11: return 55; case 22: return 110; /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ case 44: return 220; } } else if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11A) { /* IEEE Std 802.11a-1999 page 14, subclause 17.3.4.1 */ switch (rate) { case 12: return 0x0b; case 18: return 0x0f; case 24: return 0x0a; case 36: return 0x0e; case 48: return 0x09; case 72: return 0x0d; case 96: return 0x08; case 108: return 0x0c; } } else panic("%s: unexpected mode %u", __func__, mode); DPRINTF(("unsupported rate %u\n", rate)); return 0; } u_int8_t ieee80211_plcp2rate(u_int8_t plcp, enum ieee80211_phymode mode) { if (mode == IEEE80211_MODE_11B) { /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ switch (plcp) { case 10: return 2; case 20: return 4; case 55: return 11; case 110: return 22; /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ case 220: return 44; } } else if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11A) { /* IEEE Std 802.11a-1999 page 14, subclause 17.3.4.1 */ switch (plcp) { case 0x0b: return 12; case 0x0f: return 18; case 0x0a: return 24; case 0x0e: return 36; case 0x09: return 48; case 0x0d: return 72; case 0x08: return 96; case 0x0c: return 108; } } else panic("%s: unexpected mode %u", __func__, mode); DPRINTF(("unsupported plcp %u\n", plcp)); return 0; } ================================================ FILE: itl80211/openbsd/net80211/ieee80211.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211.h,v 1.62 2019/02/19 08:12:30 stsp Exp $ */ /* $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _NET80211_IEEE80211_H_ #define _NET80211_IEEE80211_H_ /* * 802.11 protocol definitions. */ #include #include #define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ /* is 802.11 address multicast/broadcast? */ #define IEEE80211_IS_MULTICAST(_a) (*(_a) & 0x01) /* * Generic definitions for IEEE 802.11 frames. */ struct ieee80211_frame { u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_addr1[IEEE80211_ADDR_LEN]; u_int8_t i_addr2[IEEE80211_ADDR_LEN]; u_int8_t i_addr3[IEEE80211_ADDR_LEN]; u_int8_t i_seq[2]; } __packed; struct ieee80211_qosframe { u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_addr1[IEEE80211_ADDR_LEN]; u_int8_t i_addr2[IEEE80211_ADDR_LEN]; u_int8_t i_addr3[IEEE80211_ADDR_LEN]; u_int8_t i_seq[2]; u_int8_t i_qos[2]; } __packed; struct ieee80211_htframe { /* 11n */ u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_addr1[IEEE80211_ADDR_LEN]; u_int8_t i_addr2[IEEE80211_ADDR_LEN]; u_int8_t i_addr3[IEEE80211_ADDR_LEN]; u_int8_t i_seq[2]; u_int8_t i_qos[2]; u_int8_t i_ht[4]; } __packed; struct ieee80211_frame_addr4 { u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_addr1[IEEE80211_ADDR_LEN]; u_int8_t i_addr2[IEEE80211_ADDR_LEN]; u_int8_t i_addr3[IEEE80211_ADDR_LEN]; u_int8_t i_seq[2]; u_int8_t i_addr4[IEEE80211_ADDR_LEN]; } __packed; struct ieee80211_qosframe_addr4 { u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_addr1[IEEE80211_ADDR_LEN]; u_int8_t i_addr2[IEEE80211_ADDR_LEN]; u_int8_t i_addr3[IEEE80211_ADDR_LEN]; u_int8_t i_seq[2]; u_int8_t i_addr4[IEEE80211_ADDR_LEN]; u_int8_t i_qos[2]; } __packed; struct ieee80211_htframe_addr4 { /* 11n */ u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_addr1[IEEE80211_ADDR_LEN]; u_int8_t i_addr2[IEEE80211_ADDR_LEN]; u_int8_t i_addr3[IEEE80211_ADDR_LEN]; u_int8_t i_seq[2]; u_int8_t i_addr4[IEEE80211_ADDR_LEN]; u_int8_t i_qos[2]; u_int8_t i_ht[4]; } __packed; /** * enum ieee80211_chan_width - channel width definitions * * @IEEE80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel * @IEEE80211_CHAN_WIDTH_20: 20 MHz HT channel * @IEEE80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 * attribute must be provided as well * @IEEE80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 * attribute must be provided as well * @IEEE80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well * @IEEE80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 * attribute must be provided as well * @IEEE80211_CHAN_WIDTH_5: 5 MHz OFDM channel * @IEEE80211_CHAN_WIDTH_10: 10 MHz OFDM channel * @IEEE80211_CHAN_WIDTH_1: 1 MHz OFDM channel * @IEEE80211_CHAN_WIDTH_2: 2 MHz OFDM channel * @IEEE80211_CHAN_WIDTH_4: 4 MHz OFDM channel * @IEEE80211_CHAN_WIDTH_8: 8 MHz OFDM channel * @IEEE80211_CHAN_WIDTH_16: 16 MHz OFDM channel */ enum ieee80211_chan_width { IEEE80211_CHAN_WIDTH_20_NOHT, IEEE80211_CHAN_WIDTH_20, IEEE80211_CHAN_WIDTH_40, IEEE80211_CHAN_WIDTH_80, IEEE80211_CHAN_WIDTH_80P80, IEEE80211_CHAN_WIDTH_160, IEEE80211_CHAN_WIDTH_5, IEEE80211_CHAN_WIDTH_10, IEEE80211_CHAN_WIDTH_1, IEEE80211_CHAN_WIDTH_2, IEEE80211_CHAN_WIDTH_4, IEEE80211_CHAN_WIDTH_8, IEEE80211_CHAN_WIDTH_16, }; const char * const ieee80211_chan_width_name[] = { "20", "20", "40", "80", "80P80", "160", "5", "10", "1", "2", "4", "8", "16", }; #define IEEE80211_FC0_VERSION_MASK 0x03 #define IEEE80211_FC0_VERSION_SHIFT 0 #define IEEE80211_FC0_VERSION_0 0x00 #define IEEE80211_FC0_TYPE_MASK 0x0c #define IEEE80211_FC0_TYPE_SHIFT 2 #define IEEE80211_FC0_TYPE_MGT 0x00 #define IEEE80211_FC0_TYPE_CTL 0x04 #define IEEE80211_FC0_TYPE_DATA 0x08 #define IEEE80211_FC0_TYPE_ORDER 0x8000 #define IEEE80211_FC0_SUBTYPE_MASK 0xf0 #define IEEE80211_FC0_SUBTYPE_SHIFT 4 /* for TYPE_MGT */ #define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 #define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 #define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 #define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 #define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 #define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 #define IEEE80211_FC0_SUBTYPE_BEACON 0x80 #define IEEE80211_FC0_SUBTYPE_ATIM 0x90 #define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 #define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 #define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 #define IEEE80211_FC0_SUBTYPE_ACTION 0xd0 #define IEEE80211_FC0_SUBTYPE_ACTION_NOACK 0xe0 /* 11n */ /* for TYPE_CTL */ #define IEEE80211_FC0_SUBTYPE_WRAPPER 0x70 /* 11n */ #define IEEE80211_FC0_SUBTYPE_BAR 0x80 #define IEEE80211_FC0_SUBTYPE_BA 0x90 #define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 #define IEEE80211_FC0_SUBTYPE_RTS 0xb0 #define IEEE80211_FC0_SUBTYPE_CTS 0xc0 #define IEEE80211_FC0_SUBTYPE_ACK 0xd0 #define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 #define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 /* for TYPE_DATA (bit combination) */ #define IEEE80211_FC0_SUBTYPE_DATA 0x00 #define IEEE80211_FC0_SUBTYPE_DATA_CF_ACK 0x10 #define IEEE80211_FC0_SUBTYPE_DATA_CF_POLL 0x20 #define IEEE80211_FC0_SUBTYPE_DATA_CF_ACKPOLL 0x30 #define IEEE80211_FC0_SUBTYPE_NODATA 0x40 #define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK 0x50 #define IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL 0x60 #define IEEE80211_FC0_SUBTYPE_NODATA_CF_ACKPOLL 0x70 #define IEEE80211_FC0_SUBTYPE_QOS 0x80 #define IEEE80211_FC1_DIR_MASK 0x03 #define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ #define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ #define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ #define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ #define IEEE80211_FC1_MORE_FRAG 0x04 #define IEEE80211_FC1_RETRY 0x08 #define IEEE80211_FC1_PWR_MGT 0x10 #define IEEE80211_FC1_MORE_DATA 0x20 #define IEEE80211_FC1_PROTECTED 0x40 #define IEEE80211_FC1_WEP 0x40 /* pre-RSNA compat */ #define IEEE80211_FC1_ORDER 0x80 #define IEEE80211_FC1_BITS \ "\20\03MORE_FRAG\04RETRY\05PWR_MGT\06MORE_DATA" \ "\07PROTECTED\08ORDER" /* * Sequence Control field (see 802.11-2012 8.2.4.4). */ #define IEEE80211_SEQ_FRAG_MASK 0x000f #define IEEE80211_SEQ_FRAG_SHIFT 0 #define IEEE80211_SEQ_SEQ_MASK 0xfff0 #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_NWID_LEN 32 #define IEEE80211_MMIE_LEN 18 /* 11w */ /* * QoS Control field (see 802.11-2012 8.2.4.5). */ #define IEEE80211_QOS_TXOP 0xff00 #define IEEE80211_QOS_AMSDU 0x0080 /* 11n */ #define IEEE80211_QOS_ACK_POLICY_NORMAL 0x0000 #define IEEE80211_QOS_ACK_POLICY_NOACK 0x0020 #define IEEE80211_QOS_ACK_POLICY_NOEXPLACK 0x0040 #define IEEE80211_QOS_ACK_POLICY_BA 0x0060 #define IEEE80211_QOS_ACK_POLICY_MASK 0x0060 #define IEEE80211_QOS_ACK_POLICY_SHIFT 5 #define IEEE80211_QOS_EOSP 0x0010 #define IEEE80211_QOS_TID 0x000f /* * Control frames. */ struct ieee80211_frame_min { u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_addr1[IEEE80211_ADDR_LEN]; u_int8_t i_addr2[IEEE80211_ADDR_LEN]; /* FCS */ } __packed; struct ieee80211_frame_rts { u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_ra[IEEE80211_ADDR_LEN]; u_int8_t i_ta[IEEE80211_ADDR_LEN]; /* FCS */ } __packed; struct ieee80211_frame_cts { u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_ra[IEEE80211_ADDR_LEN]; /* FCS */ } __packed; struct ieee80211_frame_ack { u_int8_t i_fc[2]; u_int8_t i_dur[2]; u_int8_t i_ra[IEEE80211_ADDR_LEN]; /* FCS */ } __packed; struct ieee80211_frame_pspoll { u_int8_t i_fc[2]; u_int8_t i_aid[2]; u_int8_t i_bssid[IEEE80211_ADDR_LEN]; u_int8_t i_ta[IEEE80211_ADDR_LEN]; /* FCS */ } __packed; struct ieee80211_frame_cfend { /* NB: also CF-End+CF-Ack */ u_int8_t i_fc[2]; u_int8_t i_dur[2]; /* should be zero */ u_int8_t i_ra[IEEE80211_ADDR_LEN]; u_int8_t i_bssid[IEEE80211_ADDR_LEN]; /* FCS */ } __packed; #ifdef _KERNEL static __inline int ieee80211_has_seq(const struct ieee80211_frame *wh) { return (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL; } static __inline int ieee80211_has_addr4(const struct ieee80211_frame *wh) { return (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS; } static __inline int ieee80211_has_qos(const struct ieee80211_frame *wh) { return (wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS); } static __inline int ieee80211_has_htc(const struct ieee80211_frame *wh) { return (wh->i_fc[1] & IEEE80211_FC1_ORDER) && (ieee80211_has_qos(wh) || (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT); } static __inline u_int16_t ieee80211_get_qos(const struct ieee80211_frame *wh) { const u_int8_t *frm; if (ieee80211_has_addr4(wh)) frm = ((const struct ieee80211_qosframe_addr4 *)wh)->i_qos; else frm = ((const struct ieee80211_qosframe *)wh)->i_qos; return letoh16(*(const u_int16_t *)frm); } static __inline int ieee80211_is_ctl(uint16_t fc) { return (fc & htole16(IEEE80211_FC0_TYPE_MASK)) == htole16(IEEE80211_FC0_TYPE_CTL); } static __inline int ieee80211_is_data(uint16_t fc) { return (fc & htole16(IEEE80211_FC0_TYPE_MASK)) == htole16(IEEE80211_FC0_TYPE_DATA); } static __inline int ieee80211_is_mgmt(uint16_t fc) { return (fc & htole16(IEEE80211_FC0_TYPE_MASK)) == htole16(IEEE80211_FC0_TYPE_MGT); } static __inline int ieee80211_is_data_qos(uint16_t fc) { /* * mask with QOS_DATA rather than IEEE80211_FCTL_STYPE as we just need * to check the one bit */ return (fc & htole16(IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == htole16(IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS); } static __inline int ieee80211_is_qos_nullfunc(const struct ieee80211_frame *wh) { return (wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_CTS); } static __inline int ieee80211_has_order(const struct ieee80211_frame *wh) { return (wh->i_fc[0] & IEEE80211_FC0_TYPE_ORDER) != 0; } #endif /* _KERNEL */ /* * Capability Information field (see 802.11-2012 8.4.1.4). */ #define IEEE80211_CAPINFO_ESS 0x0001 #define IEEE80211_CAPINFO_IBSS 0x0002 #define IEEE80211_CAPINFO_CF_POLLABLE 0x0004 #define IEEE80211_CAPINFO_CF_POLLREQ 0x0008 #define IEEE80211_CAPINFO_PRIVACY 0x0010 #define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020 #define IEEE80211_CAPINFO_PBCC 0x0040 #define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080 #define IEEE80211_CAPINFO_SPECTRUM_MGMT 0x0100 #define IEEE80211_CAPINFO_QOS 0x0200 #define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400 #define IEEE80211_CAPINFO_APSD 0x0800 #define IEEE80211_CAPINFO_RADIO_MEASUREMENT 0x1000 #define IEEE80211_CAPINFO_DSSSOFDM 0x2000 #define IEEE80211_CAPINFO_DELAYED_B_ACK 0x4000 #define IEEE80211_CAPINFO_IMMEDIATE_B_ACK 0x8000 #define IEEE80211_CAPINFO_BITS \ "\10\01ESS\02IBSS\03CF_POLLABLE\04CF_POLLREQ" \ "\05PRIVACY\06SHORT_PREAMBLE\07PBCC\10CHNL_AGILITY" \ "\11SPECTRUM_MGMT\12QOS\13SHORT_SLOTTIME\14APSD" \ "\15RADIO_MEASUREMENT\16DSSSOFDM\17DELAYED_B_ACK\20IMMEDIATE_B_ACK" /* * Information element IDs (see 802.11-2012 Table 8.4.2). */ enum { IEEE80211_ELEMID_SSID = 0, IEEE80211_ELEMID_RATES = 1, IEEE80211_ELEMID_FHPARMS = 2, IEEE80211_ELEMID_DSPARMS = 3, IEEE80211_ELEMID_CFPARMS = 4, IEEE80211_ELEMID_TIM = 5, IEEE80211_ELEMID_IBSSPARMS = 6, IEEE80211_ELEMID_COUNTRY = 7, IEEE80211_ELEMID_HOPPING_PARMS = 8, IEEE80211_ELEMID_HOPPING_PATTERN = 9, IEEE80211_ELEMID_REQUEST = 10, IEEE80211_ELEMID_QBSS_LOAD = 11, IEEE80211_ELEMID_EDCAPARMS = 12, IEEE80211_ELEMID_TSPEC = 13, IEEE80211_ELEMID_TCLASS = 14, IEEE80211_ELEMID_SCHEDULE = 15, IEEE80211_ELEMID_CHALLENGE = 16, /* 17-31 reserved for challenge text extension */ IEEE80211_ELEMID_POWER_CONSTRAINT = 32, IEEE80211_ELEMID_POWER_CAP = 33, IEEE80211_ELEMID_TPC_REQUEST = 34, IEEE80211_ELEMID_TPC_REPORT = 35, IEEE80211_ELEMID_SUPP_CHNLS = 35, IEEE80211_ELEMID_CSA = 37, /* 11h */ IEEE80211_ELEMID_MEASUREMENT_REQUEST = 38, /* DFS */ IEEE80211_ELEMID_MEASUREMENT_REPORT = 39, /* DFS */ IEEE80211_ELEMID_QUIET = 40, IEEE80211_ELEMID_IBSS_DFS = 41, IEEE80211_ELEMID_ERP = 42, IEEE80211_ELEMID_TS_DELAY = 43, IEEE80211_ELEMID_TCLAS = 44, IEEE80211_ELEMID_HTCAPS = 45, /* 11n */ IEEE80211_ELEMID_QOS_CAP = 46, /* 47 reserved for Broadcom */ IEEE80211_ELEMID_RSN = 48, IEEE80211_ELEMID_802_15_COEX = 49, IEEE80211_ELEMID_XRATES = 50, IEEE80211_ELEMID_AP_CHNL_REPORT = 51, IEEE80211_ELEMID_NBR_REPORT = 52, IEEE80211_ELEMID_RCPI = 53, IEEE80211_ELEMID_MDE = 54, IEEE80211_ELEMID_FTE = 55, IEEE80211_ELEMID_TIE = 56, /* 11r */ IEEE80211_ELEMID_RDE = 57, IEEE80211_ELEMID_DSE = 58, IEEE80211_ELEMID_SUPP_OPCLASS = 59, IEEE80211_ELEMID_XCSA = 60, IEEE80211_ELEMID_HTOP = 61, /* 11n */ IEEE80211_ELEMID_SECONDARY_CHANL_OFFSET = 62, /* 11n */ IEEE80211_ELEMID_AVG_ACCESS_DELAY = 63, IEEE80211_ELEMID_ANTENNA = 64, IEEE80211_ELEMID_RSNI = 65, IEEE80211_ELEMID_MEASUREMENT_PILOT_TX = 66, IEEE80211_ELEMID_AVAIL_CAPACITY = 67, IEEE80211_ELEMID_AC_ACCESS_DELAY = 68, IEEE80211_ELEMID_TIME_ADVERT = 69, IEEE80211_ELEMID_RM = 70, IEEE80211_ELEMID_MULTI_BSSID = 71, IEEE80211_ELEMID_20_40_CBW_COEX = 72, /* 11n */ IEEE80211_ELEMID_20_40_CBW_INTOLERANT = 73, /* 11n */ IEEE80211_ELEMID_SCAN_PARAM_OVERLAP = 74, IEEE80211_ELEMID_RIC = 75, IEEE80211_ELEMID_MMIE = 76, /* 11w */ IEEE80211_ELEMID_EVENT_REQUEST = 78, IEEE80211_ELEMID_EVENT_REPORT = 79, IEEE80211_ELEMID_DIAG_REQUEST = 80, IEEE80211_ELEMID_DIAG_REPORT = 81, IEEE80211_ELEMID_LOCATION_PARMS = 82, IEEE80211_ELEMID_NONTX_BSSID = 83, IEEE80211_ELEMID_SSID_LIST = 84, IEEE80211_ELEMID_MULTI_BSSID_IDX = 85, IEEE80211_ELEMID_FMS_DESC = 86, IEEE80211_ELEMID_FMS_REQUEST = 87, IEEE80211_ELEMID_FMS_RESPONSE = 88, IEEE80211_ELEMID_QOS_TRAFFIC_CAP = 89, IEEE80211_ELEMID_MAX_IDLE_PERIOD = 90, IEEE80211_ELEMID_TFS_REQUEST = 91, IEEE80211_ELEMID_TFS_RESPONSE = 92, IEEE80211_ELEMID_WNM_SLEEP = 93, IEEE80211_ELEMID_TIM_BCAST_REQUEST = 94, IEEE80211_ELEMID_TIM_BCAST_RESPONSE = 95, IEEE80211_ELEMID_INTERFERENCE_REPORT = 96, IEEE80211_ELEMID_CHNL_USAGE = 97, IEEE80211_ELEMID_TIME_ZONE = 98, IEEE80211_ELEMID_DMS_REQUEST = 99, IEEE80211_ELEMID_DMS_RESPONSE = 100, IEEE80211_ELEMID_LINK_ID = 101, IEEE80211_ELEMID_WAKE_SCHED = 102, /* 103 undefined */ IEEE80211_ELEMID_CHNL_SWITCH_TIMING = 104, IEEE80211_ELEMID_PTI_CTRL = 105, IEEE80211_ELEMID_TPU_BUF_STATUS = 106, IEEE80211_ELEMID_INTERWORKING = 107, IEEE80211_ELEMID_ADVERT_PROTOCOL = 108, IEEE80211_ELEMID_EXPEDITED_BW_REQUEST = 109, IEEE80211_ELEMID_QOS_MAP_SET = 110, IEEE80211_ELEMID_ROAMING_CONSORTIUM = 111, IEEE80211_ELEMID_EMERGENCY_ALERT_ID = 112, IEEE80211_ELEMID_MESHCONF = 113, IEEE80211_ELEMID_MESHID = 114, IEEE80211_ELEMID_MESHLINK = 115, IEEE80211_ELEMID_MESHCNGST = 116, IEEE80211_ELEMID_MESHPEER = 117, IEEE80211_ELEMID_MESHCSA = 118, IEEE80211_ELEMID_MESHAWAKEW = 119, IEEE80211_ELEMID_MESHBEACONT = 120, IEEE80211_ELEMID_MCCAOP_SETUP_REQUEST = 121, IEEE80211_ELEMID_MCCAOP_SETUP_REPLY = 122, IEEE80211_ELEMID_MCCAOP_ADVERT = 123, IEEE80211_ELEMID_MCCAOP_TEARDOWN = 124, IEEE80211_ELEMID_MESHGANN = 125, IEEE80211_ELEMID_MESHRANN = 126, IEEE80211_ELEMID_XCAPS = 127, /* 128-129 reserved for Agere */ IEEE80211_ELEMID_MESHPREQ = 130, IEEE80211_ELEMID_MESHPREP = 131, IEEE80211_ELEMID_MESHPERR = 132, /* 133-136 reserved for Cisco */ IEEE80211_ELEMID_MESHPXU = 137, IEEE80211_ELEMID_MESHPXUC = 138, IEEE80211_ELEMID_AUTH_MESH_PEERING_XCHG = 139, IEEE80211_ELEMID_MIC = 140, IEEE80211_ELEMID_DEST_URI = 141, IEEE80211_ELEMID_U_APSD_COEX = 142, /* 143-174 reserved */ IEEE80211_ELEMID_WAKEUP_SCHEDULE = 143, IEEE80211_ELEMID_EXT_SCHEDULE = 144, IEEE80211_ELEMID_STA_AVAILABILITY = 145, IEEE80211_ELEMID_DMG_TSPEC = 146, IEEE80211_ELEMID_DMG_AT = 147, IEEE80211_ELEMID_DMG_CAP = 148, /* 149 reserved for Cisco */ IEEE80211_ELEMID_CISCO_VENDOR_SPECIFIC = 150, IEEE80211_ELEMID_DMG_OPERATION = 151, IEEE80211_ELEMID_DMG_BSS_PARAM_CHANGE = 152, IEEE80211_ELEMID_DMG_BEAM_REFINEMENT = 153, IEEE80211_ELEMID_CHANNEL_MEASURE_FEEDBACK = 154, /* 155-156 reserved for Cisco */ IEEE80211_ELEMID_AWAKE_WINDOW = 157, IEEE80211_ELEMID_MULTI_BAND = 158, IEEE80211_ELEMID_ADDBA_EXT = 159, IEEE80211_ELEMID_NEXT_PCP_LIST = 160, IEEE80211_ELEMID_PCP_HANDOVER = 161, IEEE80211_ELEMID_DMG_LINK_MARGIN = 162, IEEE80211_ELEMID_SWITCHING_STREAM = 163, IEEE80211_ELEMID_SESSION_TRANSITION = 164, IEEE80211_ELEMID_DYN_TONE_PAIRING_REPORT = 165, IEEE80211_ELEMID_CLUSTER_REPORT = 166, IEEE80211_ELEMID_RELAY_CAP = 167, IEEE80211_ELEMID_RELAY_XFER_PARAM_SET = 168, IEEE80211_ELEMID_BEAM_LINK_MAINT = 169, IEEE80211_ELEMID_MULTIPLE_MAC_ADDR = 170, IEEE80211_ELEMID_U_PID = 171, IEEE80211_ELEMID_DMG_LINK_ADAPT_ACK = 172, /* 173 reserved for Symbol */ IEEE80211_ELEMID_MCCAOP_ADVERT_OVIEW = 174, IEEE80211_ELEMID_QUIET_PERIOD_REQ = 175, /* 176 reserved for Symbol */ IEEE80211_ELEMID_QUIET_PERIOD_RESP = 177, /* 178-179 reserved for Symbol */ /* 180 reserved for ISO/IEC 20011 */ IEEE80211_ELEMID_EPAC_POLICY = 182, IEEE80211_ELEMID_CLISTER_TIME_OFF = 183, IEEE80211_ELEMID_INTER_AC_PRIO = 184, IEEE80211_ELEMID_SCS_DESCRIPTOR = 185, IEEE80211_ELEMID_QLOAD_REPORT = 186, IEEE80211_ELEMID_HCCA_TXOP_UPDATE_COUNT = 187, IEEE80211_ELEMID_HL_STREAM_ID = 188, IEEE80211_ELEMID_GCR_GROUP_ADDR = 189, IEEE80211_ELEMID_ANTENNA_SECTOR_ID_PATTERN = 190, /* 802.11ac */ IEEE80211_ELEMID_VHT_CAP = 191, IEEE80211_ELEMID_VHT_OPMODE = 192, IEEE80211_ELEMID_EXTENDED_BSS_LOAD = 193, IEEE80211_ELEMID_WIDE_BW_CHANNEL_SWITCH = 194, IEEE80211_ELEMID_VHT_PWR_ENV = 195, IEEE80211_ELEMID_CHANNEL_SWITCH_WRAPPER = 196, IEEE80211_ELEMID_AID = 197, IEEE80211_ELEMID_QUIET_CHANNEL = 198, IEEE80211_ELEMID_OPMODE_NOTIF = 199, IEEE80211_ELEMID_VENDOR = 221, /* vendor private */ IEEE80211_ELEMID_QOS_PARAMETER = 222, IEEE80211_ELEMID_CAG_NUMBER = 237, IEEE80211_ELEMID_AP_CSN = 239, IEEE80211_ELEMID_FILS_INDICATION = 240, IEEE80211_ELEMID_DILS = 241, IEEE80211_ELEMID_FRAGMENT = 242, IEEE80211_ELEMID_EXTENSION = 255, }; /* Element ID Extensions for Element ID 255 */ enum ieee80211_eid_ext { IEEE80211_ELEMID_EXT_ASSOC_DELAY_INFO = 1, IEEE80211_ELEMID_EXT_FILS_REQ_PARAMS = 2, IEEE80211_ELEMID_EXT_FILS_KEY_CONFIRM = 3, IEEE80211_ELEMID_EXT_FILS_SESSION = 4, IEEE80211_ELEMID_EXT_FILS_HLP_CONTAINER = 5, IEEE80211_ELEMID_EXT_FILS_IP_ADDR_ASSIGN = 6, IEEE80211_ELEMID_EXT_KEY_DELIVERY = 7, IEEE80211_ELEMID_EXT_FILS_WRAPPED_DATA = 8, IEEE80211_ELEMID_EXT_FILS_PUBLIC_KEY = 12, IEEE80211_ELEMID_EXT_FILS_NONCE = 13, IEEE80211_ELEMID_EXT_FUTURE_CHAN_GUIDANCE = 14, IEEE80211_ELEMID_EXT_HE_CAPABILITY = 35, IEEE80211_ELEMID_EXT_HE_OPERATION = 36, IEEE80211_ELEMID_EXT_UORA = 37, IEEE80211_ELEMID_EXT_HE_MU_EDCA = 38, IEEE80211_ELEMID_EXT_HE_SPR = 39, IEEE80211_ELEMID_EXT_NDP_FEEDBACK_REPORT_PARAMSET = 41, IEEE80211_ELEMID_EXT_BSS_COLOR_CHG_ANN = 42, IEEE80211_ELEMID_EXT_QUIET_TIME_PERIOD_SETUP = 43, IEEE80211_ELEMID_EXT_ESS_REPORT = 45, IEEE80211_ELEMID_EXT_OPS = 46, IEEE80211_ELEMID_EXT_HE_BSS_LOAD = 47, IEEE80211_ELEMID_EXT_MAX_CHANNEL_SWITCH_TIME = 52, IEEE80211_ELEMID_EXT_MULTIPLE_BSSID_CONFIGURATION = 55, IEEE80211_ELEMID_EXT_NON_INHERITANCE = 56, IEEE80211_ELEMID_EXT_KNOWN_BSSID = 57, IEEE80211_ELEMID_EXT_SHORT_SSID_LIST = 58, IEEE80211_ELEMID_EXT_HE_6GHZ_CAPA = 59, IEEE80211_ELEMID_EXT_UL_MU_POWER_CAPA = 60, }; /* * Action field category values (see 802.11-2012 8.4.1.11 Table 8-38). */ enum { IEEE80211_CATEG_SPECTRUM = 0, IEEE80211_CATEG_QOS = 1, IEEE80211_CATEG_DLS = 2, IEEE80211_CATEG_BA = 3, IEEE80211_CATEG_PUB = 4, IEEE80211_CATEG_RADIO_MSRMNT = 5, IEEE80211_CATEG_FAST_BSS_TRANS = 6, IEEE80211_CATEG_HT = 7, /* 11n */ IEEE80211_CATEG_SA_QUERY = 8, /* 11w */ IEEE80211_CATEG_PROT_DUAL_PUBLIC_ACTION = 9, IEEE80211_CATEG_WNM = 10, IEEE80211_CATEG_UNPROT_WNM = 11, IEEE80211_CATEG_TDLS = 12, IEEE80211_CATEG_MESH = 13, IEEE80211_CATEG_MULTIHOP = 14, IEEE80211_CATEG_SELF_PROT = 15, /* 16-125 reserved */ IEEE80211_CATEG_PROT_VENDOR = 126, IEEE80211_CATEG_VENDOR = 127 /* 128-255 error */ }; /* * Block Ack Action field values (see 802.11-2012 8.5.5 Table 8-202). */ #define IEEE80211_ACTION_ADDBA_REQ 0 #define IEEE80211_ACTION_ADDBA_RESP 1 #define IEEE80211_ACTION_DELBA 2 /* 3-255 reserved */ /* * SA Query Action field values (see 802.11-2012 8.5.10 Table 8-227). */ #define IEEE80211_ACTION_SA_QUERY_REQ 0 #define IEEE80211_ACTION_SA_QUERY_RESP 1 /* * HT Action field values (see 802.11-2012 8.5.12 Table 8-229). */ #define IEEE80211_ACTION_NOTIFYCW 0 #define IEEE80211_ACTION_SM_PWRSAVE 1 #define IEEE80211_ACTION_PSMP 2 #define IEEE80211_ACTION_SET_PCO_PHASE 3 #define IEEE80211_ACTION_CSI 4 #define IEEE80211_ACTION_NONCOMPRESSED_BF 5 #define IEEE80211_ACTION_COMPRESSED_BF 6 #define IEEE80211_ACTION_ASEL_IDX_FEEDBACK 7 /* 8-255 reserved */ #define IEEE80211_RATE_BASIC 0x80 #define IEEE80211_RATE_VAL 0x7f #define IEEE80211_RATE_SIZE 8 /* 802.11 standard */ #define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */ #define IEEE80211_HT_NUM_MCS 77 #define IEEE80211_VHT_NUM_MCS 10 /* * BlockAck/BlockAckReq Control field (see 802.11-2012 8.3.1.9 Figure 8-25). */ #define IEEE80211_BA_ACK_POLICY 0x0001 #define IEEE80211_BA_MULTI_TID 0x0002 #define IEEE80211_BA_COMPRESSED 0x0004 #define IEEE80211_BA_TID_INFO_MASK 0xf000 #define IEEE80211_BA_TID_INFO_SHIFT 12 /* * ADDBA Parameter Set field (see 802.11-2012 8.4.1.14 Figure 8-48). */ #define IEEE80211_ADDBA_AMSDU 0x0001 /* A-MSDU in A-MPDU supported */ #define IEEE80211_ADDBA_BA_POLICY 0x0002 /* 1=immediate BA 0=delayed BA */ #define IEEE80211_ADDBA_TID_MASK 0x003c #define IEEE80211_ADDBA_TID_SHIFT 2 #define IEEE80211_ADDBA_BUFSZ_MASK 0xffc0 #define IEEE80211_ADDBA_BUFSZ_SHIFT 6 /* * DELBA Parameter Set field (see 802.11-2012 8.4.1.16 Figure 8-50). */ #define IEEE80211_DELBA_INITIATOR 0x0800 #define IEEE80211_DELBA_TID_INFO_MASK 0xf000 #define IEEE80211_DELBA_TID_INFO_SHIFT 12 /* * ERP information element parameters (see 802.11-2012 8.4.2.14 Figure 8-95). */ #define IEEE80211_ERP_NON_ERP_PRESENT 0x01 #define IEEE80211_ERP_USE_PROTECTION 0x02 #define IEEE80211_ERP_BARKER_MODE 0x04 /* * RSN capabilities (see 802.11-2012 8.4.2.27.4). */ #define IEEE80211_RSNCAP_PREAUTH 0x0001 #define IEEE80211_RSNCAP_NOPAIRWISE 0x0002 #define IEEE80211_RSNCAP_PTKSA_RCNT_MASK 0x000c #define IEEE80211_RSNCAP_PTKSA_RCNT_SHIFT 2 #define IEEE80211_RSNCAP_GTKSA_RCNT_MASK 0x0030 #define IEEE80211_RSNCAP_GTKSA_RCNT_SHIFT 4 #define IEEE80211_RSNCAP_RCNT1 0 #define IEEE80211_RSNCAP_RCNT2 1 #define IEEE80211_RSNCAP_RCNT4 2 #define IEEE80211_RSNCAP_RCNT16 3 #define IEEE80211_RSNCAP_MFPR 0x0040 /* 11w */ #define IEEE80211_RSNCAP_MFPC 0x0080 /* 11w */ #define IEEE80211_RSNCAP_PEERKEYENA 0x0200 #define IEEE80211_RSNCAP_SPPAMSDUC 0x0400 /* 11n */ #define IEEE80211_RSNCAP_SPPAMSDUR 0x0800 /* 11n */ #define IEEE80211_RSNCAP_PBAC 0x1000 /* 11n */ #define IEEE80211_RSNCAP_EXTENDED_KEYID 0x2000 /* * HT Capabilities Info (see 802.11-2012 8.4.2.58.2). */ #define IEEE80211_HTCAP_LDPC 0x00000001 #define IEEE80211_HTCAP_CBW20_40 0x00000002 #define IEEE80211_HTCAP_SMPS_MASK 0x0000000c #define IEEE80211_HTCAP_SMPS_SHIFT 2 #define IEEE80211_HTCAP_SMPS_STA 0 #define IEEE80211_HTCAP_SMPS_DYN 1 #define IEEE80211_HTCAP_SMPS_DIS 3 #define IEEE80211_HTCAP_GF 0x00000010 #define IEEE80211_HTCAP_SGI20 0x00000020 #define IEEE80211_HTCAP_SGI40 0x00000040 #define IEEE80211_HTCAP_TXSTBC 0x00000080 #define IEEE80211_HTCAP_RXSTBC_MASK 0x00000300 #define IEEE80211_HTCAP_RXSTBC_SHIFT 8 #define IEEE80211_HTCAP_DELAYEDBA 0x00000400 #define IEEE80211_HTCAP_AMSDU7935 0x00000800 #define IEEE80211_HTCAP_DSSSCCK40 0x00001000 #define IEEE80211_HTCAP_PSMP 0x00002000 #define IEEE80211_HTCAP_40INTOLERANT 0x00004000 #define IEEE80211_HTCAP_LSIGTXOPPROT 0x00008000 /* * HT A-MPDU parameters (see 802.11-2012 8.4.2.58.3). */ #define IEEE80211_AMPDU_PARAM_LE 0x03 #define IEEE80211_AMPDU_PARAM_SS 0x1c #define IEEE80211_AMPDU_PARAM_SS_NONE (0 << 2) #define IEEE80211_AMPDU_PARAM_SS_0_25 (1 << 2) #define IEEE80211_AMPDU_PARAM_SS_0_5 (2 << 2) #define IEEE80211_AMPDU_PARAM_SS_1 (3 << 2) #define IEEE80211_AMPDU_PARAM_SS_2 (4 << 2) #define IEEE80211_AMPDU_PARAM_SS_4 (5 << 2) #define IEEE80211_AMPDU_PARAM_SS_8 (6 << 2) #define IEEE80211_AMPDU_PARAM_SS_16 (7 << 2) /* bits 5-7 reserved */ /* * HT Supported MCS Set (see 802.11-2012 8.4.2.58.4). * This field is 16 bytes in size. Bitmasks given below * operate on 8 or 16 bit integer subsets of this field * for use with ieee80211com and ieee80211_node. */ /* Bits 0-76: Supported Rx MCS bitmask */ /* Bits 77-79: Reserved */ /* Bits 80-89: Highest Rx rate in units of 1MB/s */ #define IEEE80211_MCS_RX_RATE_HIGH 0x03ff /* Bits 90-95: Reserved */ /* Bits 96-100: Tx MCS set */ #define IEEE80211_TX_MCS_SET_DEFINED 0x01 #define IEEE80211_TX_RX_MCS_NOT_EQUAL 0x02 #define IEEE80211_TX_SPATIAL_STREAMS 0x0c #define IEEE80211_TX_UNEQUAL_MODULATION 0x10 /* Bits 101-127: Reserved */ /* * HT Extended Capabilities (see 802.11-2012 8.4.2.58.5). */ #define IEEE80211_HTXCAP_PCO 0x0001 #define IEEE80211_HTXCAP_PCOTT_MASK 0x0006 #define IEEE80211_HTXCAP_PCOTT_SHIFT 1 #define IEEE80211_HTXCAP_PCOTT_400 1 #define IEEE80211_HTXCAP_PCOTT_1500 2 #define IEEE80211_HTXCAP_PCOTT_5000 3 /* Bits 3-7 are reserved. */ #define IEEE80211_HTXCAP_MFB_MASK 0x0300 #define IEEE80211_HTXCAP_MFB_SHIFT 8 #define IEEE80211_HTXCAP_MFB_NONE 0 #define IEEE80211_HTXCAP_MFB_UNSOL 2 #define IEEE80211_HTXCAP_MFB_BOTH 3 #define IEEE80211_HTXCAP_HTC 0x0400 #define IEEE80211_HTXCAP_RDRESP 0x0800 /* Bits 12-15 are reserved. */ /* * Transmit Beamforming (TxBF) Capabilities (see 802.11-2012 8.4.2.58.6). */ #define IEEE80211_TXBFCAP_IMPLICIT_RX 0x00000001 #define IEEE80211_TXBFCAP_RSSC 0x00000002 #define IEEE80211_TXBFCAP_TSSC 0x00000004 #define IEEE80211_TXBFCAP_RNDP 0x00000008 #define IEEE80211_TXBFCAP_TNDP 0x00000010 #define IEEE80211_TXBFCAP_IMPLICIT_TX 0x00000020 #define IEEE80211_TXBFCAP_CALIB_MASK 0x000000c0 #define IEEE80211_TXBFCAP_CALIB_SHIFT 6 #define IEEE80211_TXBFCAP_TX_CSI 0x00000100 #define IEEE80211_TXBFCAP_EXPLICIT_NSC 0x00000200 #define IEEE80211_TXBFCAP_EXPLICIT_CSC 0x00000400 #define IEEE80211_TXBFCAP_CSI_FB_DELAYED 0x00000800 #define IEEE80211_TXBFCAP_CSI_FB_IMMEDIATE 0x00001000 #define IEEE80211_TXBFCAP_EXPLICIT_NB_FB_DELAYED 0x00002000 #define IEEE80211_TXBFCAP_EXPLICIT_NB_FB_IMMEDIATE 0x00004000 #define IEEE80211_TXBFCAP_EXPLICIT_CB_FB_DELAYED 0x00008000 #define IEEE80211_TXBFCAP_EXPLICIT_CB_FB_IMMEDIATE 0x00010000 #define IEEE80211_TXBFCAP_MINIMAL_GROUPING_1_2 0x00020000 #define IEEE80211_TXBFCAP_MINIMAL_GROUPING_1_4 0x00040000 #define IEEE80211_TXBFCAP_CSI_NUM_ANT_MASK 0x00180000 #define IEEE80211_TXBFCAP_CSI_NUM_ANT_SHIFT 19 #define IEEE80211_TXBFCAP_NS_NUM_ANT_MASK 0x00600000 #define IEEE80211_TXBFCAP_NS_NUM_ANT_SHIFT 21 #define IEEE80211_TXBFCAP_CS_NUM_ANT_MASK 0x01800000 #define IEEE80211_TXBFCAP_CS_NUM_ANT_SHIFT 23 #define IEEE80211_TXBFCAP_CSI_NUM_ROWS_MASK 0x06000000 #define IEEE80211_TXBFCAP_CSI_NUM_ROWS_SHIFT 25 #define IEEE80211_TXBFCAP_CHANL_ESTIMATE_MASK 0x18000000 #define IEEE80211_TXBFCAP_CHANL_ESTIMATE_SHIFT 27 /* * Antenna Selection (ASEL) Capability (see 802.11-2012 8.4.2.58.7). */ #define IEEE80211_ASELCAP_ASEL 0x01 #define IEEE80211_ASELCAP_CSIFB_TX 0x02 #define IEEE80211_ASELCAP_ANT_IDX_FB_TX 0x04 #define IEEE80211_ASELCAP_CSIFB 0x08 #define IEEE80211_ASELCAP_ANT_IDX_FB 0x10 #define IEEE80211_ASELCAP_ASEL_RX 0x20 #define IEEE80211_ASELCAP_TX_SOUND_PPDU 0x20 /* Bit 7 is reserved. */ /* * HT Operation element (see 802.11-2012 8.4.2.59). */ /* Byte 0 contains primary channel number. */ /* Byte 1. */ #define IEEE80211_HTOP0_SCO_MASK 0x03 #define IEEE80211_HTOP0_SCO_SHIFT 0 #define IEEE80211_HTOP0_SCO_SCN 0 #define IEEE80211_HTOP0_SCO_SCA 1 #define IEEE80211_HTOP0_SCO_SCB 3 #define IEEE80211_HTOP0_CHW 0x04 #define IEEE80211_HTOP0_RIFS 0x08 /* bits 4-7 reserved */ /* Bytes 2-3. */ #define IEEE80211_HTOP1_PROT_MASK 0x0003 #define IEEE80211_HTOP1_PROT_SHIFT 0 #define IEEE80211_HTOP1_NONGF_STA 0x0004 /* Bit 3 is reserved. */ #define IEEE80211_HTOP1_OBSS_NONHT_STA 0x0010 /* Bits 5-15 are reserved. */ #define IEEE80211_HT_OP_MODE_CCFS2_SHIFT 5 #define IEEE80211_HT_OP_MODE_CCFS2_MASK 0x1fe0 /* Bytes 4-5. */ /* Bits 0-5 are reserved. */ #define IEEE80211_HTOP2_DUALBEACON 0x0040 #define IEEE80211_HTOP2_DUALCTSPROT 0x0080 #define IEEE80211_HTOP2_STBCBEACON 0x0100 #define IEEE80211_HTOP2_LSIGTXOP 0x0200 #define IEEE80211_HTOP2_PCOACTIVE 0x0400 #define IEEE80211_HTOP2_PCOPHASE40 0x0800 /* Bits 12-15 are reserved. */ /* * EDCA Access Categories. */ enum ieee80211_edca_ac { EDCA_AC_BK = 1, /* Background */ EDCA_AC_BE = 0, /* Best Effort */ EDCA_AC_VI = 2, /* Video */ EDCA_AC_VO = 3 /* Voice */ }; #define EDCA_NUM_AC 4 /* number of TID values (traffic identifier) */ #define IEEE80211_NUM_TID 16 /* Atheros private advanced capabilities info */ #define ATHEROS_CAP_TURBO_PRIME 0x01 #define ATHEROS_CAP_COMPRESSION 0x02 #define ATHEROS_CAP_FAST_FRAME 0x04 /* bits 3-6 reserved */ #define ATHEROS_CAP_BOOST 0x80 /*- * Organizationally Unique Identifiers. * See http://standards.ieee.org/regauth/oui/oui.txt for a list. */ #define ATHEROS_OUI ((const u_int8_t[]){ 0x00, 0x03, 0x7f }) #define BROADCOM_OUI ((const u_int8_t[]){ 0x00, 0x90, 0x4c }) #define IEEE80211_OUI ((const u_int8_t[]){ 0x00, 0x0f, 0xac }) #define MICROSOFT_OUI ((const u_int8_t[]){ 0x00, 0x50, 0xf2 }) #define IEEE80211_AUTH_ALGORITHM(auth) \ ((auth)[0] | ((auth)[1] << 8)) #define IEEE80211_AUTH_TRANSACTION(auth) \ ((auth)[2] | ((auth)[3] << 8)) #define IEEE80211_AUTH_STATUS(auth) \ ((auth)[4] | ((auth)[5] << 8)) /* * Authentication Algorithm Number field (see 7.3.1.1). */ #define IEEE80211_AUTH_ALG_OPEN 0x0000 #define IEEE80211_AUTH_ALG_SHARED 0x0001 #define IEEE80211_AUTH_ALG_LEAP 0x0080 /* * 802.11n HT Capability IE * NB: these reflect D1.10 */ struct ieee80211_ie_htcap { uint8_t hc_id; /* element ID */ uint8_t hc_len; /* length in bytes */ uint16_t hc_cap; /* HT caps (see below) */ uint8_t hc_param; /* HT params (see below) */ uint8_t hc_mcsset[16]; /* supported MCS set */ uint16_t hc_extcap; /* extended HT capabilities */ uint32_t hc_txbf; /* txbf capabilities */ uint8_t hc_antenna; /* antenna capabilities */ } __packed; /* * Authentication Transaction Sequence Number field (see 7.3.1.2). */ enum { IEEE80211_AUTH_OPEN_REQUEST = 1, IEEE80211_AUTH_OPEN_RESPONSE = 2 }; enum { IEEE80211_AUTH_SHARED_REQUEST = 1, IEEE80211_AUTH_SHARED_CHALLENGE = 2, IEEE80211_AUTH_SHARED_RESPONSE = 3, IEEE80211_AUTH_SHARED_PASS = 4 }; /* * Reason codes (see Table 22). */ enum { IEEE80211_REASON_UNSPECIFIED = 1, IEEE80211_REASON_AUTH_EXPIRE = 2, IEEE80211_REASON_AUTH_LEAVE = 3, IEEE80211_REASON_ASSOC_EXPIRE = 4, IEEE80211_REASON_ASSOC_TOOMANY = 5, IEEE80211_REASON_NOT_AUTHED = 6, IEEE80211_REASON_NOT_ASSOCED = 7, IEEE80211_REASON_ASSOC_LEAVE = 8, IEEE80211_REASON_ASSOC_NOT_AUTHED = 9, /* XXX the following two reason codes are not correct */ IEEE80211_REASON_RSN_REQUIRED = 11, IEEE80211_REASON_RSN_INCONSISTENT = 12, IEEE80211_REASON_IE_INVALID = 13, IEEE80211_REASON_MIC_FAILURE = 14, IEEE80211_REASON_4WAY_TIMEOUT = 15, IEEE80211_REASON_GROUP_TIMEOUT = 16, IEEE80211_REASON_RSN_DIFFERENT_IE = 17, IEEE80211_REASON_BAD_GROUP_CIPHER = 18, IEEE80211_REASON_BAD_PAIRWISE_CIPHER = 19, IEEE80211_REASON_BAD_AKMP = 20, IEEE80211_REASON_RSN_IE_VER_UNSUP = 21, IEEE80211_REASON_RSN_IE_BAD_CAP = 22, IEEE80211_REASON_CIPHER_REJ_POLICY = 24, IEEE80211_REASON_SETUP_REQUIRED = 38, IEEE80211_REASON_TIMEOUT = 39 }; /* * Status codes (see Table 23). */ enum { IEEE80211_STATUS_SUCCESS = 0, IEEE80211_STATUS_UNSPECIFIED = 1, IEEE80211_STATUS_CAPINFO = 10, IEEE80211_STATUS_NOT_ASSOCED = 11, IEEE80211_STATUS_OTHER = 12, IEEE80211_STATUS_ALG = 13, IEEE80211_STATUS_SEQUENCE = 14, IEEE80211_STATUS_CHALLENGE = 15, IEEE80211_STATUS_TIMEOUT = 16, IEEE80211_STATUS_TOOMANY = 17, IEEE80211_STATUS_BASIC_RATE = 18, IEEE80211_STATUS_SP_REQUIRED = 19, IEEE80211_STATUS_PBCC_REQUIRED = 20, IEEE80211_STATUS_CA_REQUIRED = 21, IEEE80211_STATUS_TOO_MANY_STATIONS = 22, IEEE80211_STATUS_RATES = 23, IEEE80211_STATUS_SHORTSLOT_REQUIRED = 25, IEEE80211_STATUS_DSSSOFDM_REQUIRED = 26, IEEE80211_STATUS_TRY_AGAIN_LATER = 30, IEEE80211_STATUS_MFP_POLICY = 31, IEEE80211_STATUS_REFUSED = 37, IEEE80211_STATUS_INVALID_PARAM = 38, IEEE80211_STATUS_IE_INVALID = 40, IEEE80211_STATUS_BAD_GROUP_CIPHER = 41, IEEE80211_STATUS_BAD_PAIRWISE_CIPHER = 42, IEEE80211_STATUS_BAD_AKMP = 43, IEEE80211_STATUS_RSN_IE_VER_UNSUP = 44, IEEE80211_STATUS_CIPHER_REJ_POLICY = 46 }; #define IEEE80211_WEP_KEYLEN 5 /* 40bit */ #define IEEE80211_WEP_NKID 4 /* number of key ids */ #define IEEE80211_CHALLENGE_LEN 128 /* WEP header constants */ #define IEEE80211_WEP_IVLEN 3 /* 24bit */ #define IEEE80211_WEP_KIDLEN 1 /* 1 octet */ #define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */ #define IEEE80211_CRC_LEN 4 #define IEEE80211_WEP_TOTLEN (IEEE80211_WEP_IVLEN + \ IEEE80211_WEP_KIDLEN + \ IEEE80211_WEP_CRCLEN) /* * 802.11i defines an extended IV for use with non-WEP ciphers. * When the EXTIV bit is set in the key id byte an additional * 4 bytes immediately follow the IV for TKIP. For CCMP the * EXTIV bit is likewise set but the 8 bytes represent the * CCMP header rather than IV+extended-IV. */ #define IEEE80211_WEP_EXTIV 0x20 #define IEEE80211_WEP_EXTIVLEN 4 /* extended IV length */ #define IEEE80211_WEP_MICLEN 8 /* trailing MIC */ /* * Maximum acceptable MTU is: * IEEE80211_MAX_LEN - WEP overhead - CRC - * QoS overhead - RSN/WPA overhead * Min is arbitrarily chosen > IEEE80211_MIN_LEN. The default * mtu is Ethernet-compatible; it's set by ether_ifattach. */ #define IEEE80211_MTU_MAX 2290 #define IEEE80211_MTU_MIN 32 #define IEEE80211_MAX_LEN (2300 + IEEE80211_CRC_LEN + \ (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) #define IEEE80211_ACK_LEN \ (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN) #define IEEE80211_MIN_LEN \ (sizeof(struct ieee80211_frame_min) + IEEE80211_CRC_LEN) /* Maximal size of an A-MSDU that can be transported in a HT BA session */ #define IEEE80211_MAX_MPDU_LEN_HT_BA 4095 /* Maximal size of an A-MSDU */ #define IEEE80211_MAX_MPDU_LEN_HT_3839 3839 #define IEEE80211_MAX_MPDU_LEN_HT_7935 7935 #define IEEE80211_MAX_MPDU_LEN_VHT_3895 3895 #define IEEE80211_MAX_MPDU_LEN_VHT_7991 7991 #define IEEE80211_MAX_MPDU_LEN_VHT_11454 11454 /* * The 802.11 spec says at most 2007 stations may be * associated at once. For most AP's this is way more * than is feasible so we use a default of 1800. This * number may be overridden by the driver and/or by * user configuration. */ #define IEEE80211_AID_MAX 2007 #define IEEE80211_AID_DEF 1800 #define IEEE80211_AID(b) ((b) &~ 0xc000) /* * RTS frame length parameters. The default is specified in * the 802.11 spec. The max may be wrong for jumbo frames. */ #define IEEE80211_RTS_DEFAULT 512 #define IEEE80211_RTS_MIN 1 #define IEEE80211_RTS_MAX IEEE80211_MAX_LEN #define IEEE80211_PLCP_SERVICE 0x00 #define IEEE80211_PLCP_SERVICE_PBCC 0x08 /* PBCC encoded */ #define IEEE80211_PLCP_SERVICE_LENEXT 0x80 /* length extension bit */ /* One Time Unit (TU) is 1Kus = 1024 microseconds. */ #define IEEE80211_DUR_TU 1024 /* IEEE 802.11b durations for DSSS PHY in microseconds */ #define IEEE80211_DUR_DS_LONG_PREAMBLE 144 #define IEEE80211_DUR_DS_SHORT_PREAMBLE 72 #define IEEE80211_DUR_DS_PREAMBLE_DIFFERENCE \ (IEEE80211_DUR_DS_LONG_PREAMBLE - IEEE80211_DUR_DS_SHORT_PREAMBLE) #define IEEE80211_DUR_DS_FAST_PLCPHDR 24 #define IEEE80211_DUR_DS_SLOW_PLCPHDR 48 #define IEEE80211_DUR_DS_PLCPHDR_DIFFERENCE \ (IEEE80211_DUR_DS_SLOW_PLCPHDR - IEEE80211_DUR_DS_FAST_PLCPHDR) #define IEEE80211_DUR_DS_SLOW_ACK 112 #define IEEE80211_DUR_DS_FAST_ACK 56 #define IEEE80211_DUR_DS_SLOW_CTS 112 #define IEEE80211_DUR_DS_FAST_CTS 56 #define IEEE80211_DUR_DS_SLOT 20 #define IEEE80211_DUR_DS_SHSLOT 9 #define IEEE80211_DUR_DS_SIFS 10 #define IEEE80211_DUR_DS_PIFS (IEEE80211_DUR_DS_SIFS + IEEE80211_DUR_DS_SLOT) #define IEEE80211_DUR_DS_DIFS (IEEE80211_DUR_DS_SIFS + \ 2 * IEEE80211_DUR_DS_SLOT) #define IEEE80211_DUR_DS_EIFS (IEEE80211_DUR_DS_SIFS + \ IEEE80211_DUR_DS_SLOW_ACK + \ IEEE80211_DUR_DS_LONG_PREAMBLE + \ IEEE80211_DUR_DS_SLOW_PLCPHDR + \ IEEE80211_DUR_DIFS) /* * The RSNA key descriptor used by IEEE 802.11 does not use the IEEE 802.1X * key descriptor. Instead, it uses the key descriptor described in 8.5.2. */ #define EAPOL_KEY_NONCE_LEN 32 #define EAPOL_KEY_IV_LEN 16 #define EAPOL_KEY_MIC_LEN 16 struct ieee80211_eapol_key { u_int8_t version; #define EAPOL_VERSION 1 u_int8_t type; /* IEEE Std 802.1X-2004, 7.5.4 (only type EAPOL-Key is used here) */ #define EAP_PACKET 0 #define EAPOL_START 1 #define EAPOL_LOGOFF 2 #define EAPOL_KEY 3 #define EAPOL_ASF_ALERT 4 u_int8_t len[2]; u_int8_t desc; /* IEEE Std 802.1X-2004, 7.6.1 */ #define EAPOL_KEY_DESC_RC4 1 /* deprecated */ #define EAPOL_KEY_DESC_IEEE80211 2 #define EAPOL_KEY_DESC_WPA 254 /* non-standard WPA */ u_int8_t info[2]; #define EAPOL_KEY_VERSION_MASK 0x7 #define EAPOL_KEY_DESC_V1 1 #define EAPOL_KEY_DESC_V2 2 #define EAPOL_KEY_DESC_V3 3 /* 11r */ #define EAPOL_KEY_PAIRWISE (1 << 3) #define EAPOL_KEY_INSTALL (1 << 6) /* I */ #define EAPOL_KEY_KEYACK (1 << 7) /* A */ #define EAPOL_KEY_KEYMIC (1 << 8) /* M */ #define EAPOL_KEY_SECURE (1 << 9) /* S */ #define EAPOL_KEY_ERROR (1 << 10) #define EAPOL_KEY_REQUEST (1 << 11) #define EAPOL_KEY_ENCRYPTED (1 << 12) #define EAPOL_KEY_SMK (1 << 13) /* WPA compatibility */ #define EAPOL_KEY_WPA_KID_MASK 0x3 #define EAPOL_KEY_WPA_KID_SHIFT 4 #define EAPOL_KEY_WPA_TX EAPOL_KEY_INSTALL u_int8_t keylen[2]; u_int8_t replaycnt[8]; u_int8_t nonce[EAPOL_KEY_NONCE_LEN]; u_int8_t iv[EAPOL_KEY_IV_LEN]; u_int8_t rsc[8]; u_int8_t reserved[8]; u_int8_t mic[EAPOL_KEY_MIC_LEN]; u_int8_t paylen[2]; } __packed; /* Pairwise Transient Key (see 8.5.1.2) */ struct ieee80211_ptk { u_int8_t kck[16]; /* Key Confirmation Key */ u_int8_t kek[16]; /* Key Encryption Key */ u_int8_t tk[32]; /* Temporal Key */ } __packed; #define IEEE80211_PMKID_LEN 16 #define IEEE80211_SMKID_LEN 16 /* * Key Data Encapsulation (see Table 62). */ enum { IEEE80211_KDE_GTK = 1, IEEE80211_KDE_MACADDR = 3, IEEE80211_KDE_PMKID = 4, IEEE80211_KDE_SMK = 5, IEEE80211_KDE_NONCE = 6, IEEE80211_KDE_LIFETIME = 7, IEEE80211_KDE_ERROR = 8, IEEE80211_KDE_IGTK = 9 /* 11w */ }; /* * HT protection modes (see 802.11-2012 8.4.2.59) */ enum ieee80211_htprot { IEEE80211_HTPROT_NONE = 0, /* only 20/40MHz HT STAs exist */ IEEE80211_HTPROT_NONMEMBER, /* non-HT STA overlaps our channel */ IEEE80211_HTPROT_20MHZ, /* 20MHz HT STA on a 40MHz channel */ IEEE80211_HTPROT_NONHT_MIXED /* non-HT STA associated to our BSS */ }; /* * 802.11ac definitions - 802.11ac-2013 . */ /* * Maximum length of A-MPDU that the STA can RX in VHT. * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) */ #define IEEE80211_VHTCAP_MAX_AMPDU_8K 0 #define IEEE80211_VHTCAP_MAX_AMPDU_16K 1 #define IEEE80211_VHTCAP_MAX_AMPDU_32K 2 #define IEEE80211_VHTCAP_MAX_AMPDU_64K 3 #define IEEE80211_VHTCAP_MAX_AMPDU_128K 4 #define IEEE80211_VHTCAP_MAX_AMPDU_256K 5 #define IEEE80211_VHTCAP_MAX_AMPDU_512K 6 #define IEEE80211_VHTCAP_MAX_AMPDU_1024K 7 /* * VHT MCS information. * + rx_highest/tx_highest: optional; maximum long GI VHT PPDU * data rate. 1Mbit/sec units. * + rx_mcs_map/tx_mcs_map: bitmap of per-stream supported MCS; * 2 bits each. */ #define IEEE80211_VHT_MCS_SUPPORT_0_7 0 /* MCS0-7 */ #define IEEE80211_VHT_MCS_SUPPORT_0_8 1 /* MCS0-8 */ #define IEEE80211_VHT_MCS_SUPPORT_0_9 2 /* MCS0-9 */ #define IEEE80211_VHT_MCS_NOT_SUPPORTED 3 /* not supported */ struct ieee80211_vht_mcs_info { uint16_t rx_mcs_map; uint16_t rx_highest; uint16_t tx_mcs_map; uint16_t tx_highest; } __packed; /* for rx_highest */ #define IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT 13 #define IEEE80211_VHT_MAX_NSTS_TOTAL_MASK (7 << IEEE80211_VHT_MAX_NSTS_TOTAL_SHIFT) /* for tx_highest */ #define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13) /* VHT capabilities element: 802.11ac-2013 8.4.2.160 */ struct ieee80211_ie_vhtcap { uint8_t ie; uint8_t len; uint32_t vht_cap_info; struct ieee80211_vht_mcs_info supp_mcs; } __packed; /* VHT operation mode subfields - 802.11ac-2013 Table 8.183x */ #define IEEE80211_VHT_CHANWIDTH_USE_HT 0 /* Use HT IE for chw */ #define IEEE80211_VHT_CHANWIDTH_80MHZ 1 /* 80MHz */ #define IEEE80211_VHT_CHANWIDTH_160MHZ 2 /* 160MHz */ #define IEEE80211_VHT_CHANWIDTH_80P80MHZ 3 /* 80+80MHz */ /* VHT operation IE - 802.11ac-2013 8.4.2.161 */ struct ieee80211_ie_vht_operation { uint8_t ie; uint8_t len; uint8_t chan_width; uint8_t center_freq_seg1_idx; uint8_t center_freq_seg2_idx; uint16_t basic_mcs_set; } __packed; /* 802.11ac VHT Capabilities */ #define IEEE80211_VHTCAP_MAX_MPDU_LENGTH_3895 0x00000000 #define IEEE80211_VHTCAP_MAX_MPDU_LENGTH_7991 0x00000001 #define IEEE80211_VHTCAP_MAX_MPDU_LENGTH_11454 0x00000002 #define IEEE80211_VHTCAP_MAX_MPDU_MASK 0x00000003 #define IEEE80211_VHTCAP_MAX_MPDU_MASK_S 0 #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK 0x0000000C #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK_S 2 #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_NONE 0 #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ 4 #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160_80P80MHZ 8 #define IEEE80211_VHTCAP_RXLDPC 0x00000010 #define IEEE80211_VHTCAP_RXLDPC_S 4 #define IEEE80211_VHTCAP_SHORT_GI_80 0x00000020 #define IEEE80211_VHTCAP_SHORT_GI_80_S 5 #define IEEE80211_VHTCAP_SHORT_GI_160 0x00000040 #define IEEE80211_VHTCAP_SHORT_GI_160_S 6 #define IEEE80211_VHTCAP_TXSTBC 0x00000080 #define IEEE80211_VHTCAP_TXSTBC_S 7 #define IEEE80211_VHTCAP_RXSTBC_1 0x00000100 #define IEEE80211_VHTCAP_RXSTBC_2 0x00000200 #define IEEE80211_VHTCAP_RXSTBC_3 0x00000300 #define IEEE80211_VHTCAP_RXSTBC_4 0x00000400 #define IEEE80211_VHTCAP_RXSTBC_MASK 0x00000700 #define IEEE80211_VHTCAP_RXSTBC_MASK_S 8 #define IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE 0x00000800 #define IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE_S 11 #define IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE 0x00001000 #define IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE_S 12 #define IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT 13 #define IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK \ (7 << IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT) #define IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK_S 13 #define IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_SHIFT 16 #define IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_MASK \ (7 << IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_SHIFT) #define IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_MASK_S 16 #define IEEE80211_VHTCAP_MU_BEAMFORMER_CAPABLE 0x00080000 #define IEEE80211_VHTCAP_MU_BEAMFORMER_CAPABLE_S 19 #define IEEE80211_VHTCAP_MU_BEAMFORMEE_CAPABLE 0x00100000 #define IEEE80211_VHTCAP_MU_BEAMFORMEE_CAPABLE_S 20 #define IEEE80211_VHTCAP_VHT_TXOP_PS 0x00200000 #define IEEE80211_VHTCAP_VHT_TXOP_PS_S 21 #define IEEE80211_VHTCAP_HTC_VHT 0x00400000 #define IEEE80211_VHTCAP_HTC_VHT_S 22 #define IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 23 #define IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \ (7 << IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT) #define IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_S 23 #define IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MASK 0x0c000000 #define IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000 #define IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 #define IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MASK_S 26 #define IEEE80211_VHTCAP_RX_ANTENNA_PATTERN 0x10000000 #define IEEE80211_VHTCAP_RX_ANTENNA_PATTERN_S 28 #define IEEE80211_VHTCAP_TX_ANTENNA_PATTERN 0x20000000 #define IEEE80211_VHTCAP_TX_ANTENNA_PATTERN_S 29 #define IEEE80211_VHTCAP_EXT_NSS_BW_SHIFT 30 #define IEEE80211_VHTCAP_EXT_NSS_BW_MASK 0xc0000000 /* * XXX TODO: add the rest of the bits */ #define IEEE80211_VHTCAP_BITS \ "\20\1MPDU7991\2MPDU11454\3CHAN160\4CHAN8080\5RXLDPC\6SHORTGI80" \ "\7SHORTGI160\10RXSTBC1\11RXSTBC2\12RXSTBC3\13RXSTBC4\14BFERCAP" \ "\15BFEECAP\27VHT\37RXANTPTN\40TXANTPTN" /* * VHT Transmit Power Envelope element - 802.11ac-2013 8.4.2.164 * * This defines the maximum transmit power for various bandwidths. */ /* * Count is how many elements follow and what they're for: * * 0 - 20 MHz * 1 - 20+40 MHz * 2 - 20+40+80 MHz * 3 - 20+40+80+(160, 80+80) MHz */ #define IEEE80211_VHT_TXPWRENV_INFO_COUNT_SHIFT 0 #define IEEE80211_VHT_TXPWRENV_INFO_COUNT_MASK 0x07 /* * Unit is the tx power representation. It should be EIRP for now; * other values are reserved. */ #define IEEE80211_VHT_TXPWRENV_UNIT_MASK 0x38 #define IEEE80211_VHT_TXPWRENV_UNIT_SHIFT 3 /* This value is within the unit mask/shift above */ #define IEEE80211_VHT_TXPWRENV_UNIT_EIRP 0 struct ieee80211_ie_vht_txpwrenv { uint8_t ie; uint8_t len; uint8_t tx_info; int8_t tx_elem[0]; /* TX power elements, 1/2 dB, signed */ }; /* VHT action codes */ #define WLAN_ACTION_VHT_COMPRESSED_BF 0 #define WLAN_ACTION_VHT_GROUPID_MGMT 1 #define WLAN_ACTION_VHT_OPMODE_NOTIF 2 #define IEEE80211_EXTCAP_CMS (1ULL << 0) /* 20/40 BSS coexistence management support */ #define IEEE80211_EXTCAP_RSVD_1 (1ULL << 1) #define IEEE80211_EXTCAP_ECS (1ULL << 2) /* extended channel switching */ #define IEEE80211_EXTCAP_RSVD_3 (1ULL << 3) #define IEEE80211_EXTCAP_PSMP_CAP (1ULL << 4) /* PSMP capability */ #define IEEE80211_EXTCAP_RSVD_5 (1ULL << 5) #define IEEE80211_EXTCAP_S_PSMP_SUPP (1ULL << 6) #define IEEE80211_EXTCAP_EVENT (1ULL << 7) #define IEEE80211_EXTCAP_DIAGNOSTICS (1ULL << 8) #define IEEE80211_EXTCAP_MCAST_DIAG (1ULL << 9) #define IEEE80211_EXTCAP_LOC_TRACKING (1ULL << 10) #define IEEE80211_EXTCAP_FMS (1ULL << 11) #define IEEE80211_EXTCAP_PROXY_ARP (1ULL << 12) #define IEEE80211_EXTCAP_CIR (1ULL << 13) /* collocated interference reporting */ #define IEEE80211_EXTCAP_CIVIC_LOC (1ULL << 14) #define IEEE80211_EXTCAP_GEOSPATIAL_LOC (1ULL << 15) #define IEEE80211_EXTCAP_TFS (1ULL << 16) #define IEEE80211_EXTCAP_WNM_SLEEPMODE (1ULL << 17) #define IEEE80211_EXTCAP_TIM_BROADCAST (1ULL << 18) #define IEEE80211_EXTCAP_BSS_TRANSITION (1ULL << 19) #define IEEE80211_EXTCAP_QOS_TRAF_CAP (1ULL << 20) #define IEEE80211_EXTCAP_AC_STA_COUNT (1ULL << 21) #define IEEE80211_EXTCAP_M_BSSID (1ULL << 22) /* multiple BSSID field */ #define IEEE80211_EXTCAP_TIMING_MEAS (1ULL << 23) #define IEEE80211_EXTCAP_CHAN_USAGE (1ULL << 24) #define IEEE80211_EXTCAP_SSID_LIST (1ULL << 25) #define IEEE80211_EXTCAP_DMS (1ULL << 26) #define IEEE80211_EXTCAP_UTC_TSF_OFFSET (1ULL << 27) #define IEEE80211_EXTCAP_TLDS_BUF_STA_SUPP (1ULL << 28) /* TDLS peer U-APSP buffer STA support */ #define IEEE80211_EXTCAP_TLDS_PPSM_SUPP (1ULL << 29) /* TDLS peer PSM support */ #define IEEE80211_EXTCAP_TLDS_CH_SW (1ULL << 30) /* TDLS channel switching */ #define IEEE80211_EXTCAP_INTERWORKING (1ULL << 31) #define IEEE80211_EXTCAP_QOSMAP (1ULL << 32) #define IEEE80211_EXTCAP_EBR (1ULL << 33) #define IEEE80211_EXTCAP_SSPN_IF (1ULL << 34) #define IEEE80211_EXTCAP_RSVD_35 (1ULL << 35) #define IEEE80211_EXTCAP_MSGCF_CAP (1ULL << 36) #define IEEE80211_EXTCAP_TLDS_SUPP (1ULL << 37) #define IEEE80211_EXTCAP_TLDS_PROHIB (1ULL << 38) #define IEEE80211_EXTCAP_TLDS_CH_SW_PROHIB (1ULL << 39) /* TDLS channel switching prohibited */ #define IEEE80211_EXTCAP_RUF (1ULL << 40) /* reject unadmitted frame */ /* service interval granularity */ #define IEEE80211_EXTCAP_SIG \ ((1ULL << 41) | (1ULL << 42) | (1ULL << 43)) #define IEEE80211_EXTCAP_ID_LOC (1ULL << 44) #define IEEE80211_EXTCAP_U_APSD_COEX (1ULL << 45) #define IEEE80211_EXTCAP_WNM_NOTIFICATION (1ULL << 46) #define IEEE80211_EXTCAP_RSVD_47 (1ULL << 47) #define IEEE80211_EXTCAP_SSID (1ULL << 48) /* UTF-8 SSID */ /* bits 49-n are reserved */ struct ieee80211_extcap_ie { uint8_t ie; uint8_t len; } __packed; /* * 802.11h Quiet Time Element. */ struct ieee80211_quiet_ie { uint8_t quiet_ie; /* IEEE80211_ELEMID_QUIET */ uint8_t len; uint8_t tbttcount; /* quiet start */ uint8_t period; /* beacon intervals between quiets */ uint16_t duration; /* TUs of each quiet*/ uint16_t offset; /* TUs of from TBTT of quiet start */ } __packed; /* * 802.11h Channel Switch Announcement (CSA). */ struct ieee80211_csa_ie { uint8_t csa_ie; /* IEEE80211_ELEMID_CHANSWITCHANN */ uint8_t csa_len; uint8_t csa_mode; /* Channel Switch Mode */ uint8_t csa_newchan; /* New Channel Number */ uint8_t csa_count; /* Channel Switch Count */ } __packed; /** * struct ieee80211_vht_operation - VHT operation IE * * This structure is the "VHT operation element" as * described in 802.11ac D3.0 8.4.2.161 * @chan_width: Operating channel width * @center_freq_seg0_idx: center freq segment 0 index * @center_freq_seg1_idx: center freq segment 1 index * @basic_mcs_set: VHT Basic MCS rate set */ struct ieee80211_vht_operation { uint8_t chan_width; uint8_t center_freq_seg0_idx; uint8_t center_freq_seg1_idx; uint16_t basic_mcs_set; } __packed; #define IEEE80211_HE_PPE_THRES_MAX_LEN 25 /** * struct ieee80211_he_cap_elem - HE capabilities element * * This structure is the "HE capabilities element" fixed fields as * described in P802.11ax_D4.0 section 9.4.2.242.2 and 9.4.2.242.3 */ struct ieee80211_he_cap_elem { uint8_t mac_cap_info[6]; uint8_t phy_cap_info[11]; } __packed; #define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN 5 /** * enum ieee80211_he_mcs_support - HE MCS support definitions * @IEEE80211_HE_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the * number of streams * @IEEE80211_HE_MCS_SUPPORT_0_9: MCSes 0-9 are supported * @IEEE80211_HE_MCS_SUPPORT_0_11: MCSes 0-11 are supported * @IEEE80211_HE_MCS_NOT_SUPPORTED: This number of streams isn't supported * * These definitions are used in each 2-bit subfield of the rx_mcs_* * and tx_mcs_* fields of &struct ieee80211_he_mcs_nss_supp, which are * both split into 8 subfields by number of streams. These values indicate * which MCSes are supported for the number of streams the value appears * for. */ enum ieee80211_he_mcs_support { IEEE80211_HE_MCS_SUPPORT_0_7 = 0, IEEE80211_HE_MCS_SUPPORT_0_9 = 1, IEEE80211_HE_MCS_SUPPORT_0_11 = 2, IEEE80211_HE_MCS_NOT_SUPPORTED = 3, }; /** * struct ieee80211_he_mcs_nss_supp - HE Tx/Rx HE MCS NSS Support Field * * This structure holds the data required for the Tx/Rx HE MCS NSS Support Field * described in P802.11ax_D2.0 section 9.4.2.237.4 * * @rx_mcs_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel * widths less than 80MHz. * @tx_mcs_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel * widths less than 80MHz. * @rx_mcs_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel * width 160MHz. * @tx_mcs_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel * width 160MHz. * @rx_mcs_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for * channel width 80p80MHz. * @tx_mcs_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for * channel width 80p80MHz. */ struct ieee80211_he_mcs_nss_supp { uint16_t rx_mcs_80; uint16_t tx_mcs_80; uint16_t rx_mcs_160; uint16_t tx_mcs_160; uint16_t rx_mcs_80p80; uint16_t tx_mcs_80p80; } __packed; /** * struct ieee80211_he_operation - HE capabilities element * * This structure is the "HE operation element" fields as * described in P802.11ax_D4.0 section 9.4.2.243 */ struct ieee80211_he_operation { uint32_t he_oper_params; uint16_t he_mcs_nss_set; /* Optional 0,1,3,4,5,7 or 8 bytes: depends on @he_oper_params */ uint8_t optional[]; } __packed; /** * struct ieee80211_he_spr - HE spatial reuse element * * This structure is the "HE spatial reuse element" element as * described in P802.11ax_D4.0 section 9.4.2.241 */ struct ieee80211_he_spr { uint8_t he_sr_control; /* Optional 0 to 19 bytes: depends on @he_sr_control */ uint8_t optional[]; } __packed; /** * struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field * * This structure is the "MU AC Parameter Record" fields as * described in P802.11ax_D4.0 section 9.4.2.245 */ struct ieee80211_he_mu_edca_param_ac_rec { uint8_t aifsn; uint8_t ecw_min_max; uint8_t mu_edca_timer; } __packed; /** * struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element * * This structure is the "MU EDCA Parameter Set element" fields as * described in P802.11ax_D4.0 section 9.4.2.245 */ struct ieee80211_mu_edca_param_set { uint8_t mu_qos_info; struct ieee80211_he_mu_edca_param_ac_rec ac_be; struct ieee80211_he_mu_edca_param_ac_rec ac_bk; struct ieee80211_he_mu_edca_param_ac_rec ac_vi; struct ieee80211_he_mu_edca_param_ac_rec ac_vo; } __packed; /* 802.11ax HE MAC capabilities */ #define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01 #define IEEE80211_HE_MAC_CAP0_TWT_REQ 0x02 #define IEEE80211_HE_MAC_CAP0_TWT_RES 0x04 #define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_NOT_SUPP 0x00 #define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_1 0x08 #define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_2 0x10 #define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_3 0x18 #define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_MASK 0x18 #define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_1 0x00 #define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_2 0x20 #define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_4 0x40 #define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_8 0x60 #define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_16 0x80 #define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_32 0xa0 #define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_64 0xc0 #define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_UNLIMITED 0xe0 #define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_MASK 0xe0 #define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_UNLIMITED 0x00 #define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_128 0x01 #define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_256 0x02 #define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_512 0x03 #define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_MASK 0x03 #define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US 0x00 #define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US 0x04 #define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US 0x08 #define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK 0x0c #define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1 0x00 #define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_2 0x10 #define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_3 0x20 #define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_4 0x30 #define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_5 0x40 #define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_6 0x50 #define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_7 0x60 #define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8 0x70 #define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_MASK 0x70 /* Link adaptation is split between byte HE_MAC_CAP1 and * HE_MAC_CAP2. It should be set only if IEEE80211_HE_MAC_CAP0_HTC_HE * in which case the following values apply: * 0 = No feedback. * 1 = reserved. * 2 = Unsolicited feedback. * 3 = both */ #define IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION 0x80 #define IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION 0x01 #define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02 #define IEEE80211_HE_MAC_CAP2_TRS 0x04 #define IEEE80211_HE_MAC_CAP2_BSR 0x08 #define IEEE80211_HE_MAC_CAP2_BCAST_TWT 0x10 #define IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP 0x20 #define IEEE80211_HE_MAC_CAP2_MU_CASCADING 0x40 #define IEEE80211_HE_MAC_CAP2_ACK_EN 0x80 #define IEEE80211_HE_MAC_CAP3_OMI_CONTROL 0x02 #define IEEE80211_HE_MAC_CAP3_OFDMA_RA 0x04 /* The maximum length of an A-MDPU is defined by the combination of the Maximum * A-MDPU Length Exponent field in the HT capabilities, VHT capabilities and the * same field in the HE capabilities. */ #define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_USE_VHT 0x00 #define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_1 0x08 #define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2 0x10 #define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED 0x18 #define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK 0x18 #define IEEE80211_HE_MAC_CAP3_AMSDU_FRAG 0x20 #define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x40 #define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS 0x80 #define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_SHIFT 3 #define IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG 0x01 #define IEEE80211_HE_MAC_CAP4_QTP 0x02 #define IEEE80211_HE_MAC_CAP4_BQR 0x04 #define IEEE80211_HE_MAC_CAP4_SRP_RESP 0x08 #define IEEE80211_HE_MAC_CAP4_NDP_FB_REP 0x10 #define IEEE80211_HE_MAC_CAP4_OPS 0x20 #define IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU 0x40 /* Multi TID agg TX is split between byte #4 and #5 * The value is a combination of B39,B40,B41 */ #define IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39 0x80 #define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 0x01 #define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 0x02 #define IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECVITE_TRANSMISSION 0x04 #define IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU 0x08 #define IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX 0x10 #define IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS 0x20 #define IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING 0x40 #define IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX 0x80 #define IEEE80211_HE_VHT_MAX_AMPDU_FACTOR 20 #define IEEE80211_HE_HT_MAX_AMPDU_FACTOR 16 /* 802.11ax HE PHY capabilities */ #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G 0x08 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G 0x10 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G 0x20 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G 0x40 #define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK 0xfe #define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_20MHZ 0x01 #define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_40MHZ 0x02 #define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_20MHZ 0x04 #define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_40MHZ 0x08 #define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK 0x0f #define IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A 0x10 #define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20 #define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40 /* Midamble RX/TX Max NSTS is split between byte #2 and byte #3 */ #define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS 0x80 #define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS 0x01 #define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02 #define IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ 0x04 #define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08 #define IEEE80211_HE_PHY_CAP2_DOPPLER_TX 0x10 #define IEEE80211_HE_PHY_CAP2_DOPPLER_RX 0x20 /* Note that the meaning of UL MU below is different between an AP and a non-AP * sta, where in the AP case it indicates support for Rx and in the non-AP sta * case it indicates support for Tx. */ #define IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO 0x40 #define IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO 0x80 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM 0x00 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK 0x01 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK 0x02 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM 0x03 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK 0x03 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 0x00 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2 0x04 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM 0x00 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK 0x08 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK 0x10 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM 0x18 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK 0x18 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00 #define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2 0x20 #define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40 #define IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER 0x80 #define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01 #define IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER 0x02 /* Minimal allowed value of Max STS under 80MHz is 3 */ #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 0x0c #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5 0x10 #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_6 0x14 #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_7 0x18 #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8 0x1c #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK 0x1c /* Minimal allowed value of Max STS above 80MHz is 3 */ #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4 0x60 #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5 0x80 #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_6 0xa0 #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_7 0xc0 #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 0xe0 #define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK 0xe0 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_1 0x00 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 0x01 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_3 0x02 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4 0x03 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_5 0x04 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_6 0x05 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_7 0x06 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_8 0x07 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK 0x07 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_1 0x00 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 0x08 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_3 0x10 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_4 0x18 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_5 0x20 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_6 0x28 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_7 0x30 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_8 0x38 #define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK 0x38 #define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK 0x40 #define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK 0x80 #define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01 #define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02 #define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB 0x04 #define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB 0x08 #define IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB 0x10 #define IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE 0x20 #define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40 #define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80 #define IEEE80211_HE_PHY_CAP7_SRP_BASED_SR 0x01 #define IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR 0x02 #define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04 #define IEEE80211_HE_PHY_CAP7_MAX_NC_1 0x08 #define IEEE80211_HE_PHY_CAP7_MAX_NC_2 0x10 #define IEEE80211_HE_PHY_CAP7_MAX_NC_3 0x18 #define IEEE80211_HE_PHY_CAP7_MAX_NC_4 0x20 #define IEEE80211_HE_PHY_CAP7_MAX_NC_5 0x28 #define IEEE80211_HE_PHY_CAP7_MAX_NC_6 0x30 #define IEEE80211_HE_PHY_CAP7_MAX_NC_7 0x38 #define IEEE80211_HE_PHY_CAP7_MAX_NC_MASK 0x38 #define IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ 0x40 #define IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ 0x80 #define IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI 0x01 #define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G 0x02 #define IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU 0x04 #define IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU 0x08 #define IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI 0x10 #define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_TX_2X_AND_1XLTF 0x20 #define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242 0x00 #define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484 0x40 #define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996 0x80 #define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996 0xc0 #define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_MASK 0xc0 #define IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM 0x01 #define IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK 0x02 #define IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU 0x04 #define IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU 0x08 #define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10 #define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20 #define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US 0x00 #define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US 0x40 #define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US 0x80 #define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED 0xc0 #define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK 0xc0 /* 802.11ax HE TX/RX MCS NSS Support */ #define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS (3) #define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_POS (6) #define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_POS (11) #define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_MASK 0x07c0 #define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_MASK 0xf800 /* TX/RX HE MCS Support field Highest MCS subfield encoding */ enum ieee80211_he_highest_mcs_supported_subfield_enc { HIGHEST_MCS_SUPPORTED_MCS7 = 0, HIGHEST_MCS_SUPPORTED_MCS8, HIGHEST_MCS_SUPPORTED_MCS9, HIGHEST_MCS_SUPPORTED_MCS10, HIGHEST_MCS_SUPPORTED_MCS11, }; /* Calculate 802.11ax HE capabilities IE Tx/Rx HE MCS NSS Support Field size */ static inline uint8_t ieee80211_he_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap) { uint8_t count = 4; if (he_cap->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) count += 4; if (he_cap->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) count += 4; return count; } /* 802.11ax HE PPE Thresholds */ #define IEEE80211_PPE_THRES_NSS_SUPPORT_2NSS (1) #define IEEE80211_PPE_THRES_NSS_POS (0) #define IEEE80211_PPE_THRES_NSS_MASK (7) #define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_2x966_AND_966_RU \ ((1 << 5) | (1 << 6)) #define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK 0x78 #define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS (3) #define IEEE80211_PPE_THRES_INFO_PPET_SIZE (3) /* HE Operation defines */ #define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK 0x00000007 #define IEEE80211_HE_OPERATION_TWT_REQUIRED 0x00000008 #define IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK 0x00003ff0 #define IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET 4 #define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00004000 #define IEEE80211_HE_OPERATION_CO_HOSTED_BSS 0x00008000 #define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x00010000 #define IEEE80211_HE_OPERATION_6GHZ_OP_INFO 0x00020000 #define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x3f000000 #define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24 #define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000 #define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x80000000 /* * Calculate 802.11ax HE capabilities IE PPE field size * Input: Header byte of ppe_thres (first byte), and HE capa IE's PHY cap u8* */ static inline uint8_t ieee80211_he_ppe_size(uint8_t ppe_thres_hdr, const uint8_t *phy_cap_info) { uint8_t n; if ((phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0) return 0; n = hweight8(ppe_thres_hdr & IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK); n *= (1 + ((ppe_thres_hdr & IEEE80211_PPE_THRES_NSS_MASK) >> IEEE80211_PPE_THRES_NSS_POS)); /* * Each pair is 6 bits, and we need to add the 7 "header" bits to the * total size. */ n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7; n = DIV_ROUND_UP(n, 8); return n; } /** * ieee80211_he_6ghz_oper - HE 6 GHz operation Information field * @primary: primary channel * @control: control flags * @ccfs0: channel center frequency segment 0 * @ccfs1: channel center frequency segment 1 * @minrate: minimum rate (in 1 Mbps units) */ struct ieee80211_he_6ghz_oper { uint8_t primary; #define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH 0x3 #define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ 0 #define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ 1 #define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ 2 #define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ 3 #define IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON 0x4 uint8_t control; uint8_t ccfs0; uint8_t ccfs1; uint8_t minrate; } __packed; /* * ieee80211_he_oper_size - calculate 802.11ax HE Operations IE size * @he_oper_ie: byte data of the He Operations IE, stating from the byte * after the ext ID byte. It is assumed that he_oper_ie has at least * sizeof(struct ieee80211_he_operation) bytes, the caller must have * validated this. * @return the actual size of the IE data (not including header), or 0 on error */ static inline uint8_t ieee80211_he_oper_size(const uint8_t *he_oper_ie) { struct ieee80211_he_operation *he_oper = (struct ieee80211_he_operation *)he_oper_ie; uint8_t oper_len = sizeof(struct ieee80211_he_operation); uint32_t he_oper_params; /* Make sure the input is not NULL */ if (!he_oper_ie) return 0; /* Calc required length */ he_oper_params = le32toh(he_oper->he_oper_params); if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO) oper_len += 3; if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS) oper_len++; if (he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO) oper_len += sizeof(struct ieee80211_he_6ghz_oper); /* Add the first byte (extension ID) to the total length */ oper_len++; return oper_len; } /** * ieee80211_he_6ghz_oper - obtain 6 GHz operation field * @he_oper: HE operation element (must be pre-validated for size) * but may be %NULL * * Return: a pointer to the 6 GHz operation field, or %NULL */ static inline const struct ieee80211_he_6ghz_oper * ieee80211_he_6ghz_oper(const struct ieee80211_he_operation *he_oper) { const uint8_t *ret = (const uint8_t *)&he_oper->optional; uint32_t he_oper_params; if (!he_oper) return NULL; he_oper_params = le32toh(he_oper->he_oper_params); if (!(he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO)) return NULL; if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO) ret += 3; if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS) ret++; return (struct ieee80211_he_6ghz_oper *)ret; } /* HE Spatial Reuse defines */ #define IEEE80211_HE_SPR_PSR_DISALLOWED (1 << 0) #define IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED (1 << 1) #define IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT (1 << 2) #define IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT (1 << 3) #define IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED (1 << 4) /* * ieee80211_he_spr_size - calculate 802.11ax HE Spatial Reuse IE size * @he_spr_ie: byte data of the He Spatial Reuse IE, stating from the byte * after the ext ID byte. It is assumed that he_spr_ie has at least * sizeof(struct ieee80211_he_spr) bytes, the caller must have validated * this * @return the actual size of the IE data (not including header), or 0 on error */ static inline uint8_t ieee80211_he_spr_size(const uint8_t *he_spr_ie) { struct ieee80211_he_spr *he_spr = (struct ieee80211_he_spr *)he_spr_ie; uint8_t spr_len = sizeof(struct ieee80211_he_spr); uint8_t he_spr_params; /* Make sure the input is not NULL */ if (!he_spr_ie) return 0; /* Calc required length */ he_spr_params = he_spr->he_sr_control; if (he_spr_params & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT) spr_len++; if (he_spr_params & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) spr_len += 18; /* Add the first byte (extension ID) to the total length */ spr_len++; return spr_len; } /* * Note the min acceptable CSA count is used to guard against * malicious CSA injection in station mode. Defining this value * as other than 0 violates the 11h spec. */ #define IEEE80211_CSA_COUNT_MIN 2 #define IEEE80211_CSA_COUNT_MAX 255 #define IEEE80211_IS_CHAN_HT(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT) != 0) #define IEEE80211_IS_CHAN_HT20(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT20) != 0) #define IEEE80211_IS_CHAN_HT40(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT40) != 0) #define IEEE80211_IS_CHAN_HT40U(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT40U) != 0) #define IEEE80211_IS_CHAN_HT40D(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT40D) != 0) #define IEEE80211_IS_CHAN_VHT(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_VHT) != 0) #define IEEE80211_IS_CHAN_VHT_2GHZ(_c) \ (IEEE80211_IS_CHAN_2GHZ(_c) && \ ((_c)->ic_flags & IEEE80211_CHAN_VHT) != 0) #define IEEE80211_IS_CHAN_VHT_5GHZ(_c) \ (IEEE80211_IS_CHAN_5GHZ(_c) && \ ((_c)->ic_flags & IEEE80211_CHAN_VHT) != 0) #define IEEE80211_IS_CHAN_VHT20(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_VHT20) != 0) #define IEEE80211_IS_CHAN_VHT40(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_VHT40) != 0) #define IEEE80211_IS_CHAN_VHT40U(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_VHT40U) != 0) #define IEEE80211_IS_CHAN_VHT40D(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_VHT40D) != 0) #define IEEE80211_IS_CHAN_VHTA(_c) \ (IEEE80211_IS_CHAN_5GHZ(_c) && \ ((_c)->ic_flags & IEEE80211_CHAN_VHT) != 0) #define IEEE80211_IS_CHAN_VHTG(_c) \ (IEEE80211_IS_CHAN_2GHZ(_c) && \ ((_c)->ic_flags & IEEE80211_CHAN_VHT) != 0) #define IEEE80211_IS_CHAN_VHT80(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_VHT80) != 0) #define IEEE80211_IS_CHAN_VHT80_80(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_VHT80_80) != 0) #define IEEE80211_IS_CHAN_VHT160(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_VHT160) != 0) #define WME_OUI 0xf25000 #define WME_OUI_TYPE 0x02 #define WME_INFO_OUI_SUBTYPE 0x00 #define WME_PARAM_OUI_SUBTYPE 0x01 #define WME_VERSION 1 /* WME stream classes */ #define WME_AC_BE 0 /* best effort */ #define WME_AC_BK 1 /* background */ #define WME_AC_VI 2 /* video */ #define WME_AC_VO 3 /* voice */ /* * WME/802.11e information element. */ struct ieee80211_wme_info { uint8_t wme_id; /* IEEE80211_ELEMID_VENDOR */ uint8_t wme_len; /* length in bytes */ uint8_t wme_oui[3]; /* 0x00, 0x50, 0xf2 */ uint8_t wme_type; /* OUI type */ uint8_t wme_subtype; /* OUI subtype */ uint8_t wme_version; /* spec revision */ uint8_t wme_info; /* QoS info */ } __packed; #ifdef AIRPORT static inline uint64_t airport_up_time() { struct timeval tv; microuptime(&tv); return tv.tv_sec * 1000 + tv.tv_usec / 1000; } #endif #endif /* _NET80211_IEEE80211_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_amrr.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. */ /* $OpenBSD: ieee80211_amrr.c,v 1.12 2019/02/24 09:36:28 stsp Exp $ */ /*- * Copyright (c) 2006 * Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #define is_success(amn) \ ((amn)->amn_retrycnt < (amn)->amn_txcnt / 10) #define is_failure(amn) \ ((amn)->amn_retrycnt > (amn)->amn_txcnt / 3) #define is_enough(amn) \ ((amn)->amn_txcnt > 10) #define reset_cnt(amn) \ do { (amn)->amn_txcnt = (amn)->amn_retrycnt = 0; } while (0) static inline int is_min_rate(struct ieee80211_node *ni) { return (ni->ni_txrate == 0); } static inline int is_max_rate(struct ieee80211_node *ni) { return (ni->ni_txrate == ni->ni_rates.rs_nrates - 1); } static inline void increase_rate(struct ieee80211_node *ni) { ni->ni_txrate++; } static inline void decrease_rate(struct ieee80211_node *ni) { ni->ni_txrate--; } void ieee80211_amrr_node_init(const struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn) { amn->amn_success = 0; amn->amn_recovery = 0; amn->amn_txcnt = amn->amn_retrycnt = 0; amn->amn_success_threshold = amrr->amrr_min_success_threshold; } /* * Update ni->ni_txrate. */ void ieee80211_amrr_choose(struct ieee80211_amrr *amrr, struct ieee80211_node *ni, struct ieee80211_amrr_node *amn) { #define RV(rate) ((rate) & IEEE80211_RATE_VAL) int need_change = 0; if (is_success(amn) && is_enough(amn)) { amn->amn_success++; if (amn->amn_success >= amn->amn_success_threshold && !is_max_rate(ni)) { amn->amn_recovery = 1; amn->amn_success = 0; increase_rate(ni); DPRINTF(("increase rate=%d,#tx=%d,#retries=%d\n", RV(ni->ni_rates.rs_rates[ni->ni_txrate]), amn->amn_txcnt, amn->amn_retrycnt)); need_change = 1; } else { amn->amn_recovery = 0; } } else if (is_failure(amn)) { amn->amn_success = 0; if (!is_min_rate(ni)) { if (amn->amn_recovery) { amn->amn_success_threshold *= 2; if (amn->amn_success_threshold > amrr->amrr_max_success_threshold) amn->amn_success_threshold = amrr->amrr_max_success_threshold; } else { amn->amn_success_threshold = amrr->amrr_min_success_threshold; } decrease_rate(ni); DPRINTF(("decrease rate=%d,#tx=%d,#retries=%d\n", RV(ni->ni_rates.rs_rates[ni->ni_txrate]), amn->amn_txcnt, amn->amn_retrycnt)); need_change = 1; } amn->amn_recovery = 0; } if (is_enough(amn) || need_change) reset_cnt(amn); #undef RV } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_amrr.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_amrr.h,v 1.4 2007/06/16 13:17:05 damien Exp $ */ /*- * Copyright (c) 2006 * Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _NET80211_IEEE80211_AMRR_H_ #define _NET80211_IEEE80211_AMRR_H_ /*- * Naive implementation of the Adaptive Multi Rate Retry algorithm: * * "IEEE 802.11 Rate Adaptation: A Practical Approach" * Mathieu Lacage, Hossein Manshaei, Thierry Turletti * INRIA Sophia - Projet Planete * http://www-sop.inria.fr/rapports/sophia/RR-5208.html */ /* * Rate control settings. */ struct ieee80211_amrr { u_int amrr_min_success_threshold; u_int amrr_max_success_threshold; }; #define IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD 1 #define IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD 15 /* * Rate control state for a given node. */ struct ieee80211_amrr_node { u_int amn_success; u_int amn_recovery; u_int amn_success_threshold; u_int amn_txcnt; u_int amn_retrycnt; }; void ieee80211_amrr_node_init(const struct ieee80211_amrr *, struct ieee80211_amrr_node *); void ieee80211_amrr_choose(struct ieee80211_amrr *, struct ieee80211_node *, struct ieee80211_amrr_node *); #endif /* _NET80211_IEEE80211_AMRR_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_crypto.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. */ /* $OpenBSD: ieee80211_crypto.c,v 1.75 2019/08/16 19:53:32 procter Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void ieee80211_prf(const u_int8_t *, size_t, const u_int8_t *, size_t, const u_int8_t *, size_t, u_int8_t *, size_t); void ieee80211_kdf(const u_int8_t *, size_t, const u_int8_t *, size_t, const u_int8_t *, size_t, u_int8_t *, size_t); void ieee80211_derive_pmkid(enum ieee80211_akm, const u_int8_t *, const u_int8_t *, const u_int8_t *, u_int8_t *); void ieee80211_crypto_attach(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; TAILQ_INIT(&ic->ic_pmksa); if (ic->ic_caps & IEEE80211_C_RSN) { ic->ic_rsnprotos = IEEE80211_PROTO_RSN; ic->ic_rsnakms = IEEE80211_AKM_PSK; ic->ic_rsnciphers = IEEE80211_CIPHER_CCMP; ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP; ic->ic_rsngroupmgmtcipher = IEEE80211_CIPHER_BIP; } ic->ic_set_key = ieee80211_set_key; ic->ic_delete_key = ieee80211_delete_key; #ifndef IEEE80211_STA_ONLY timeout_set(&ic->ic_tkip_micfail_timeout, ieee80211_michael_mic_failure_timeout, ic); #endif } void ieee80211_crypto_detach(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ieee80211_pmk *pmk; /* purge the PMKSA cache */ while ((pmk = TAILQ_FIRST(&ic->ic_pmksa)) != NULL) { TAILQ_REMOVE(&ic->ic_pmksa, pmk, pmk_next); explicit_bzero(pmk, sizeof(*pmk)); free(pmk); } /* clear all group keys from memory */ ieee80211_crypto_clear_groupkeys(ic); /* clear pre-shared key from memory */ explicit_bzero(ic->ic_psk, IEEE80211_PMK_LEN); #ifndef IEEE80211_STA_ONLY timeout_del(&ic->ic_tkip_micfail_timeout); timeout_free(&ic->ic_tkip_micfail_timeout); #endif } void ieee80211_crypto_clear_groupkeys(struct ieee80211com *ic) { int i; for (i = 0; i < IEEE80211_GROUP_NKID; i++) { struct ieee80211_key *k = &ic->ic_nw_keys[i]; if (k->k_cipher != IEEE80211_CIPHER_NONE) (*ic->ic_delete_key)(ic, NULL, k); explicit_bzero(k, sizeof(*k)); } } /* * Return the length in bytes of a cipher suite key (see Table 60). */ int ieee80211_cipher_keylen(enum ieee80211_cipher cipher) { switch (cipher) { case IEEE80211_CIPHER_WEP40: return 5; case IEEE80211_CIPHER_TKIP: return 32; case IEEE80211_CIPHER_CCMP: return 16; case IEEE80211_CIPHER_WEP104: return 13; case IEEE80211_CIPHER_BIP: return 16; default: /* unknown cipher */ return 0; } } int ieee80211_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { int error; switch (k->k_cipher) { case IEEE80211_CIPHER_WEP40: case IEEE80211_CIPHER_WEP104: error = ieee80211_wep_set_key(ic, k); break; case IEEE80211_CIPHER_TKIP: error = ieee80211_tkip_set_key(ic, k); break; case IEEE80211_CIPHER_CCMP: error = ieee80211_ccmp_set_key(ic, k); break; case IEEE80211_CIPHER_BIP: error = ieee80211_bip_set_key(ic, k); break; default: /* should not get there */ error = EINVAL; } if (error == 0) k->k_flags |= IEEE80211_KEY_SWCRYPTO; XYLog("%s kid=%d cipher=%d, error=%d\n", __FUNCTION__, k->k_id, k->k_cipher, error); return error; } void ieee80211_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { switch (k->k_cipher) { case IEEE80211_CIPHER_WEP40: case IEEE80211_CIPHER_WEP104: ieee80211_wep_delete_key(ic, k); break; case IEEE80211_CIPHER_TKIP: ieee80211_tkip_delete_key(ic, k); break; case IEEE80211_CIPHER_CCMP: ieee80211_ccmp_delete_key(ic, k); break; case IEEE80211_CIPHER_BIP: ieee80211_bip_delete_key(ic, k); break; default: /* should not get there */ break; } explicit_bzero(k, sizeof(*k)); } struct ieee80211_key * ieee80211_get_txkey(struct ieee80211com *ic, const struct ieee80211_frame *wh, struct ieee80211_node *ni) { int kid; if ((ic->ic_flags & IEEE80211_F_RSNON) && !IEEE80211_IS_MULTICAST(wh->i_addr1) && ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) return &ni->ni_pairwise_key; /* All other cases (including WEP) use a group key. */ if (ni->ni_flags & IEEE80211_NODE_MFP) kid = ic->ic_igtk_kid; else kid = ic->ic_def_txkey; return &ic->ic_nw_keys[kid]; } struct ieee80211_key * ieee80211_get_rxkey(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { struct ieee80211_key *k = NULL; struct ieee80211_frame *wh; u_int16_t kid; u_int8_t *ivp, *mmie; int hdrlen; wh = mtod(m, struct ieee80211_frame *); if ((ic->ic_flags & IEEE80211_F_RSNON) && !IEEE80211_IS_MULTICAST(wh->i_addr1) && ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) { k = &ni->ni_pairwise_key; } else if (!IEEE80211_IS_MULTICAST(wh->i_addr1) || (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT) { /* retrieve group data key id from IV field */ hdrlen = ieee80211_get_hdrlen(wh); /* check that IV field is present */ if (mbuf_len(m) < hdrlen + 4) return NULL; ivp = (u_int8_t *)wh + hdrlen; kid = ivp[3] >> 6; k = &ic->ic_nw_keys[kid]; } else { /* retrieve integrity group key id from MMIE */ if (mbuf_len(m) < sizeof(*wh) + IEEE80211_MMIE_LEN) return NULL; /* it is assumed management frames are contiguous */ mmie = (u_int8_t *)wh + mbuf_len(m) - IEEE80211_MMIE_LEN; /* check that MMIE is valid */ if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) return NULL; kid = LE_READ_2(&mmie[2]); if (kid != 4 && kid != 5) return NULL; k = &ic->ic_nw_keys[kid]; } return k; } mbuf_t ieee80211_encrypt(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_key *k) { if ((k->k_flags & IEEE80211_KEY_SWCRYPTO) == 0) { XYLog("%s: BUG! key unset for sw crypto. k_id: %d k_cipher: %d k_flags: %d\n", __FUNCTION__, k->k_id, k->k_cipher, k->k_flags); mbuf_freem(m0); return NULL; } XYLog("%s kid=%d cipher=%d\n", __FUNCTION__, k->k_id, k->k_cipher); switch (k->k_cipher) { case IEEE80211_CIPHER_WEP40: case IEEE80211_CIPHER_WEP104: m0 = ieee80211_wep_encrypt(ic, m0, k); break; case IEEE80211_CIPHER_TKIP: m0 = ieee80211_tkip_encrypt(ic, m0, k); break; case IEEE80211_CIPHER_CCMP: m0 = ieee80211_ccmp_encrypt(ic, m0, k); break; case IEEE80211_CIPHER_BIP: m0 = ieee80211_bip_encap(ic, m0, k); break; default: /* should not get there */ panic("invalid key cipher 0x%x", k->k_cipher); } return m0; } mbuf_t ieee80211_decrypt(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_node *ni) { struct ieee80211_key *k; /* find key for decryption */ k = ieee80211_get_rxkey(ic, m0, ni); if (k == NULL || (k->k_flags & IEEE80211_KEY_SWCRYPTO) == 0) { mbuf_freem(m0); return NULL; } switch (k->k_cipher) { case IEEE80211_CIPHER_WEP40: case IEEE80211_CIPHER_WEP104: m0 = ieee80211_wep_decrypt(ic, m0, k); break; case IEEE80211_CIPHER_TKIP: m0 = ieee80211_tkip_decrypt(ic, m0, k); break; case IEEE80211_CIPHER_CCMP: m0 = ieee80211_ccmp_decrypt(ic, m0, k); break; case IEEE80211_CIPHER_BIP: m0 = ieee80211_bip_decap(ic, m0, k); break; default: /* key not defined */ mbuf_freem(m0); m0 = NULL; } return m0; } /* * SHA1-based Pseudo-Random Function (see 8.5.1.1). */ void ieee80211_prf(const u_int8_t *key, size_t key_len, const u_int8_t *label, size_t label_len, const u_int8_t *context, size_t context_len, u_int8_t *output, size_t len) { HMAC_SHA1_CTX ctx; u_int8_t digest[SHA1_DIGEST_LENGTH]; u_int8_t count; for (count = 0; len != 0; count++) { HMAC_SHA1_Init(&ctx, key, key_len); HMAC_SHA1_Update(&ctx, label, label_len); HMAC_SHA1_Update(&ctx, context, context_len); HMAC_SHA1_Update(&ctx, &count, 1); if (len < SHA1_DIGEST_LENGTH) { HMAC_SHA1_Final(digest, &ctx); /* truncate HMAC-SHA1 to len bytes */ memcpy(output, digest, len); break; } HMAC_SHA1_Final(output, &ctx); output += SHA1_DIGEST_LENGTH; len -= SHA1_DIGEST_LENGTH; } } /* * SHA256-based Key Derivation Function (see 8.5.1.5.2). */ void ieee80211_kdf(const u_int8_t *key, size_t key_len, const u_int8_t *label, size_t label_len, const u_int8_t *context, size_t context_len, u_int8_t *output, size_t len) { HMAC_SHA256_CTX ctx; u_int8_t digest[SHA256_DIGEST_LENGTH]; u_int16_t i, iter, length; length = htole16(len * NBBY); for (i = 1; len != 0; i++) { HMAC_SHA256_Init(&ctx, key, key_len); iter = htole16(i); HMAC_SHA256_Update(&ctx, (u_int8_t *)&iter, sizeof iter); HMAC_SHA256_Update(&ctx, label, label_len); HMAC_SHA256_Update(&ctx, context, context_len); HMAC_SHA256_Update(&ctx, (u_int8_t *)&length, sizeof length); if (len < SHA256_DIGEST_LENGTH) { HMAC_SHA256_Final(digest, &ctx); /* truncate HMAC-SHA-256 to len bytes */ memcpy(output, digest, len); break; } HMAC_SHA256_Final(output, &ctx); output += SHA256_DIGEST_LENGTH; len -= SHA256_DIGEST_LENGTH; } } /* * Derive Pairwise Transient Key (PTK) (see 8.5.1.2). */ void ieee80211_derive_ptk(enum ieee80211_akm akm, const u_int8_t *pmk, const u_int8_t *aa, const u_int8_t *spa, const u_int8_t *anonce, const u_int8_t *snonce, struct ieee80211_ptk *ptk) { void (*kdf)(const u_int8_t *, size_t, const u_int8_t *, size_t, const u_int8_t *, size_t, u_int8_t *, size_t); u_int8_t buf[2 * IEEE80211_ADDR_LEN + 2 * EAPOL_KEY_NONCE_LEN]; int ret; /* Min(AA,SPA) || Max(AA,SPA) */ ret = memcmp(aa, spa, IEEE80211_ADDR_LEN) < 0; memcpy(&buf[ 0], ret ? aa : spa, IEEE80211_ADDR_LEN); memcpy(&buf[ 6], ret ? spa : aa, IEEE80211_ADDR_LEN); /* Min(ANonce,SNonce) || Max(ANonce,SNonce) */ ret = memcmp(anonce, snonce, EAPOL_KEY_NONCE_LEN) < 0; memcpy(&buf[12], ret ? anonce : snonce, EAPOL_KEY_NONCE_LEN); memcpy(&buf[44], ret ? snonce : anonce, EAPOL_KEY_NONCE_LEN); kdf = ieee80211_is_sha256_akm(akm) ? ieee80211_kdf : ieee80211_prf; (*kdf)(pmk, IEEE80211_PMK_LEN, (const u_int8_t *)"Pairwise key expansion", 23, buf, sizeof buf, (u_int8_t *)ptk, sizeof(*ptk)); } static void ieee80211_pmkid_sha1(const u_int8_t *pmk, const u_int8_t *aa, const u_int8_t *spa, u_int8_t *pmkid) { HMAC_SHA1_CTX ctx; u_int8_t digest[SHA1_DIGEST_LENGTH]; HMAC_SHA1_Init(&ctx, pmk, IEEE80211_PMK_LEN); HMAC_SHA1_Update(&ctx, (const u_int8_t *)"PMK Name", 8); HMAC_SHA1_Update(&ctx, aa, IEEE80211_ADDR_LEN); HMAC_SHA1_Update(&ctx, spa, IEEE80211_ADDR_LEN); HMAC_SHA1_Final(digest, &ctx); /* use the first 128 bits of HMAC-SHA1 */ memcpy(pmkid, digest, IEEE80211_PMKID_LEN); } static void ieee80211_pmkid_sha256(const u_int8_t *pmk, const u_int8_t *aa, const u_int8_t *spa, u_int8_t *pmkid) { HMAC_SHA256_CTX ctx; u_int8_t digest[SHA256_DIGEST_LENGTH]; HMAC_SHA256_Init(&ctx, pmk, IEEE80211_PMK_LEN); HMAC_SHA256_Update(&ctx, (uint8_t *)"PMK Name", 8); HMAC_SHA256_Update(&ctx, aa, IEEE80211_ADDR_LEN); HMAC_SHA256_Update(&ctx, spa, IEEE80211_ADDR_LEN); HMAC_SHA256_Final(digest, &ctx); /* use the first 128 bits of HMAC-SHA-256 */ memcpy(pmkid, digest, IEEE80211_PMKID_LEN); } /* * Derive Pairwise Master Key Identifier (PMKID) (see 8.5.1.2). */ void ieee80211_derive_pmkid(enum ieee80211_akm akm, const u_int8_t *pmk, const u_int8_t *aa, const u_int8_t *spa, u_int8_t *pmkid) { if (ieee80211_is_sha256_akm(akm)) ieee80211_pmkid_sha256(pmk, aa, spa, pmkid); else ieee80211_pmkid_sha1(pmk, aa, spa, pmkid); } typedef union _ANY_CTX { HMAC_MD5_CTX md5; HMAC_SHA1_CTX sha1; AES_CMAC_CTX cmac; } ANY_CTX; /* * Compute the Key MIC field of an EAPOL-Key frame using the specified Key * Confirmation Key (KCK). The hash function can be HMAC-MD5, HMAC-SHA1 * or AES-128-CMAC depending on the EAPOL-Key Key Descriptor Version. */ void ieee80211_eapol_key_mic(struct ieee80211_eapol_key *key, const u_int8_t *kck) { XYLog("%s\n", __FUNCTION__); u_int8_t digest[SHA1_DIGEST_LENGTH]; ANY_CTX ctx; /* XXX off stack? */ u_int len; len = BE_READ_2(key->len) + 4; switch (BE_READ_2(key->info) & EAPOL_KEY_VERSION_MASK) { case EAPOL_KEY_DESC_V1: HMAC_MD5_Init(&ctx.md5, kck, 16); HMAC_MD5_Update(&ctx.md5, (u_int8_t *)key, len); HMAC_MD5_Final(key->mic, &ctx.md5); break; case EAPOL_KEY_DESC_V2: HMAC_SHA1_Init(&ctx.sha1, kck, 16); HMAC_SHA1_Update(&ctx.sha1, (u_int8_t *)key, len); HMAC_SHA1_Final(digest, &ctx.sha1); /* truncate HMAC-SHA1 to its 128 MSBs */ memcpy(key->mic, digest, EAPOL_KEY_MIC_LEN); break; case EAPOL_KEY_DESC_V3: AES_CMAC_Init(&ctx.cmac); AES_CMAC_SetKey(&ctx.cmac, kck); AES_CMAC_Update(&ctx.cmac, (u_int8_t *)key, len); AES_CMAC_Final(key->mic, &ctx.cmac); break; } } /* * Check the MIC of a received EAPOL-Key frame using the specified Key * Confirmation Key (KCK). */ int ieee80211_eapol_key_check_mic(struct ieee80211_eapol_key *key, const u_int8_t *kck) { u_int8_t mic[EAPOL_KEY_MIC_LEN]; memcpy(mic, key->mic, EAPOL_KEY_MIC_LEN); memset(key->mic, 0, EAPOL_KEY_MIC_LEN); ieee80211_eapol_key_mic(key, kck); return timingsafe_bcmp(key->mic, mic, EAPOL_KEY_MIC_LEN) != 0; } #ifndef IEEE80211_STA_ONLY /* * Encrypt the Key Data field of an EAPOL-Key frame using the specified Key * Encryption Key (KEK). The encryption algorithm can be either ARC4 or * AES Key Wrap depending on the EAPOL-Key Key Descriptor Version. */ void ieee80211_eapol_key_encrypt(struct ieee80211com *ic, struct ieee80211_eapol_key *key, const u_int8_t *kek) { union { struct rc4_ctx rc4; aes_key_wrap_ctx aes; } ctx; /* XXX off stack? */ u_int8_t keybuf[EAPOL_KEY_IV_LEN + 16]; u_int16_t len, info; u_int8_t *data; int n; len = BE_READ_2(key->paylen); info = BE_READ_2(key->info); data = (u_int8_t *)(key + 1); switch (info & EAPOL_KEY_VERSION_MASK) { case EAPOL_KEY_DESC_V1: /* set IV to the lower 16 octets of our global key counter */ memcpy(key->iv, ic->ic_globalcnt + 16, 16); /* increment our global key counter (256-bit, big-endian) */ for (n = 31; n >= 0 && ++ic->ic_globalcnt[n] == 0; n--); /* concatenate the EAPOL-Key IV field and the KEK */ memcpy(keybuf, key->iv, EAPOL_KEY_IV_LEN); memcpy(keybuf + EAPOL_KEY_IV_LEN, kek, 16); rc4_keysetup(&ctx.rc4, keybuf, sizeof keybuf); /* discard the first 256 octets of the ARC4 key stream */ rc4_skip(&ctx.rc4, RC4STATE); rc4_crypt(&ctx.rc4, data, data, len); break; case EAPOL_KEY_DESC_V2: case EAPOL_KEY_DESC_V3: if (len < 16 || (len & 7) != 0) { /* insert padding */ n = (len < 16) ? 16 - len : 8 - (len & 7); data[len++] = IEEE80211_ELEMID_VENDOR; memset(&data[len], 0, n - 1); len += n - 1; } aes_key_wrap_set_key_wrap_only(&ctx.aes, kek, 16); aes_key_wrap(&ctx.aes, data, len / 8, data); len += 8; /* AES Key Wrap adds 8 bytes */ /* update key data length */ BE_WRITE_2(key->paylen, len); /* update packet body length */ BE_WRITE_2(key->len, sizeof(*key) + len - 4); break; } } #endif /* IEEE80211_STA_ONLY */ /* * Decrypt the Key Data field of an EAPOL-Key frame using the specified Key * Encryption Key (KEK). The encryption algorithm can be either ARC4 or * AES Key Wrap depending on the EAPOL-Key Key Descriptor Version. */ int ieee80211_eapol_key_decrypt(struct ieee80211_eapol_key *key, const u_int8_t *kek) { union { struct rc4_ctx rc4; aes_key_wrap_ctx aes; } ctx; /* XXX off stack? */ u_int8_t keybuf[EAPOL_KEY_IV_LEN + 16]; u_int16_t len, info; u_int8_t *data; len = BE_READ_2(key->paylen); info = BE_READ_2(key->info); data = (u_int8_t *)(key + 1); switch (info & EAPOL_KEY_VERSION_MASK) { case EAPOL_KEY_DESC_V1: /* concatenate the EAPOL-Key IV field and the KEK */ memcpy(keybuf, key->iv, EAPOL_KEY_IV_LEN); memcpy(keybuf + EAPOL_KEY_IV_LEN, kek, 16); rc4_keysetup(&ctx.rc4, keybuf, sizeof keybuf); /* discard the first 256 octets of the ARC4 key stream */ rc4_skip(&ctx.rc4, RC4STATE); rc4_crypt(&ctx.rc4, data, data, len); return 0; case EAPOL_KEY_DESC_V2: case EAPOL_KEY_DESC_V3: /* Key Data Length must be a multiple of 8 */ if (len < 16 + 8 || (len & 7) != 0) return 1; len -= 8; /* AES Key Wrap adds 8 bytes */ aes_key_wrap_set_key(&ctx.aes, kek, 16); return aes_key_unwrap(&ctx.aes, data, data, len / 8); } return 1; /* unknown Key Descriptor Version */ } /* * Add a PMK entry to the PMKSA cache. */ struct ieee80211_pmk * ieee80211_pmksa_add(struct ieee80211com *ic, enum ieee80211_akm akm, const u_int8_t *macaddr, const u_int8_t *key, u_int32_t lifetime) { struct ieee80211_pmk *pmk; /* check if an entry already exists for this (STA,AKMP) */ TAILQ_FOREACH(pmk, &ic->ic_pmksa, pmk_next) { if (pmk->pmk_akm == akm && IEEE80211_ADDR_EQ(pmk->pmk_macaddr, macaddr)) break; } if (pmk == NULL) { /* allocate a new PMKSA entry */ if ((pmk = (struct ieee80211_pmk *)malloc(sizeof(*pmk), 0, 0)) == NULL) return NULL; pmk->pmk_akm = akm; IEEE80211_ADDR_COPY(pmk->pmk_macaddr, macaddr); TAILQ_INSERT_TAIL(&ic->ic_pmksa, pmk, pmk_next); } memcpy(pmk->pmk_key, key, IEEE80211_PMK_LEN); pmk->pmk_lifetime = lifetime; /* XXX not used yet */ #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) { ieee80211_derive_pmkid(pmk->pmk_akm, pmk->pmk_key, ic->ic_myaddr, macaddr, pmk->pmk_pmkid); } else #endif { ieee80211_derive_pmkid(pmk->pmk_akm, pmk->pmk_key, macaddr, ic->ic_myaddr, pmk->pmk_pmkid); } return pmk; } /* * Check if we have a cached PMK entry for the specified node and PMKID. */ struct ieee80211_pmk * ieee80211_pmksa_find(struct ieee80211com *ic, struct ieee80211_node *ni, const u_int8_t *pmkid) { struct ieee80211_pmk *pmk; TAILQ_FOREACH(pmk, &ic->ic_pmksa, pmk_next) { if (pmk->pmk_akm == ni->ni_rsnakms && IEEE80211_ADDR_EQ(pmk->pmk_macaddr, ni->ni_macaddr) && (pmkid == NULL || memcmp(pmk->pmk_pmkid, pmkid, IEEE80211_PMKID_LEN) == 0)) break; } return pmk; } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_crypto.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_crypto.h,v 1.26 2019/08/16 19:53:32 procter Exp $ */ /*- * Copyright (c) 2007,2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _NET80211_IEEE80211_CRYPTO_H_ #define _NET80211_IEEE80211_CRYPTO_H_ /* * 802.11 protocol crypto-related definitions. */ #define _KERNEL /* * 802.11 ciphers. */ enum ieee80211_cipher { IEEE80211_CIPHER_NONE = 0x00000000, IEEE80211_CIPHER_USEGROUP = 0x00000001, IEEE80211_CIPHER_WEP40 = 0x00000002, IEEE80211_CIPHER_TKIP = 0x00000004, IEEE80211_CIPHER_CCMP = 0x00000008, IEEE80211_CIPHER_WEP104 = 0x00000010, IEEE80211_CIPHER_BIP = 0x00000020 /* 11w */ }; /* * 802.11 Authentication and Key Management Protocols. */ enum ieee80211_akm { IEEE80211_AKM_NONE = 0x00000000, IEEE80211_AKM_8021X = 0x00000001, IEEE80211_AKM_PSK = 0x00000002, IEEE80211_AKM_SHA256_8021X = 0x00000004, /* 11w */ IEEE80211_AKM_SHA256_PSK = 0x00000008 /* 11w */ }; #define IEEE80211_TKIP_HDRLEN 8 #define IEEE80211_TKIP_MICLEN 8 #define IEEE80211_CCMP_HDRLEN 8 #define IEEE80211_CCMP_MICLEN 8 #define IEEE80211_WEP_IVLEN 4 #define IEEE80211_WEP_ICVLEN 4 #define IEEE80211_CCMP_PNLEN 6 #define IEEE80211_CCMP_256_HDRLEN 8 #define IEEE80211_CCMP_256_MICLEN 16 #define IEEE80211_CCMP_256_PNLEN 6 #define IEEE80211_TKIP_IVLEN 8 #define IEEE80211_TKIP_ICVLEN 4 #define IEEE80211_CMAC_PNLEN 6 #define IEEE80211_GMAC_PNLEN 6 #define IEEE80211_GCMP_HDRLEN 8 #define IEEE80211_GCMP_MICLEN 16 #define IEEE80211_GCMP_PNLEN 6 #define IEEE80211_PMK_LEN 32 #ifdef _KERNEL static __inline int ieee80211_is_8021x_akm(enum ieee80211_akm akm) { return akm == IEEE80211_AKM_8021X || akm == IEEE80211_AKM_SHA256_8021X; } static __inline int ieee80211_is_sha256_akm(enum ieee80211_akm akm) { return akm == IEEE80211_AKM_SHA256_8021X || akm == IEEE80211_AKM_SHA256_PSK; } struct ieee80211_key { u_int8_t k_id; /* identifier (0-5) */ enum ieee80211_cipher k_cipher; u_int k_flags; #define IEEE80211_KEY_GROUP 0x00000001 /* group data key */ #define IEEE80211_KEY_TX 0x00000002 /* Tx+Rx */ #define IEEE80211_KEY_IGTK 0x00000004 /* integrity group key */ #define IEEE80211_KEY_SWCRYPTO 0x00000080 /* loaded for software crypto */ u_int k_len; u_int64_t k_rsc[IEEE80211_NUM_TID]; u_int64_t k_mgmt_rsc; u_int64_t k_tsc; u_int8_t k_key[32]; void *k_priv; }; #define IEEE80211_KEYBUF_SIZE 16 /* * Entry in the PMKSA cache. */ struct ieee80211_pmk { enum ieee80211_akm pmk_akm; u_int32_t pmk_lifetime; #define IEEE80211_PMK_INFINITE 0 u_int8_t pmk_pmkid[IEEE80211_PMKID_LEN]; u_int8_t pmk_macaddr[IEEE80211_ADDR_LEN]; u_int8_t pmk_key[IEEE80211_PMK_LEN]; TAILQ_ENTRY(ieee80211_pmk) pmk_next; }; /* forward references */ struct ieee80211com; struct ieee80211_node; void ieee80211_crypto_attach(struct _ifnet *); void ieee80211_crypto_detach(struct _ifnet *); void ieee80211_crypto_clear_groupkeys(struct ieee80211com *); struct ieee80211_key *ieee80211_get_txkey(struct ieee80211com *, const struct ieee80211_frame *, struct ieee80211_node *); struct ieee80211_key *ieee80211_get_rxkey(struct ieee80211com *, mbuf_t, struct ieee80211_node *); mbuf_t ieee80211_encrypt(struct ieee80211com *, mbuf_t, struct ieee80211_key *); mbuf_t ieee80211_decrypt(struct ieee80211com *, mbuf_t, struct ieee80211_node *); int ieee80211_set_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); void ieee80211_delete_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); void ieee80211_eapol_key_mic(struct ieee80211_eapol_key *, const u_int8_t *); int ieee80211_eapol_key_check_mic(struct ieee80211_eapol_key *, const u_int8_t *); #ifndef IEEE80211_STA_ONLY void ieee80211_eapol_key_encrypt(struct ieee80211com *, struct ieee80211_eapol_key *, const u_int8_t *); #endif int ieee80211_eapol_key_decrypt(struct ieee80211_eapol_key *, const u_int8_t *); struct ieee80211_pmk *ieee80211_pmksa_add(struct ieee80211com *, enum ieee80211_akm, const u_int8_t *, const u_int8_t *, u_int32_t); struct ieee80211_pmk *ieee80211_pmksa_find(struct ieee80211com *, struct ieee80211_node *, const u_int8_t *); void ieee80211_derive_ptk(enum ieee80211_akm, const u_int8_t *, const u_int8_t *, const u_int8_t *, const u_int8_t *, const u_int8_t *, struct ieee80211_ptk *); int ieee80211_cipher_keylen(enum ieee80211_cipher); int ieee80211_wep_set_key(struct ieee80211com *, struct ieee80211_key *); void ieee80211_wep_delete_key(struct ieee80211com *, struct ieee80211_key *); mbuf_t ieee80211_wep_encrypt(struct ieee80211com *, mbuf_t, struct ieee80211_key *); mbuf_t ieee80211_wep_decrypt(struct ieee80211com *, mbuf_t, struct ieee80211_key *); int ieee80211_tkip_set_key(struct ieee80211com *, struct ieee80211_key *); void ieee80211_tkip_delete_key(struct ieee80211com *, struct ieee80211_key *); mbuf_t ieee80211_tkip_encrypt(struct ieee80211com *, mbuf_t, struct ieee80211_key *); int ieee80211_tkip_get_tsc(uint64_t *, uint64_t **, mbuf_t, struct ieee80211_key *); mbuf_t ieee80211_tkip_decrypt(struct ieee80211com *, mbuf_t, struct ieee80211_key *); void ieee80211_tkip_mic(mbuf_t, int, const u_int8_t *, u_int8_t[IEEE80211_TKIP_MICLEN]); void ieee80211_michael_mic_failure(struct ieee80211com *, u_int64_t); #ifndef IEEE80211_STA_ONLY void ieee80211_michael_mic_failure_timeout(void *); #endif int ieee80211_ccmp_set_key(struct ieee80211com *, struct ieee80211_key *); void ieee80211_ccmp_delete_key(struct ieee80211com *, struct ieee80211_key *); mbuf_t ieee80211_ccmp_encrypt(struct ieee80211com *, mbuf_t, struct ieee80211_key *); int ieee80211_ccmp_get_pn(uint64_t *, uint64_t **, mbuf_t, struct ieee80211_key *); mbuf_t ieee80211_ccmp_decrypt(struct ieee80211com *, mbuf_t, struct ieee80211_key *); int ieee80211_bip_set_key(struct ieee80211com *, struct ieee80211_key *); void ieee80211_bip_delete_key(struct ieee80211com *, struct ieee80211_key *); mbuf_t ieee80211_bip_encap(struct ieee80211com *, mbuf_t, struct ieee80211_key *); mbuf_t ieee80211_bip_decap(struct ieee80211com *, mbuf_t, struct ieee80211_key *); #endif /* _KERNEL */ #endif /* _NET80211_IEEE80211_CRYPTO_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_crypto_bip.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. */ /* $OpenBSD: ieee80211_crypto_bip.c,v 1.10 2018/11/09 14:14:31 claudio Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the Broadcast/Multicast Integrity Protocol (BIP) * defined in IEEE P802.11w/D7.0 section 8.3.4. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* BIP software crypto context */ struct ieee80211_bip_ctx { AES_CMAC_CTX cmac; }; /* * Initialize software crypto context. This function can be overridden * by drivers doing hardware crypto. */ int ieee80211_bip_set_key(struct ieee80211com *ic, struct ieee80211_key *k) { struct ieee80211_bip_ctx *ctx; ctx = (struct ieee80211_bip_ctx *)malloc(sizeof(*ctx), 0, 0); if (ctx == NULL) return ENOMEM; AES_CMAC_SetKey(&ctx->cmac, k->k_key); k->k_priv = ctx; return 0; } void ieee80211_bip_delete_key(struct ieee80211com *ic, struct ieee80211_key *k) { if (k->k_priv != NULL) { explicit_bzero(k->k_priv, sizeof(struct ieee80211_bip_ctx)); free(k->k_priv); } k->k_priv = NULL; } /* pseudo-header used for BIP MIC computation */ struct ieee80211_bip_frame { u_int8_t i_fc[2]; u_int8_t i_addr1[IEEE80211_ADDR_LEN]; u_int8_t i_addr2[IEEE80211_ADDR_LEN]; u_int8_t i_addr3[IEEE80211_ADDR_LEN]; } __packed; mbuf_t ieee80211_bip_encap(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_key *k) { struct ieee80211_bip_ctx *ctx = (struct ieee80211_bip_ctx *)k->k_priv; struct ieee80211_bip_frame aad; struct ieee80211_frame *wh; u_int8_t *mmie, mic[AES_CMAC_DIGEST_LENGTH]; mbuf_t m; mbuf_t temp; wh = mtod(m0, struct ieee80211_frame *); _KASSERT((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT); /* clear Protected bit from group management frames */ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; /* construct AAD (additional authenticated data) */ aad.i_fc[0] = wh->i_fc[0]; aad.i_fc[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | IEEE80211_FC1_MORE_DATA); /* XXX 11n may require clearing the Order bit too */ IEEE80211_ADDR_COPY(aad.i_addr1, wh->i_addr1); IEEE80211_ADDR_COPY(aad.i_addr2, wh->i_addr2); IEEE80211_ADDR_COPY(aad.i_addr3, wh->i_addr3); AES_CMAC_Init(&ctx->cmac); AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&aad, sizeof aad); AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&wh[1], mbuf_len(m0) - sizeof(*wh)); m = m0; /* reserve trailing space for MMIE */ if (mbuf_trailingspace(m) < IEEE80211_MMIE_LEN) { temp = NULL; mbuf_mclget(MBUF_DONTWAIT, mbuf_type(m), &temp); if (temp == NULL) goto nospace; mbuf_setnext(m, temp); m = temp; mbuf_setlen(m, 0); } /* construct Management MIC IE */ mmie = mtod(m, u_int8_t *) + mbuf_len(m); mmie[0] = IEEE80211_ELEMID_MMIE; mmie[1] = 16; LE_WRITE_2(&mmie[2], k->k_id); LE_WRITE_6(&mmie[4], k->k_tsc); memset(&mmie[10], 0, 8); /* MMIE MIC field set to 0 */ AES_CMAC_Update(&ctx->cmac, mmie, IEEE80211_MMIE_LEN); AES_CMAC_Final(mic, &ctx->cmac); /* truncate AES-128-CMAC to 64-bit */ memcpy(&mmie[10], mic, 8); mbuf_setlen(m, mbuf_len(m) + IEEE80211_MMIE_LEN); mbuf_pkthdr_setlen(m0, mbuf_pkthdr_len(m0) + IEEE80211_MMIE_LEN); k->k_tsc++; return m0; nospace: ic->ic_stats.is_tx_nombuf++; mbuf_freem(m0); return NULL; } mbuf_t ieee80211_bip_decap(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_key *k) { struct ieee80211_bip_ctx *ctx = (struct ieee80211_bip_ctx *)k->k_priv; struct ieee80211_frame *wh; struct ieee80211_bip_frame aad; u_int8_t *mmie, mic0[8], mic[AES_CMAC_DIGEST_LENGTH]; u_int64_t ipn; wh = mtod(m0, struct ieee80211_frame *); _KASSERT((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT); /* * It is assumed that management frames are contiguous and that * the mbuf length has already been checked to contain at least * a header and a MMIE (checked in ieee80211_decrypt()). */ _KASSERT(m0->m_len >= sizeof(*wh) + IEEE80211_MMIE_LEN); mmie = mtod(m0, u_int8_t *) + mbuf_len(m0) - IEEE80211_MMIE_LEN; ipn = LE_READ_6(&mmie[4]); if (ipn <= k->k_mgmt_rsc) { /* replayed frame, discard */ ic->ic_stats.is_cmac_replays++; mbuf_freem(m0); return NULL; } /* save and mask MMIE MIC field to 0 */ memcpy(mic0, &mmie[10], 8); memset(&mmie[10], 0, 8); /* construct AAD (additional authenticated data) */ aad.i_fc[0] = wh->i_fc[0]; aad.i_fc[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | IEEE80211_FC1_MORE_DATA); /* XXX 11n may require clearing the Order bit too */ IEEE80211_ADDR_COPY(aad.i_addr1, wh->i_addr1); IEEE80211_ADDR_COPY(aad.i_addr2, wh->i_addr2); IEEE80211_ADDR_COPY(aad.i_addr3, wh->i_addr3); /* compute MIC */ AES_CMAC_Init(&ctx->cmac); AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&aad, sizeof aad); AES_CMAC_Update(&ctx->cmac, (u_int8_t *)&wh[1], mbuf_len(m0) - sizeof(*wh)); AES_CMAC_Final(mic, &ctx->cmac); /* check that MIC matches the one in MMIE */ if (timingsafe_bcmp(mic, mic0, 8) != 0) { ic->ic_stats.is_cmac_icv_errs++; mbuf_freem(m0); return NULL; } /* * There is no need to trim the MMIE from the mbuf since it is * an information element and will be ignored by upper layers. * We do it anyway as it is cheap to do it here and because it * may be confused with fixed fields by upper layers. */ mbuf_adj(m0, -IEEE80211_MMIE_LEN); /* update last seen packet number (MIC is validated) */ k->k_mgmt_rsc = ipn; return m0; } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_crypto_ccmp.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. */ /* $OpenBSD: ieee80211_crypto_ccmp.c,v 1.21 2018/11/09 14:14:31 claudio Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the CTR with CBC-MAC protocol (CCMP) defined in * IEEE Std 802.11-2007 section 8.3.3. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* CCMP software crypto context */ struct ieee80211_ccmp_ctx { AES_CTX aesctx; }; /* * Initialize software crypto context. This function can be overridden * by drivers doing hardware crypto. */ int ieee80211_ccmp_set_key(struct ieee80211com *ic, struct ieee80211_key *k) { struct ieee80211_ccmp_ctx *ctx; ctx = (struct ieee80211_ccmp_ctx *)malloc(sizeof(*ctx), 0, 0); if (ctx == NULL) return ENOMEM; AES_Setkey(&ctx->aesctx, k->k_key, 16); k->k_priv = ctx; return 0; } void ieee80211_ccmp_delete_key(struct ieee80211com *ic, struct ieee80211_key *k) { if (k->k_priv != NULL) { explicit_bzero(k->k_priv, sizeof(struct ieee80211_ccmp_ctx)); free(k->k_priv); } k->k_priv = NULL; } /*- * Counter with CBC-MAC (CCM) - see RFC3610. * CCMP uses the following CCM parameters: M = 8, L = 2 */ static void ieee80211_ccmp_phase1(AES_CTX *ctx, const struct ieee80211_frame *wh, u_int64_t pn, int lm, u_int8_t b[16], u_int8_t a[16], u_int8_t s0[16]) { u_int8_t auth[32], nonce[13]; u_int8_t *aad; u_int8_t tid = 0; int la, i; /* construct AAD (additional authenticated data) */ aad = &auth[2]; /* skip l(a), will be filled later */ *aad = wh->i_fc[0]; /* 11w: conditionally mask subtype field */ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) *aad &= ~IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS; aad++; /* protected bit is already set in wh */ *aad = wh->i_fc[1]; *aad &= ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | IEEE80211_FC1_MORE_DATA); /* 11n: conditionally mask order bit */ if (ieee80211_has_qos(wh)) *aad &= ~IEEE80211_FC1_ORDER; aad++; IEEE80211_ADDR_COPY(aad, wh->i_addr1); aad += IEEE80211_ADDR_LEN; IEEE80211_ADDR_COPY(aad, wh->i_addr2); aad += IEEE80211_ADDR_LEN; IEEE80211_ADDR_COPY(aad, wh->i_addr3); aad += IEEE80211_ADDR_LEN; *aad++ = wh->i_seq[0] & ~0xf0; *aad++ = 0; if (ieee80211_has_addr4(wh)) { IEEE80211_ADDR_COPY(aad, ((const struct ieee80211_frame_addr4 *)wh)->i_addr4); aad += IEEE80211_ADDR_LEN; } if (ieee80211_has_qos(wh)) { /* * XXX 802.11-2012 11.4.3.3.3 g says the A-MSDU present bit * must be set here if both STAs are SPP A-MSDU capable. */ *aad++ = tid = ieee80211_get_qos(wh) & IEEE80211_QOS_TID; *aad++ = 0; } /* construct CCM nonce */ nonce[ 0] = tid; if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) nonce[0] |= 1 << 4; /* 11w: set management bit */ IEEE80211_ADDR_COPY(&nonce[1], wh->i_addr2); nonce[ 7] = pn >> 40; /* PN5 */ nonce[ 8] = pn >> 32; /* PN4 */ nonce[ 9] = pn >> 24; /* PN3 */ nonce[10] = pn >> 16; /* PN2 */ nonce[11] = pn >> 8; /* PN1 */ nonce[12] = pn; /* PN0 */ /* add 2 authentication blocks (including l(a) and padded AAD) */ la = aad - &auth[2]; /* fill l(a) */ auth[0] = la >> 8; auth[1] = la & 0xff; memset(aad, 0, 30 - la); /* pad AAD with zeros */ /* construct first block B_0 */ b[ 0] = 89; /* Flags = 64*Adata + 8*((M-2)/2) + (L-1) */ memcpy(&b[1], nonce, 13); b[14] = lm >> 8; b[15] = lm & 0xff; AES_Encrypt(ctx, b, b); for (i = 0; i < 16; i++) b[i] ^= auth[i]; AES_Encrypt(ctx, b, b); for (i = 0; i < 16; i++) b[i] ^= auth[16 + i]; AES_Encrypt(ctx, b, b); /* construct S_0 */ a[ 0] = 1; /* Flags = L' = (L-1) */ memcpy(&a[1], nonce, 13); a[14] = a[15] = 0; AES_Encrypt(ctx, a, s0); } mbuf_t ieee80211_ccmp_encrypt(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_key *k) { struct ieee80211_ccmp_ctx *ctx = (struct ieee80211_ccmp_ctx *)k->k_priv; const struct ieee80211_frame *wh; const u_int8_t *src; u_int8_t *ivp, *mic, *dst; u_int8_t a[16], b[16], s0[16], s[16]; mbuf_t n0, m, n; int hdrlen, left, moff, noff, len; u_int16_t ctr; int i, j; mbuf_t temp; unsigned int max_chunks = 1; mbuf_get(MBUF_DONTWAIT, mbuf_type(m0), &n0); if (n0 == NULL) goto nospace; if (m_dup_pkthdr(n0, m0, MBUF_DONTWAIT)) goto nospace; mbuf_pkthdr_setlen(n0, mbuf_pkthdr_len(n0) + IEEE80211_CCMP_HDRLEN); mbuf_setlen(n0, mbuf_get_mhlen()); if (mbuf_pkthdr_len(n0) >= mbuf_get_minclsize() - IEEE80211_CCMP_MICLEN) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n0), &n0); if (mbuf_flags(n0) & MBUF_EXT) mbuf_setlen(n0, MCLBYTES); } if (mbuf_len(n0) > mbuf_pkthdr_len(n0)) mbuf_setlen(n0, mbuf_pkthdr_len(n0)); /* copy 802.11 header */ wh = mtod(m0, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); memcpy(mtod(n0, caddr_t), wh, hdrlen); k->k_tsc++; /* increment the 48-bit PN */ /* construct CCMP header */ ivp = mtod(n0, u_int8_t *) + hdrlen; ivp[0] = k->k_tsc; /* PN0 */ ivp[1] = k->k_tsc >> 8; /* PN1 */ ivp[2] = 0; /* Rsvd */ ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; /* KeyID | ExtIV */ ivp[4] = k->k_tsc >> 16; /* PN2 */ ivp[5] = k->k_tsc >> 24; /* PN3 */ ivp[6] = k->k_tsc >> 32; /* PN4 */ ivp[7] = k->k_tsc >> 40; /* PN5 */ /* construct initial B, A and S_0 blocks */ ieee80211_ccmp_phase1(&ctx->aesctx, wh, k->k_tsc, mbuf_pkthdr_len(m0) - hdrlen, b, a, s0); /* construct S_1 */ ctr = 1; a[14] = ctr >> 8; a[15] = ctr & 0xff; AES_Encrypt(&ctx->aesctx, a, s); /* encrypt frame body and compute MIC */ j = 0; m = m0; n = n0; moff = hdrlen; noff = hdrlen + IEEE80211_CCMP_HDRLEN; left = mbuf_pkthdr_len(m0) - moff; while (left > 0) { if (moff == mbuf_len(m)) { /* nothing left to copy from m */ m = mbuf_next(m); moff = 0; } if (noff == mbuf_len(n)) { /* n is full and there's more data to copy */ temp = NULL; mbuf_get(MBUF_DONTWAIT, mbuf_type(n), &temp); if (temp == NULL) goto nospace; mbuf_setnext(n, temp); n = mbuf_next(n); mbuf_setlen(n, mbuf_get_mlen()); if (left >= mbuf_get_minclsize() - IEEE80211_CCMP_MICLEN) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n), &n); if (mbuf_flags(n) & MBUF_EXT) mbuf_setlen(n, MCLBYTES); } if (mbuf_len(n) > left) mbuf_setlen(n, left); noff = 0; } len = min(mbuf_len(m) - moff, mbuf_len(n) - noff); src = mtod(m, u_int8_t *) + moff; dst = mtod(n, u_int8_t *) + noff; for (i = 0; i < len; i++) { /* update MIC with clear text */ b[j] ^= src[i]; /* encrypt message */ dst[i] = src[i] ^ s[j]; if (++j < 16) continue; /* we have a full block, encrypt MIC */ AES_Encrypt(&ctx->aesctx, b, b); /* construct a new S_ctr block */ ctr++; a[14] = ctr >> 8; a[15] = ctr & 0xff; AES_Encrypt(&ctx->aesctx, a, s); j = 0; } moff += len; noff += len; left -= len; } if (j != 0) /* partial block, encrypt MIC */ AES_Encrypt(&ctx->aesctx, b, b); /* reserve trailing space for MIC */ if (mbuf_trailingspace(n) < IEEE80211_CCMP_MICLEN) { temp = NULL; mbuf_get(MBUF_DONTWAIT, mbuf_type(n), &temp); if (temp == NULL) goto nospace; mbuf_setnext(n, temp); n = mbuf_next(n); mbuf_setlen(n, 0); } /* finalize MIC, U := T XOR first-M-bytes( S_0 ) */ mic = mtod(n, u_int8_t *) + mbuf_len(n); for (i = 0; i < IEEE80211_CCMP_MICLEN; i++) mic[i] = b[i] ^ s0[i]; mbuf_setlen(n, mbuf_len(n) + IEEE80211_CCMP_MICLEN); mbuf_pkthdr_setlen(n0, mbuf_pkthdr_len(n0) + IEEE80211_CCMP_MICLEN); mbuf_freem(m0); return n0; nospace: ic->ic_stats.is_tx_nombuf++; mbuf_freem(m0); mbuf_freem(n0); return NULL; } int ieee80211_ccmp_get_pn(uint64_t *pn, uint64_t **prsc, mbuf_t m, struct ieee80211_key *k) { struct ieee80211_frame *wh; int hdrlen; const u_int8_t *ivp; wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); if (mbuf_pkthdr_len(m) < hdrlen + IEEE80211_CCMP_HDRLEN) return EINVAL; ivp = (u_int8_t *)wh + hdrlen; /* check that ExtIV bit is set */ if (!(ivp[3] & IEEE80211_WEP_EXTIV)) return EINVAL; /* retrieve last seen packet number for this frame type/priority */ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { u_int8_t tid = ieee80211_has_qos(wh) ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; *prsc = &k->k_rsc[tid]; } else /* 11w: management frames have their own counters */ *prsc = &k->k_mgmt_rsc; /* extract the 48-bit PN from the CCMP header */ *pn = (u_int64_t)ivp[0] | (u_int64_t)ivp[1] << 8 | (u_int64_t)ivp[4] << 16 | (u_int64_t)ivp[5] << 24 | (u_int64_t)ivp[6] << 32 | (u_int64_t)ivp[7] << 40; return 0; } mbuf_t ieee80211_ccmp_decrypt(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_key *k) { struct ieee80211_ccmp_ctx *ctx = (struct ieee80211_ccmp_ctx *)k->k_priv; struct ieee80211_frame *wh; u_int64_t pn, *prsc; const u_int8_t *src; u_int8_t *dst; u_int8_t mic0[IEEE80211_CCMP_MICLEN]; u_int8_t a[16], b[16], s0[16], s[16]; mbuf_t n0, m, n; int hdrlen, left, moff, noff, len; u_int16_t ctr; int i, j; mbuf_t temp; unsigned int max_chunks = 1; wh = mtod(m0, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); if (mbuf_pkthdr_len(m0) < hdrlen + IEEE80211_CCMP_HDRLEN + IEEE80211_CCMP_MICLEN) { mbuf_freem(m0); return NULL; } /* * Get the frame's Packet Number (PN) and a pointer to our last-seen * Receive Sequence Counter (RSC) which we can use to detect replays. */ if (ieee80211_ccmp_get_pn(&pn, &prsc, m0, k) != 0) { mbuf_freem(m0); return NULL; } if (pn <= *prsc) { /* replayed frame, discard */ ic->ic_stats.is_ccmp_replays++; mbuf_freem(m0); return NULL; } mbuf_get(MBUF_DONTWAIT, mbuf_type(m0), &n0); if (n0 == NULL) goto nospace; if (m_dup_pkthdr(n0, m0, MBUF_DONTWAIT)) goto nospace; mbuf_pkthdr_setlen(n0, mbuf_pkthdr_len(n0) - (IEEE80211_CCMP_HDRLEN + IEEE80211_CCMP_MICLEN)); mbuf_setlen(n0, mbuf_get_mhlen()); if (mbuf_pkthdr_len(n0) >= mbuf_get_minclsize()) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n0), &n0); if (mbuf_flags(n0) & MBUF_EXT) mbuf_setlen(n0, MCLBYTES); } if (mbuf_len(n0) > mbuf_pkthdr_len(n0)) mbuf_setlen(n0, mbuf_pkthdr_len(n0)); /* construct initial B, A and S_0 blocks */ ieee80211_ccmp_phase1(&ctx->aesctx, wh, pn, mbuf_pkthdr_len(n0) - hdrlen, b, a, s0); /* copy 802.11 header and clear protected bit */ memcpy(mtod(n0, caddr_t), wh, hdrlen); wh = mtod(n0, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; /* construct S_1 */ ctr = 1; a[14] = ctr >> 8; a[15] = ctr & 0xff; AES_Encrypt(&ctx->aesctx, a, s); /* decrypt frame body and compute MIC */ j = 0; m = m0; n = n0; moff = hdrlen + IEEE80211_CCMP_HDRLEN; noff = hdrlen; left = mbuf_pkthdr_len(n0) - noff; while (left > 0) { if (moff == mbuf_len(m)) { /* nothing left to copy from m */ m = mbuf_next(m); moff = 0; } if (noff == mbuf_len(n)) { /* n is full and there's more data to copy */ temp = NULL; mbuf_get(MBUF_DONTWAIT, mbuf_type(n), &temp); if (temp == NULL) goto nospace; mbuf_setnext(n, temp); n = mbuf_next(n); mbuf_setlen(n, mbuf_get_mlen()); if (left >= mbuf_get_minclsize()) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n), &n); if (mbuf_flags(n) & MBUF_EXT) mbuf_setlen(n, MCLBYTES); } if (mbuf_len(n) > left) mbuf_setlen(n, left); noff = 0; } len = min(mbuf_len(m) - moff, mbuf_len(n) - noff); src = mtod(m, u_int8_t *) + moff; dst = mtod(n, u_int8_t *) + noff; for (i = 0; i < len; i++) { /* decrypt message */ dst[i] = src[i] ^ s[j]; /* update MIC with clear text */ b[j] ^= dst[i]; if (++j < 16) continue; /* we have a full block, encrypt MIC */ AES_Encrypt(&ctx->aesctx, b, b); /* construct a new S_ctr block */ ctr++; a[14] = ctr >> 8; a[15] = ctr & 0xff; AES_Encrypt(&ctx->aesctx, a, s); j = 0; } moff += len; noff += len; left -= len; } if (j != 0) /* partial block, encrypt MIC */ AES_Encrypt(&ctx->aesctx, b, b); /* finalize MIC, U := T XOR first-M-bytes( S_0 ) */ for (i = 0; i < IEEE80211_CCMP_MICLEN; i++) b[i] ^= s0[i]; /* check that it matches the MIC in received frame */ mbuf_copydata(m, moff, IEEE80211_CCMP_MICLEN, mic0); if (timingsafe_bcmp(mic0, b, IEEE80211_CCMP_MICLEN) != 0) { ic->ic_stats.is_ccmp_dec_errs++; mbuf_freem(m0); mbuf_freem(n0); return NULL; } /* update last seen packet number (MIC is validated) */ *prsc = pn; mbuf_freem(m0); return n0; nospace: ic->ic_stats.is_rx_nombuf++; mbuf_freem(m0); mbuf_freem(n0); return NULL; } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_crypto_tkip.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. */ /* $OpenBSD: ieee80211_crypto_tkip.c,v 1.30 2018/11/09 14:14:31 claudio Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the Temporal Key Integrity Protocol (TKIP) defined * in IEEE Std 802.11-2007 section 8.3.2. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef u_int8_t byte; /* 8-bit byte (octet) */ typedef u_int16_t u16b; /* 16-bit unsigned word */ typedef u_int32_t u32b; /* 32-bit unsigned word */ static void Phase1(u16b *, const byte *, const byte *, u32b); static void Phase2(byte *, const byte *, const u16b *, u16b); /* TKIP software crypto context */ struct ieee80211_tkip_ctx { struct rc4_ctx rc4; const u_int8_t *txmic; const u_int8_t *rxmic; u_int16_t txttak[5]; u_int16_t rxttak[5]; u_int8_t txttak_ok; u_int8_t rxttak_ok; }; /* * Initialize software crypto context. This function can be overridden * by drivers doing hardware crypto. */ int ieee80211_tkip_set_key(struct ieee80211com *ic, struct ieee80211_key *k) { struct ieee80211_tkip_ctx *ctx; ctx = (struct ieee80211_tkip_ctx *)malloc(sizeof(*ctx), 0, 0); if (ctx == NULL) return ENOMEM; /* * Use bits 128-191 as the Michael key for AA->SPA and bits * 192-255 as the Michael key for SPA->AA. */ #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) { ctx->txmic = &k->k_key[16]; ctx->rxmic = &k->k_key[24]; } else #endif { #ifdef USE_APPLE_SUPPLICANT ctx->txmic = &k->k_key[16]; ctx->rxmic = &k->k_key[24]; #else ctx->rxmic = &k->k_key[16]; ctx->txmic = &k->k_key[24]; #endif } k->k_priv = ctx; XYLog("%s kid=%d klen=%d key=%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X \n", __FUNCTION__, k->k_id, k->k_len, k->k_key[0], k->k_key[1], k->k_key[2], k->k_key[3], k->k_key[4], k->k_key[5], k->k_key[6], k->k_key[7], k->k_key[8], k->k_key[9], k->k_key[10], k->k_key[11], k->k_key[12], k->k_key[13], k->k_key[14], k->k_key[15], k->k_key[16], k->k_key[17], k->k_key[18], k->k_key[19], k->k_key[20], k->k_key[21], k->k_key[22], k->k_key[23], k->k_key[24], k->k_key[25], k->k_key[26], k->k_key[27], k->k_key[28], k->k_key[29], k->k_key[30], k->k_key[31]); XYLog("%s rxmic=%02X %02X %02X %02X %02X %02X %02X %02X txmic=%02X %02X %02X %02X %02X %02X %02X %02X ", __FUNCTION__, ctx->rxmic[0], ctx->rxmic[1], ctx->rxmic[2], ctx->rxmic[3], ctx->rxmic[4], ctx->rxmic[5], ctx->rxmic[6], ctx->rxmic[7], ctx->txmic[0], ctx->txmic[1], ctx->txmic[2], ctx->txmic[3], ctx->txmic[4], ctx->txmic[5], ctx->txmic[6], ctx->txmic[7]); return 0; } void ieee80211_tkip_delete_key(struct ieee80211com *ic, struct ieee80211_key *k) { if (k->k_priv != NULL) { explicit_bzero(k->k_priv, sizeof(struct ieee80211_tkip_ctx)); free(k->k_priv); } k->k_priv = NULL; } /* pseudo-header used for TKIP MIC computation */ struct ieee80211_tkip_frame { u_int8_t i_da[IEEE80211_ADDR_LEN]; u_int8_t i_sa[IEEE80211_ADDR_LEN]; u_int8_t i_pri; u_int8_t i_pad[3]; } __packed; /* * Compute TKIP MIC over an mbuf chain starting "off" bytes from the * beginning. This function should be kept independant from the software * TKIP crypto code so that drivers doing hardware crypto but not MIC can * call it without a software crypto context. */ void ieee80211_tkip_mic(mbuf_t m0, int off, const u_int8_t *key, u_int8_t mic[IEEE80211_TKIP_MICLEN]) { const struct ieee80211_frame *wh; struct ieee80211_tkip_frame wht; MICHAEL_CTX ctx; /* small enough */ mbuf_t m; caddr_t pos; int len; /* assumes 802.11 header is contiguous */ wh = mtod(m0, struct ieee80211_frame *); /* construct pseudo-header for TKIP MIC computation */ switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr1); IEEE80211_ADDR_COPY(wht.i_sa, wh->i_addr2); break; case IEEE80211_FC1_DIR_TODS: IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr3); IEEE80211_ADDR_COPY(wht.i_sa, wh->i_addr2); break; case IEEE80211_FC1_DIR_FROMDS: IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr1); IEEE80211_ADDR_COPY(wht.i_sa, wh->i_addr3); break; case IEEE80211_FC1_DIR_DSTODS: IEEE80211_ADDR_COPY(wht.i_da, wh->i_addr3); IEEE80211_ADDR_COPY(wht.i_sa, ((const struct ieee80211_frame_addr4 *)wh)->i_addr4); break; } if (ieee80211_has_qos(wh)) wht.i_pri = ieee80211_get_qos(wh) & IEEE80211_QOS_TID; else wht.i_pri = 0; wht.i_pad[0] = wht.i_pad[1] = wht.i_pad[2] = 0; michael_init(&ctx); michael_key(key, &ctx); michael_update((MICHAEL_CTX *)&ctx, (const u_int8_t *)&wht, sizeof(wht)); m = m0; /* assumes the first "off" bytes are contiguous */ pos = mtod(m, caddr_t) + off; len = mbuf_len(m) - off; for (;;) { michael_update(&ctx, (const u_int8_t *)pos, len); if ((m = mbuf_next(m)) == NULL) break; pos = mtod(m, caddr_t); len = mbuf_len(m); } michael_final(mic, &ctx); } /* shortcuts */ #define IEEE80211_TKIP_TAILLEN \ (IEEE80211_TKIP_MICLEN + IEEE80211_WEP_CRCLEN) #define IEEE80211_TKIP_OVHD \ (IEEE80211_TKIP_HDRLEN + IEEE80211_TKIP_TAILLEN) mbuf_t ieee80211_tkip_encrypt(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_key *k) { struct ieee80211_tkip_ctx *ctx = (struct ieee80211_tkip_ctx *)k->k_priv; u_int16_t wepseed[8]; /* needs to be 16-bit aligned for Phase2 */ const struct ieee80211_frame *wh; u_int8_t *ivp, *mic, *icvp; mbuf_t n0, m, n; u_int32_t crc; int left, moff, noff, len, hdrlen; mbuf_t temp; unsigned int max_chunks = 1; struct _ifnet *ifp = &ic->ic_ac.ac_if; if (m0 == NULL) { XYLog("%s, m0==NULL\n", __FUNCTION__); return NULL; } mbuf_get(MBUF_DONTWAIT, mbuf_type(m0), &n0); if (n0 == NULL) goto nospace; if (m_dup_pkthdr(n0, m0, MBUF_DONTWAIT)) goto nospace; mbuf_pkthdr_setlen(n0, mbuf_pkthdr_len(n0) + IEEE80211_TKIP_HDRLEN); mbuf_setlen(n0, mbuf_get_mhlen()); if (mbuf_pkthdr_len(n0) >= mbuf_get_minclsize() - IEEE80211_TKIP_TAILLEN) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n0), &n0); if (mbuf_flags(n0) & MBUF_EXT) mbuf_setlen(n0, MCLBYTES); } if (mbuf_len(n0) > mbuf_pkthdr_len(n0)) mbuf_setlen(n0, mbuf_pkthdr_len(n0)); /* copy 802.11 header */ wh = mtod(m0, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); memcpy(mtod(n0, caddr_t), wh, hdrlen); k->k_tsc++; /* increment the 48-bit TSC */ /* construct TKIP header */ ivp = mtod(n0, u_int8_t *) + hdrlen; ivp[0] = k->k_tsc >> 8; /* TSC1 */ /* WEP Seed = (TSC1 | 0x20) & 0x7f (see 8.3.2.2) */ ivp[1] = (ivp[0] | 0x20) & 0x7f; ivp[2] = k->k_tsc; /* TSC0 */ ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; /* KeyID | ExtIV */ ivp[4] = k->k_tsc >> 16; /* TSC2 */ ivp[5] = k->k_tsc >> 24; /* TSC3 */ ivp[6] = k->k_tsc >> 32; /* TSC4 */ ivp[7] = k->k_tsc >> 40; /* TSC5 */ /* compute WEP seed */ if (!ctx->txttak_ok || (k->k_tsc & 0xffff) == 0) { Phase1(ctx->txttak, k->k_key, wh->i_addr2, k->k_tsc >> 16); ctx->txttak_ok = 1; } Phase2((u_int8_t *)wepseed, k->k_key, ctx->txttak, k->k_tsc & 0xffff); rc4_keysetup(&ctx->rc4, (u_int8_t *)wepseed, 16); explicit_bzero(wepseed, sizeof(wepseed)); /* encrypt frame body and compute WEP ICV */ m = m0; n = n0; moff = hdrlen; noff = hdrlen + IEEE80211_TKIP_HDRLEN; left = mbuf_pkthdr_len(m0) - moff; crc = ~0; while (left > 0) { if (moff == mbuf_len(m)) { /* nothing left to copy from m */ m = mbuf_next(m); moff = 0; } if (noff == mbuf_len(n)) { /* n is full and there's more data to copy */ temp = NULL; mbuf_get(MBUF_DONTWAIT, mbuf_type(n), &temp); if (temp == NULL) goto nospace; mbuf_setnext(n, temp); n = mbuf_next(n); mbuf_setlen(n, mbuf_get_mlen()); if (left >= mbuf_get_minclsize() - IEEE80211_TKIP_TAILLEN) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n), &n); if (mbuf_flags(n) & MBUF_EXT) mbuf_setlen(n, MCLBYTES); } if (mbuf_len(n) > left) mbuf_setlen(n, left); noff = 0; } len = min(mbuf_len(m) - moff, mbuf_len(n) - noff); crc = ether_crc32_le_update(crc, mtod(m, const u_int8_t *) + moff, len); rc4_crypt(&ctx->rc4, mtod(m, u_char*) + moff, mtod(n, u_char*) + noff, len); moff += len; noff += len; left -= len; } /* reserve trailing space for TKIP MIC and WEP ICV */ if (mbuf_trailingspace(n) < IEEE80211_TKIP_TAILLEN) { temp = NULL; mbuf_get(MBUF_DONTWAIT, mbuf_type(n), &temp); if (temp == NULL) goto nospace; mbuf_setnext(n, temp); n = mbuf_next(n); mbuf_setlen(n, 0); } /* compute TKIP MIC over clear text */ mic = mtod(n, uint8_t*) + mbuf_len(n); ieee80211_tkip_mic(m0, hdrlen, ctx->txmic, mic); crc = ether_crc32_le_update(crc, mic, IEEE80211_TKIP_MICLEN); rc4_crypt(&ctx->rc4, mic, mic, IEEE80211_TKIP_MICLEN); mbuf_setlen(n, mbuf_len(n) + IEEE80211_TKIP_MICLEN); /* finalize WEP ICV */ icvp = mtod(n, uint8_t*) + mbuf_len(n); crc = ~crc; icvp[0] = crc; icvp[1] = crc >> 8; icvp[2] = crc >> 16; icvp[3] = crc >> 24; rc4_crypt(&ctx->rc4, icvp, icvp, IEEE80211_WEP_CRCLEN); mbuf_setlen(n, mbuf_len(n) + IEEE80211_WEP_CRCLEN); mbuf_pkthdr_setlen(n0, mbuf_pkthdr_len(n0) + IEEE80211_TKIP_TAILLEN); mbuf_freem(m0); return n0; nospace: ic->ic_stats.is_tx_nombuf++; mbuf_freem(m0); mbuf_freem(n0); return NULL; } int ieee80211_tkip_get_tsc(uint64_t *tsc, uint64_t **prsc, mbuf_t m, struct ieee80211_key *k) { struct ieee80211_frame *wh; int hdrlen; u_int8_t tid; const u_int8_t *ivp; wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); if (mbuf_pkthdr_len(m) < hdrlen + IEEE80211_TKIP_HDRLEN) return EINVAL; ivp = (u_int8_t *)wh + hdrlen; /* check that ExtIV bit is set */ if (!(ivp[3] & IEEE80211_WEP_EXTIV)) return EINVAL; /* Retrieve last seen packet number for this frame priority. */ tid = ieee80211_has_qos(wh) ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; *prsc = &k->k_rsc[tid]; /* extract the 48-bit TSC from the TKIP header */ *tsc = (u_int64_t)ivp[2] | (u_int64_t)ivp[0] << 8 | (u_int64_t)ivp[4] << 16 | (u_int64_t)ivp[5] << 24 | (u_int64_t)ivp[6] << 32 | (u_int64_t)ivp[7] << 40; return 0; } mbuf_t ieee80211_tkip_decrypt(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_key *k) { struct ieee80211_tkip_ctx *ctx = (struct ieee80211_tkip_ctx *)k->k_priv; struct ieee80211_frame *wh; u_int16_t wepseed[8]; /* needs to be 16-bit aligned for Phase2 */ u_int8_t buf[IEEE80211_TKIP_MICLEN + IEEE80211_WEP_CRCLEN]; u_int8_t mic[IEEE80211_TKIP_MICLEN]; u_int64_t tsc, *prsc; u_int32_t crc, crc0; u_int8_t *mic0; mbuf_t n0, m, n; int hdrlen, left, moff, noff, len; mbuf_t temp; unsigned int max_chunks = 1; struct _ifnet *ifp = &ic->ic_ac.ac_if; wh = mtod(m0, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); if (mbuf_pkthdr_len(m0) < hdrlen + IEEE80211_TKIP_OVHD) { mbuf_freem(m0); return NULL; } /* * Get the frame's Tansmit Sequence Counter (TSC), and a pointer to * our last-seen Receive Sequence Counter (RSC) with which we can * detect replays. */ if (ieee80211_tkip_get_tsc(&tsc, &prsc, m0, k) != 0) { mbuf_freem(m0); return NULL; } if (tsc <= *prsc) { /* replayed frame, discard */ ic->ic_stats.is_tkip_replays++; mbuf_freem(m0); return NULL; } mbuf_get(MBUF_DONTWAIT, mbuf_type(m0), &n0); if (n0 == NULL) goto nospace; if (m_dup_pkthdr(n0, m0, MBUF_DONTWAIT)) goto nospace; mbuf_pkthdr_setlen(n0, mbuf_pkthdr_len(n0) - IEEE80211_TKIP_OVHD); mbuf_setlen(n0, mbuf_get_mhlen()); if (mbuf_pkthdr_len(n0) >= mbuf_get_minclsize()) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n0), &n0); if (mbuf_flags(n0) & MBUF_EXT) mbuf_setlen(n0, MCLBYTES); } if (mbuf_len(n0) > mbuf_pkthdr_len(n0)) mbuf_setlen(n0, mbuf_pkthdr_len(n0)); /* copy 802.11 header and clear protected bit */ memcpy(mtod(n0, caddr_t), wh, hdrlen); wh = mtod(n0, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; /* compute WEP seed */ if (!ctx->rxttak_ok || (tsc >> 16) != (*prsc >> 16)) { ctx->rxttak_ok = 0; /* invalidate cached TTAK (if any) */ Phase1(ctx->rxttak, k->k_key, wh->i_addr2, tsc >> 16); } Phase2((u_int8_t *)wepseed, k->k_key, ctx->rxttak, tsc & 0xffff); rc4_keysetup(&ctx->rc4, (u_int8_t *)wepseed, 16); explicit_bzero(wepseed, sizeof(wepseed)); /* decrypt frame body and compute WEP ICV */ m = m0; n = n0; moff = hdrlen + IEEE80211_TKIP_HDRLEN; noff = hdrlen; left = mbuf_pkthdr_len(n0) - noff; crc = ~0; while (left > 0) { if (moff == mbuf_len(m)) { /* nothing left to copy from m */ m = mbuf_next(m); moff = 0; } if (noff == mbuf_len(n)) { /* n is full and there's more data to copy */ temp = NULL; mbuf_get(MBUF_DONTWAIT, mbuf_type(n), &temp); if (temp == NULL) goto nospace; mbuf_setnext(n, temp); n = mbuf_next(n); mbuf_setlen(n, mbuf_get_mlen()); if (left >= mbuf_get_minclsize()) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n), &n); if (mbuf_flags(n) & MBUF_EXT) mbuf_setlen(n, MCLBYTES); } if (mbuf_len(n) > left) mbuf_setlen(n, left); noff = 0; } len = min(mbuf_len(m) - moff, mbuf_len(n) - noff); rc4_crypt(&ctx->rc4, mtod(m, u_char*) + moff, mtod(n, u_char*) + noff, len); crc = ether_crc32_le_update(crc, mtod(n, const uint8_t*) + noff, len); moff += len; noff += len; left -= len; } /* extract and decrypt TKIP MIC and WEP ICV from m0's tail */ mbuf_copydata(m, moff, IEEE80211_TKIP_TAILLEN, buf); rc4_crypt(&ctx->rc4, buf, buf, IEEE80211_TKIP_TAILLEN); /* include TKIP MIC in WEP ICV */ mic0 = buf; crc = ether_crc32_le_update(crc, mic0, IEEE80211_TKIP_MICLEN); crc = ~crc; /* decrypt ICV and compare it with calculated ICV */ crc0 = *(u_int32_t *)(buf + IEEE80211_TKIP_MICLEN); if (crc != letoh32(crc0)) { ic->ic_stats.is_tkip_icv_errs++; mbuf_freem(m0); mbuf_freem(n0); return NULL; } /* compute TKIP MIC over decrypted message */ ieee80211_tkip_mic(n0, hdrlen, ctx->rxmic, mic); /* check that it matches the MIC in received frame */ if (timingsafe_bcmp(mic0, mic, IEEE80211_TKIP_MICLEN) != 0) { mbuf_freem(m0); mbuf_freem(n0); ic->ic_stats.is_rx_locmicfail++; ieee80211_michael_mic_failure(ic, tsc); return NULL; } /* update last seen packet number (MIC is validated) */ *prsc = tsc; /* mark cached TTAK as valid */ ctx->rxttak_ok = 1; mbuf_freem(m0); return n0; nospace: ic->ic_stats.is_rx_nombuf++; mbuf_freem(m0); mbuf_freem(n0); return NULL; } #ifndef IEEE80211_STA_ONLY /* * This function is called in HostAP mode to deauthenticate all STAs using * TKIP as their pairwise or group cipher (as part of TKIP countermeasures). */ static void ieee80211_tkip_deauth(void *arg, struct ieee80211_node *ni) { struct ieee80211com *ic = (struct ieee80211com *)arg; if (ni->ni_state == IEEE80211_STA_ASSOC && (ic->ic_bss->ni_rsngroupcipher == IEEE80211_CIPHER_TKIP || ni->ni_rsncipher == IEEE80211_CIPHER_TKIP)) { /* deauthenticate STA */ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_MIC_FAILURE); ieee80211_node_leave(ic, ni); } } void ieee80211_michael_mic_failure_timeout(void *arg) { struct ieee80211com *ic = (struct ieee80211com *)arg; /* Disable TKIP countermeasures. */ ic->ic_flags &= ~IEEE80211_F_COUNTERM; } #endif /* IEEE80211_STA_ONLY */ /* * This function can be called by the software TKIP crypto code or by the * drivers when their hardware crypto engines detect a Michael MIC failure. */ void ieee80211_michael_mic_failure(struct ieee80211com *ic, u_int64_t tsc) { #ifndef IEEE80211_STA_ONLY int sec; #endif if (ic->ic_flags & IEEE80211_F_COUNTERM) return; /* countermeasures already active */ //log(LOG_WARNING, "%s: Michael MIC failure\n", ic->ic_if.if_xname); /* * NB. do not send Michael MIC Failure reports as recommended since * these may be used as an oracle to verify CRC guesses as described * in Beck, M. and Tews S. "Practical attacks against WEP and WPA" * http://dl.aircrack-ng.org/breakingwepandwpa.pdf */ /* * Activate TKIP countermeasures (see 802.11-2012 11.4.2.4) if less than * 60 seconds have passed since the most recent previous MIC failure. */ if (ic->ic_tkip_micfail == 0 || ticks - (ic->ic_tkip_micfail + 60 * hz) >= 0) { ic->ic_tkip_micfail = ticks; ic->ic_tkip_micfail_last_tsc = tsc; return; } switch (ic->ic_opmode) { #ifndef IEEE80211_STA_ONLY case IEEE80211_M_HOSTAP: /* refuse new TKIP associations for at least 60 seconds */ ic->ic_flags |= IEEE80211_F_COUNTERM; sec = 60 + arc4random_uniform(30); //log(LOG_WARNING, "%s: HostAP will be disabled for %d seconds " // "as a countermeasure against TKIP key cracking attempts\n", // ic->ic_if.if_xname, sec); timeout_add_sec(&ic->ic_tkip_micfail_timeout, sec); /* deauthenticate all currently associated STAs using TKIP */ ieee80211_iterate_nodes(ic, ieee80211_tkip_deauth, ic); /* schedule a GTK change */ timeout_add_sec(&ic->ic_rsn_timeout, 1); break; #endif case IEEE80211_M_STA: /* * Notify the AP of MIC failures: send two Michael * MIC Failure Report frames back-to-back to trigger * countermeasures at the AP end. */ (void)ieee80211_send_eapol_key_req(ic, ic->ic_bss, EAPOL_KEY_KEYMIC | EAPOL_KEY_ERROR | EAPOL_KEY_SECURE, ic->ic_tkip_micfail_last_tsc); (void)ieee80211_send_eapol_key_req(ic, ic->ic_bss, EAPOL_KEY_KEYMIC | EAPOL_KEY_ERROR | EAPOL_KEY_SECURE, tsc); /* deauthenticate from the AP.. */ IEEE80211_SEND_MGMT(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_MIC_FAILURE); /* ..and find another one */ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); break; default: break; } ic->ic_tkip_micfail = ticks; ic->ic_tkip_micfail_last_tsc = tsc; } /*********************************************************************** Contents: Generate IEEE 802.11 per-frame RC4 key hash test vectors Date: April 19, 2002 Notes: This code is written for pedagogical purposes, NOT for performance. ************************************************************************/ /* macros for extraction/creation of byte/u16b values */ #define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) #define Lo8(v16) ((byte)( (v16) & 0x00FF)) #define Hi8(v16) ((byte)(((v16) >> 8) & 0x00FF)) #define Lo16(v32) ((u16b)( (v32) & 0xFFFF)) #define Hi16(v32) ((u16b)(((v32) >>16) & 0xFFFF)) #define Mk16(hi,lo) ((lo) ^ (((u16b)(hi)) << 8)) /* select the Nth 16-bit word of the Temporal Key byte array TK[] */ #define TK16(N) Mk16(TK[2 * (N) + 1], TK[2 * (N)]) /* S-box lookup: 16 bits --> 16 bits */ #define _S_(v16) (Sbox[Lo8(v16)] ^ swap16(Sbox[Hi8(v16)])) /* fixed algorithm "parameters" */ #define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */ #define TA_SIZE 6 /* 48-bit transmitter address */ #define TK_SIZE 16 /* 128-bit Temporal Key */ #define P1K_SIZE 10 /* 80-bit Phase1 key */ #define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */ /* 2-byte by 2-byte subset of the full AES S-box table */ static const u16b Sbox[256]= /* Sbox for hash */ { 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A }; /* ********************************************************************** * Routine: Phase 1 -- generate P1K, given TA, TK, IV32 * * Inputs: * TK[] = Temporal Key [128 bits] * TA[] = transmitter's MAC address [ 48 bits] * IV32 = upper 32 bits of IV [ 32 bits] * Output: * P1K[] = Phase 1 key [ 80 bits] * * Note: * This function only needs to be called every 2**16 frames, * although in theory it could be called every frame. * ********************************************************************** */ static void Phase1(u16b *P1K, const byte *TK, const byte *TA, u32b IV32) { int i; /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ P1K[0] = Lo16(IV32); P1K[1] = Hi16(IV32); P1K[2] = Mk16(TA[1], TA[0]); /* use TA[] as little-endian */ P1K[3] = Mk16(TA[3], TA[2]); P1K[4] = Mk16(TA[5], TA[4]); /* Now compute an unbalanced Feistel cipher with 80-bit block */ /* size on the 80-bit block P1K[], using the 128-bit key TK[] */ for (i = 0; i < PHASE1_LOOP_CNT; i++) { /* Each add operation here is mod 2**16 */ P1K[0] += _S_(P1K[4] ^ TK16((i & 1) + 0)); P1K[1] += _S_(P1K[0] ^ TK16((i & 1) + 2)); P1K[2] += _S_(P1K[1] ^ TK16((i & 1) + 4)); P1K[3] += _S_(P1K[2] ^ TK16((i & 1) + 6)); P1K[4] += _S_(P1K[3] ^ TK16((i & 1) + 0)); P1K[4] += i; /* avoid "slide attacks" */ } } /* ********************************************************************** * Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16 * * Inputs: * TK[] = Temporal Key [128 bits] * P1K[] = Phase 1 output key [ 80 bits] * IV16 = low 16 bits of IV counter [ 16 bits] * Output: * RC4KEY[] = the key used to encrypt the frame [128 bits] * * Note: * The value {TA,IV32,IV16} for Phase1/Phase2 must be unique * across all frames using the same key TK value. Then, for a * given value of TK[], this TKIP48 construction guarantees that * the final RC4KEY value is unique across all frames. * ********************************************************************** */ static void Phase2(byte *RC4KEY, const byte *TK, const u16b *P1K, u16b IV16) { u16b *PPK; /* temporary key for mixing */ int i; /* * Suggested implementation optimization: if PPK[] is "overlaid" * appropriately on RC4KEY[], there is no need for the final for * loop that copies the PPK[] result into RC4KEY[]. */ PPK = (u16b *)&RC4KEY[4]; /* all adds in the PPK[] equations below are mod 2**16 */ for (i = 0; i < 5; i++) PPK[i] = P1K[i]; /* first, copy P1K to PPK */ PPK[5] = P1K[4] + IV16; /* next, add in IV16 */ /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */ PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */ PPK[1] += _S_(PPK[0] ^ TK16(1)); PPK[2] += _S_(PPK[1] ^ TK16(2)); PPK[3] += _S_(PPK[2] ^ TK16(3)); PPK[4] += _S_(PPK[3] ^ TK16(4)); PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */ /* Final sweep: bijective, linear. Rotates kill LSB correlations */ PPK[0] += RotR1(PPK[5] ^ TK16(6)); PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */ PPK[2] += RotR1(PPK[1]); PPK[3] += RotR1(PPK[2]); PPK[4] += RotR1(PPK[3]); PPK[5] += RotR1(PPK[4]); /* At this point, for a given key TK[0..15], the 96-bit output */ /* value PPK[0..5] is guaranteed to be unique, as a function */ /* of the 96-bit "input" value {TA,IV32,IV16}. That is, P1K */ /* is now a keyed permutation of {TA,IV32,IV16}. */ /* Set RC4KEY[0..3], which includes cleartext portion of RC4 key */ RC4KEY[0] = Hi8(IV16); /* RC4KEY[0..2] is the WEP IV */ RC4KEY[1] =(Hi8(IV16) | 0x20) & 0x7F; /* Help avoid FMS weak keys */ RC4KEY[2] = Lo8(IV16); RC4KEY[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); #if BYTE_ORDER == BIG_ENDIAN /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ for (i = 0; i < 6; i++) PPK[i] = swap16(PPK[i]); #endif } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_crypto_wep.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. */ /* $OpenBSD: ieee80211_crypto_wep.c,v 1.17 2018/11/09 14:14:31 claudio Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements Wired Equivalent Privacy (WEP) defined in * IEEE Std 802.11-2007 section 8.2.1. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* WEP software crypto context */ struct ieee80211_wep_ctx { struct rc4_ctx rc4; u_int32_t iv; }; /* * Initialize software crypto context. This function can be overridden * by drivers doing hardware crypto. */ int ieee80211_wep_set_key(struct ieee80211com *ic, struct ieee80211_key *k) { struct ieee80211_wep_ctx *ctx; ctx = (struct ieee80211_wep_ctx *)malloc(sizeof(*ctx), 0, 0); if (ctx == NULL) return ENOMEM; k->k_priv = ctx; return 0; } void ieee80211_wep_delete_key(struct ieee80211com *ic, struct ieee80211_key *k) { if (k->k_priv != NULL) { explicit_bzero(k->k_priv, sizeof(struct ieee80211_wep_ctx)); free(k->k_priv); } k->k_priv = NULL; } /* shortcut */ #define IEEE80211_WEP_HDRLEN \ (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN) mbuf_t ieee80211_wep_encrypt(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_key *k) { struct ieee80211_wep_ctx *ctx = (struct ieee80211_wep_ctx *)k->k_priv; u_int8_t wepseed[16]; const struct ieee80211_frame *wh; mbuf_t n0, m, n; u_int8_t *ivp, *icvp; u_int32_t iv, crc; int left, moff, noff, len, hdrlen; mbuf_t temp; mbuf_get(MBUF_DONTWAIT, mbuf_type(m0), &n0); if (n0 == NULL) goto nospace; if (m_dup_pkthdr(n0, m0, MBUF_DONTWAIT)) goto nospace; mbuf_pkthdr_setlen(n0, mbuf_pkthdr_len(n0) + IEEE80211_WEP_HDRLEN); mbuf_setlen(n0, mbuf_get_mhlen()); if (mbuf_pkthdr_len(n0) >= mbuf_get_minclsize() - IEEE80211_WEP_CRCLEN) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n0), &n0); if (mbuf_flags(n0) & MBUF_EXT) mbuf_setlen(n0, MCLBYTES); } if (mbuf_len(n0) > mbuf_pkthdr_len(n0)) mbuf_setlen(n0, mbuf_pkthdr_len(n0)); /* copy 802.11 header */ wh = mtod(m0, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); memcpy(mtod(n0, caddr_t), wh, hdrlen); /* select a new IV for every MPDU */ iv = (ctx->iv != 0) ? ctx->iv : arc4random(); /* skip weak IVs from Fluhrer/Mantin/Shamir */ if (iv >= 0x03ff00 && (iv & 0xf8ff00) == 0x00ff00) iv += 0x000100; ctx->iv = iv + 1; ivp = mtod(n0, u_int8_t *) + hdrlen; ivp[0] = iv; ivp[1] = iv >> 8; ivp[2] = iv >> 16; ivp[3] = k->k_id << 6; /* compute WEP seed: concatenate IV and WEP Key */ memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN); memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len); rc4_keysetup(&ctx->rc4, wepseed, IEEE80211_WEP_IVLEN + k->k_len); explicit_bzero(wepseed, sizeof(wepseed)); /* encrypt frame body and compute WEP ICV */ m = m0; n = n0; moff = hdrlen; noff = hdrlen + IEEE80211_WEP_HDRLEN; left = mbuf_pkthdr_len(m0)- moff; crc = ~0; while (left > 0) { if (moff == mbuf_len(m)) { /* nothing left to copy from m */ m = mbuf_next(m); moff = 0; } if (noff == mbuf_len(n)) { /* n is full and there's more data to copy */ temp = NULL; mbuf_get(MBUF_DONTWAIT, mbuf_type(n), &temp); if (temp == NULL) goto nospace; mbuf_setnext(n, temp); n = mbuf_next(n); mbuf_setlen(n, mbuf_get_mlen()); if (left >= mbuf_get_minclsize() - IEEE80211_WEP_CRCLEN) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n), &n); // MCLGET(n, MBUF_DONTWAIT); if (mbuf_flags(n) & MBUF_EXT) mbuf_setlen(n, MCLBYTES); } if (mbuf_len(n) > left) mbuf_setlen(n, left); noff = 0; } len = min(mbuf_len(m) - moff, mbuf_len(n) - noff); crc = ether_crc32_le_update(crc, mtod(m, const u_int8_t *) + moff, len); rc4_crypt(&ctx->rc4, mtod(m, u_char *) + moff, mtod(n, u_char *) + noff, len); moff += len; noff += len; left -= len; } /* reserve trailing space for WEP ICV */ if (mbuf_trailingspace(n) < IEEE80211_WEP_CRCLEN) { temp = NULL; mbuf_get(MBUF_DONTWAIT, mbuf_type(n), &temp); if (temp == NULL) goto nospace; mbuf_setnext(n, temp); n = mbuf_next(n); mbuf_setlen(n, 0); } /* finalize WEP ICV */ icvp = mtod(n, uint8_t *) + mbuf_len(n); crc = ~crc; icvp[0] = crc; icvp[1] = crc >> 8; icvp[2] = crc >> 16; icvp[3] = crc >> 24; rc4_crypt(&ctx->rc4, icvp, icvp, IEEE80211_WEP_CRCLEN); mbuf_setlen(n, mbuf_len(n) + IEEE80211_WEP_CRCLEN); mbuf_pkthdr_setlen(n0, mbuf_pkthdr_len(n0) + IEEE80211_WEP_CRCLEN); mbuf_freem(m0); return n0; nospace: ic->ic_stats.is_tx_nombuf++; mbuf_freem(m0); mbuf_freem(n0); return NULL; } mbuf_t ieee80211_wep_decrypt(struct ieee80211com *ic, mbuf_t m0, struct ieee80211_key *k) { struct ieee80211_wep_ctx *ctx = (struct ieee80211_wep_ctx *)k->k_priv; struct ieee80211_frame *wh; u_int8_t wepseed[16]; u_int32_t crc, crc0; u_int8_t *ivp; mbuf_t n0, m, n; int hdrlen, left, moff, noff, len; mbuf_t temp; wh = mtod(m0, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); if (mbuf_pkthdr_len(m0) < hdrlen + IEEE80211_WEP_TOTLEN) { mbuf_freem(m0); return NULL; } /* concatenate IV and WEP Key */ ivp = (u_int8_t *)wh + hdrlen; memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN); memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len); rc4_keysetup((struct rc4_ctx *)&ctx->rc4, (u_char*)wepseed, (uint32_t)(IEEE80211_WEP_IVLEN + k->k_len)); explicit_bzero(wepseed, sizeof(wepseed)); mbuf_get(MBUF_DONTWAIT, mbuf_type(m0), &n0); if (n0 == NULL) goto nospace; if (m_dup_pkthdr(n0, m0, MBUF_DONTWAIT)) goto nospace; mbuf_pkthdr_setlen(n0, mbuf_pkthdr_len(n0) - IEEE80211_WEP_TOTLEN); mbuf_setlen(n0, mbuf_get_mhlen()); if (mbuf_pkthdr_len(n0) >= mbuf_get_minclsize()) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n0), &n0); // MCLGET(n0, MBUF_DONTWAIT); if (mbuf_flags(n0) & MBUF_EXT) mbuf_setlen(n0, MCLBYTES); // n0->m_len = n0->m_ext.ext_size; } if (mbuf_len(n0) > mbuf_pkthdr_len(n0)) mbuf_setlen(n0, mbuf_pkthdr_len(n0)); /* copy 802.11 header and clear protected bit */ memcpy(mtod(n0, caddr_t), wh, hdrlen); wh = mtod(n0, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; /* decrypt frame body and compute WEP ICV */ m = m0; n = n0; moff = hdrlen + IEEE80211_WEP_HDRLEN; noff = hdrlen; left = mbuf_pkthdr_len(n0) - noff; crc = ~0; while (left > 0) { if (moff == mbuf_len(m)) { /* nothing left to copy from m */ m = mbuf_next(m); moff = 0; } if (noff == mbuf_len(n)) { /* n is full and there's more data to copy */ temp = NULL; mbuf_get(MBUF_DONTWAIT, mbuf_type(n), &temp); if (temp == NULL) goto nospace; mbuf_setnext(n, temp); n = mbuf_next(n); mbuf_setlen(n, mbuf_get_mlen()); if (left >= mbuf_get_minclsize()) { mbuf_mclget(MBUF_DONTWAIT, mbuf_type(n), &n); if (mbuf_flags(n) & MBUF_EXT) mbuf_setlen(n, MCLBYTES); } if (mbuf_len(n) > left) mbuf_setlen(n, left); noff = 0; } len = min(mbuf_len(m) - moff, mbuf_len(n) - noff); rc4_crypt(&ctx->rc4, mtod(m, u_char*) + moff, mtod(n, u_char*) + noff, len); crc = ether_crc32_le_update(crc, mtod(n, const u_int8_t *) + noff, len); moff += len; noff += len; left -= len; } /* decrypt ICV and compare it with calculated ICV */ mbuf_copydata(m, moff, IEEE80211_WEP_CRCLEN, (caddr_t)&crc0); rc4_crypt(&ctx->rc4, (u_char*)&crc0, (u_char*)&crc0, IEEE80211_WEP_CRCLEN); crc = ~crc; if (crc != letoh32(crc0)) { ic->ic_stats.is_rx_decryptcrc++; mbuf_freem(m0); mbuf_freem(n0); return NULL; } mbuf_freem(m0); return n0; nospace: ic->ic_stats.is_rx_nombuf++; mbuf_freem(m0); mbuf_freem(n0); return NULL; } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_input.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. */ /* $OpenBSD: ieee80211_input.c,v 1.235 2021/05/17 08:02:20 stsp Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * Copyright (c) 2007-2009 Damien Bergamini * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if NBPFILTER > 0 #include #endif #include #include #include #include mbuf_t ieee80211_input_hwdecrypt(struct ieee80211com *, struct ieee80211_node *, mbuf_t, struct ieee80211_rxinfo *rxi); mbuf_t ieee80211_defrag(struct ieee80211com *, mbuf_t, int); void ieee80211_defrag_timeout(void *); void ieee80211_input_ba(struct ieee80211com *, mbuf_t, struct ieee80211_node *, int, struct ieee80211_rxinfo *, struct mbuf_list *); void ieee80211_input_ba_flush(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_rx_ba *, struct mbuf_list *); int ieee80211_input_ba_gap_skip(struct ieee80211_rx_ba *); void ieee80211_input_ba_gap_timeout(void *arg); void ieee80211_ba_move_window(struct ieee80211com *, struct ieee80211_node *, u_int8_t, u_int16_t, struct mbuf_list *); void ieee80211_input_ba_seq(struct ieee80211com *, struct ieee80211_node *, uint8_t, uint16_t, struct mbuf_list *); mbuf_t ieee80211_align_mbuf(mbuf_t); void ieee80211_decap(struct ieee80211com *, mbuf_t, struct ieee80211_node *, int, struct mbuf_list *); int ieee80211_amsdu_decap_validate(struct ieee80211com *, mbuf_t, struct ieee80211_node *); void ieee80211_amsdu_decap(struct ieee80211com *, mbuf_t, struct ieee80211_node *, int, struct mbuf_list *); void ieee80211_enqueue_data(struct ieee80211com *, mbuf_t*, struct ieee80211_node *, int, struct mbuf_list *); int ieee80211_parse_edca_params_body(struct ieee80211com *, const u_int8_t *); int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *); int ieee80211_parse_wmm_params(struct ieee80211com *, const u_int8_t *); enum ieee80211_cipher ieee80211_parse_rsn_cipher(const u_int8_t[]); enum ieee80211_akm ieee80211_parse_rsn_akm(const u_int8_t[]); int ieee80211_parse_rsn_body(struct ieee80211com *, const u_int8_t *, u_int, struct ieee80211_rsnparams *); int ieee80211_save_ie(const u_int8_t *, u_int8_t **); void ieee80211_recv_probe_resp(struct ieee80211com *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *, int); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_probe_req(struct ieee80211com *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *); #endif void ieee80211_recv_auth(struct ieee80211com *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_assoc_req(struct ieee80211com *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *, int); #endif void ieee80211_recv_assoc_resp(struct ieee80211com *, mbuf_t, struct ieee80211_node *, int); void ieee80211_recv_deauth(struct ieee80211com *, mbuf_t, struct ieee80211_node *); void ieee80211_recv_disassoc(struct ieee80211com *, mbuf_t, struct ieee80211_node *); void ieee80211_recv_addba_req(struct ieee80211com *, mbuf_t, struct ieee80211_node *); void ieee80211_recv_addba_resp(struct ieee80211com *, mbuf_t, struct ieee80211_node *); void ieee80211_recv_delba(struct ieee80211com *, mbuf_t, struct ieee80211_node *); void ieee80211_recv_sa_query_req(struct ieee80211com *, mbuf_t, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_sa_query_resp(struct ieee80211com *, mbuf_t, struct ieee80211_node *); #endif void ieee80211_recv_action(struct ieee80211com *, mbuf_t, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_pspoll(struct ieee80211com *, mbuf_t, struct ieee80211_node *); #endif void ieee80211_recv_bar(struct ieee80211com *, mbuf_t, struct ieee80211_node *); void ieee80211_bar_tid(struct ieee80211com *, struct ieee80211_node *, u_int8_t, u_int16_t); /* * Retrieve the length in bytes of an 802.11 header. */ u_int ieee80211_get_hdrlen(const struct ieee80211_frame *wh) { u_int size = sizeof(*wh); /* NB: does not work with control frames */ _KASSERT(ieee80211_has_seq(wh)); if (ieee80211_has_addr4(wh)) size += IEEE80211_ADDR_LEN; /* i_addr4 */ if (ieee80211_has_qos(wh)) size += sizeof(u_int16_t); /* i_qos */ if (ieee80211_has_htc(wh)) size += sizeof(u_int32_t); /* i_ht */ return size; } /* Post-processing for drivers which perform decryption in hardware. */ mbuf_t ieee80211_input_hwdecrypt(struct ieee80211com *ic, struct ieee80211_node *ni, mbuf_t m, struct ieee80211_rxinfo *rxi) { struct ieee80211_key *k; struct ieee80211_frame *wh; uint64_t pn, *prsc; int hdrlen; k = ieee80211_get_rxkey(ic, m, ni); if (k == NULL) return NULL; wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); /* * Update the last-seen packet number (PN) for drivers using hardware * crypto offloading. This cannot be done by drivers because A-MPDU * reordering needs to occur before a valid lower bound can be * determined for the PN. Drivers will read the PN we write here and * are expected to discard replayed frames based on it. * Drivers are expected to leave the IV of decrypted frames intact * so we can update the last-seen PN and strip the IV here. */ switch (k->k_cipher) { case IEEE80211_CIPHER_CCMP: if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { /* * If the protected bit is clear then hardware has * stripped the IV and we must trust that it handles * replay detection correctly. */ break; } if (ieee80211_ccmp_get_pn(&pn, &prsc, m, k) != 0) return NULL; if (rxi->rxi_flags & IEEE80211_RXI_HWDEC_SAME_PN) { if (pn < *prsc) { ic->ic_stats.is_ccmp_replays++; return NULL; } } else if (pn <= *prsc) { ic->ic_stats.is_ccmp_replays++; return NULL; } /* Update last-seen packet number. */ *prsc = pn; /* Clear Protected bit and strip IV. */ wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; memmove(mtod(m, caddr_t) + IEEE80211_CCMP_HDRLEN, wh, hdrlen); mbuf_adj(m, IEEE80211_CCMP_HDRLEN); /* Drivers are expected to strip the MIC. */ break; case IEEE80211_CIPHER_TKIP: if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { /* * If the protected bit is clear then hardware has * stripped the IV and we must trust that it handles * replay detection correctly. */ break; } if (ieee80211_tkip_get_tsc(&pn, &prsc, m, k) != 0) return NULL; if (rxi->rxi_flags & IEEE80211_RXI_HWDEC_SAME_PN) { if (pn < *prsc) { ic->ic_stats.is_tkip_replays++; return NULL; } } else if (pn <= *prsc) { ic->ic_stats.is_tkip_replays++; return NULL; } /* Update last-seen packet number. */ *prsc = pn; /* Clear Protected bit and strip IV. */ wh = mtod(m, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; memmove(mtod(m, caddr_t) + IEEE80211_TKIP_HDRLEN, wh, hdrlen); mbuf_adj(m, IEEE80211_TKIP_HDRLEN); /* Drivers are expected to strip the MIC. */ break; default: break; } return m; } /* * Process a received frame. The node associated with the sender * should be supplied. If nothing was found in the node table then * the caller is assumed to supply a reference to ic_bss instead. * The RSSI and a timestamp are also supplied. The RSSI data is used * during AP scanning to select a AP to associate with; it can have * any units so long as values have consistent units and higher values * mean ``better signal''. The receive timestamp is currently not used * by the 802.11 layer. * * This function acts on management frames immediately and queues data frames * on the specified mbuf list. Delivery of queued data frames to upper layers * must be triggered with if_input(). Drivers should call if_input() only once * per Rx interrupt to avoid triggering the input ifq pressure drop mechanism * unnecessarily. */ void ieee80211_inputm(struct _ifnet *ifp, mbuf_t m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi, struct mbuf_list *ml) { struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ieee80211_frame *wh; u_int16_t *orxseq, nrxseq, qos; u_int8_t dir, type, subtype, tid; int hdrlen, hasqos; _KASSERT(ni != NULL); /* in monitor mode, send everything directly to bpf */ if (ic->ic_opmode == IEEE80211_M_MONITOR) goto out; /* * Do not process frames without an Address 2 field any further. * Only CTS and ACK control frames do not have this field. */ if (mbuf_len(m) < sizeof(struct ieee80211_frame_min)) { DPRINTF(("frame too short, len %u\n", mbuf_len(m))); ic->ic_stats.is_rx_tooshort++; goto out; } wh = mtod(m, struct ieee80211_frame *); if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) { DPRINTF(("frame with wrong version: %x\n", wh->i_fc[0])); ic->ic_stats.is_rx_badversion++; goto err; } dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (type != IEEE80211_FC0_TYPE_CTL) { hdrlen = ieee80211_get_hdrlen(wh); if (mbuf_len(m) < hdrlen) { DPRINTF(("frame too short, len %u\n", mbuf_len(m))); ic->ic_stats.is_rx_tooshort++; goto err; } } else hdrlen = 0; if ((hasqos = ieee80211_has_qos(wh))) { qos = ieee80211_get_qos(wh); tid = qos & IEEE80211_QOS_TID; } else { qos = 0; tid = 0; } if (ic->ic_state == IEEE80211_S_RUN && type == IEEE80211_FC0_TYPE_DATA && hasqos && (subtype & IEEE80211_FC0_SUBTYPE_NODATA) == 0 && !(rxi->rxi_flags & IEEE80211_RXI_AMPDU_DONE) #ifndef IEEE80211_STA_ONLY && (ic->ic_opmode == IEEE80211_M_STA || ni != ic->ic_bss) #endif ) { int ba_state = ni->ni_rx_ba[tid].ba_state; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) { if (!IEEE80211_ADDR_EQ(wh->i_addr1, ic->ic_bss->ni_bssid)) { ic->ic_stats.is_rx_wrongbss++; goto err; } if (ni->ni_state != IEEE80211_S_ASSOC) { ic->ic_stats.is_rx_notassoc++; goto err; } } #endif /* * If Block Ack was explicitly requested, check * if we have a BA agreement for this RA/TID. */ if ((qos & IEEE80211_QOS_ACK_POLICY_MASK) == IEEE80211_QOS_ACK_POLICY_BA && ba_state != IEEE80211_BA_AGREED) { DPRINTF(("no BA agreement for %s, TID %d\n", ether_sprintf(ni->ni_macaddr), tid)); /* send a DELBA with reason code UNKNOWN-BA */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, IEEE80211_ACTION_DELBA, IEEE80211_REASON_SETUP_REQUIRED << 16 | tid); goto err; } /* * Check if we have an explicit or implicit * Block Ack Request for a valid BA agreement. */ if (ba_state == IEEE80211_BA_AGREED && ((qos & IEEE80211_QOS_ACK_POLICY_MASK) == IEEE80211_QOS_ACK_POLICY_BA || (qos & IEEE80211_QOS_ACK_POLICY_MASK) == IEEE80211_QOS_ACK_POLICY_NORMAL)) { /* go through A-MPDU reordering */ ieee80211_input_ba(ic, m, ni, tid, rxi, ml); return; /* don't free m! */ } else if (ba_state == IEEE80211_BA_REQUESTED && (qos & IEEE80211_QOS_ACK_POLICY_MASK) == IEEE80211_QOS_ACK_POLICY_NORMAL) { /* * Apparently, qos frames for a tid where a * block ack agreement was requested but not * yet confirmed by us should still contribute * to the sequence number for this tid. */ ieee80211_input_ba(ic, m, ni, tid, rxi, ml); return; /* don't free m! */ } } /* * We do not yet support fragments. Drop any fragmented packets. * Counter-measure against attacks where an arbitrary packet is * injected via a fragment with attacker-controlled content. * See https://papers.mathyvanhoef.com/usenix2021.pdf * Section 6.8 "Treating fragments as full frames" */ if (ieee80211_has_seq(wh)) { uint16_t rxseq = letoh16(*(const u_int16_t *)wh->i_seq); if ((wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) || (rxseq & IEEE80211_SEQ_FRAG_MASK)) goto err; } /* duplicate detection (see 9.2.9) */ if (ieee80211_has_seq(wh) && ic->ic_state != IEEE80211_S_SCAN) { nrxseq = letoh16(*(u_int16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT; if (hasqos) orxseq = &ni->ni_qos_rxseqs[tid]; else orxseq = &ni->ni_rxseq; if (rxi->rxi_flags & IEEE80211_RXI_SAME_SEQ) { if (nrxseq != *orxseq) { /* duplicate, silently discarded */ ic->ic_stats.is_rx_dup++; goto out; } } else if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && nrxseq == *orxseq) { /* duplicate, silently discarded */ ic->ic_stats.is_rx_dup++; goto out; } *orxseq = nrxseq; } if (ic->ic_state > IEEE80211_S_SCAN) { ni->ni_rssi = rxi->rxi_rssi; ni->ni_rstamp = rxi->rxi_tstamp; ni->ni_inact = 0; if (ic->ic_state == IEEE80211_S_RUN && ic->ic_bgscan_start) { /* Cancel or start background scan based on RSSI. */ if ((*ic->ic_node_checkrssi)(ic, ni)) timeout_del(&ic->ic_bgscan_timeout); else if (!timeout_pending(&ic->ic_bgscan_timeout) && (ic->ic_flags & IEEE80211_F_BGSCAN) == 0 && (ic->ic_flags & IEEE80211_F_DESBSSID) == 0) timeout_add_msec(&ic->ic_bgscan_timeout, 500 * (ic->ic_bgscan_fail + 1)); } } #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP && (ic->ic_caps & IEEE80211_C_APPMGT) && ni->ni_state == IEEE80211_STA_ASSOC) { if (wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) { if (ni->ni_pwrsave == IEEE80211_PS_AWAKE) { /* turn on PS mode */ ni->ni_pwrsave = IEEE80211_PS_DOZE; DPRINTF(("PS mode on for %s\n", ether_sprintf(wh->i_addr2))); } } else if (ni->ni_pwrsave == IEEE80211_PS_DOZE) { mbuf_t m; /* turn off PS mode */ ni->ni_pwrsave = IEEE80211_PS_AWAKE; DPRINTF(("PS mode off for %s\n", ether_sprintf(wh->i_addr2))); (*ic->ic_set_tim)(ic, ni->ni_associd, 0); /* dequeue buffered unicast frames */ while ((m = mq_dequeue(&ni->ni_savedq)) != NULL) { mq_enqueue(&ic->ic_pwrsaveq, m); ifp->if_start(ifp); } } } #endif switch (type) { case IEEE80211_FC0_TYPE_DATA: switch (ic->ic_opmode) { case IEEE80211_M_STA: if (dir != IEEE80211_FC1_DIR_FROMDS) { ic->ic_stats.is_rx_wrongdir++; goto out; } if (ic->ic_state != IEEE80211_S_SCAN && !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) { /* Source address is not our BSS. */ DPRINTF(("discard frame from SA %s\n", ether_sprintf(wh->i_addr2))); ic->ic_stats.is_rx_wrongbss++; goto out; } if ((ifp->if_flags & IFF_SIMPLEX) && IEEE80211_IS_MULTICAST(wh->i_addr1) && IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_myaddr)) { /* * In IEEE802.11 network, multicast frame * sent from me is broadcasted from AP. * It should be silently discarded for * SIMPLEX interface. */ ic->ic_stats.is_rx_mcastecho++; goto out; } break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: if (dir != IEEE80211_FC1_DIR_NODS) { ic->ic_stats.is_rx_wrongdir++; goto out; } if (ic->ic_state != IEEE80211_S_SCAN && !IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid) && !IEEE80211_ADDR_EQ(wh->i_addr3, etherbroadcastaddr)) { /* Destination is not our BSS or broadcast. */ DPRINTF(("discard data frame to DA %s\n", ether_sprintf(wh->i_addr3))); ic->ic_stats.is_rx_wrongbss++; goto out; } break; case IEEE80211_M_HOSTAP: if (dir != IEEE80211_FC1_DIR_TODS) { ic->ic_stats.is_rx_wrongdir++; goto out; } if (ic->ic_state != IEEE80211_S_SCAN && !IEEE80211_ADDR_EQ(wh->i_addr1, ic->ic_bss->ni_bssid) && !IEEE80211_ADDR_EQ(wh->i_addr1, etherbroadcastaddr)) { /* BSS is not us or broadcast. */ DPRINTF(("discard data frame to BSS %s\n", ether_sprintf(wh->i_addr1))); ic->ic_stats.is_rx_wrongbss++; goto out; } /* check if source STA is associated */ if (ni == ic->ic_bss) { DPRINTF(("data from unknown src %s\n", ether_sprintf(wh->i_addr2))); /* NB: caller deals with reference */ ni = ieee80211_find_node(ic, wh->i_addr2); if (ni == NULL) ni = ieee80211_dup_bss(ic, wh->i_addr2); if (ni != NULL) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_NOT_AUTHED); } ic->ic_stats.is_rx_notassoc++; goto err; } if (ni->ni_state != IEEE80211_STA_ASSOC) { DPRINTF(("data from unassoc src %s\n", ether_sprintf(wh->i_addr2))); IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_NOT_ASSOCED); ic->ic_stats.is_rx_notassoc++; goto err; } break; #endif /* IEEE80211_STA_ONLY */ default: /* can't get there */ goto out; } /* Do not process "no data" frames any further. */ if (subtype & IEEE80211_FC0_SUBTYPE_NODATA) { #if NBPFILTER > 0 if (ic->ic_rawbpf) bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_IN); #endif goto out; } if ((ic->ic_flags & IEEE80211_F_WEPON) || ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_flags & IEEE80211_NODE_RXPROT))) { /* protection is on for Rx */ if (!(rxi->rxi_flags & IEEE80211_RXI_HWDEC)) { if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { /* drop unencrypted */ ic->ic_stats.is_rx_unencrypted++; goto err; } /* do software decryption */ m = ieee80211_decrypt(ic, m, ni); if (m == NULL) { ic->ic_stats.is_rx_wepfail++; goto err; } } else { m = ieee80211_input_hwdecrypt(ic, ni, m, rxi); if (m == NULL) goto err; } wh = mtod(m, struct ieee80211_frame *); } else if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) || (rxi->rxi_flags & IEEE80211_RXI_HWDEC)) { /* frame encrypted but protection off for Rx */ ic->ic_stats.is_rx_nowep++; goto out; } #if NBPFILTER > 0 /* copy to listener after decrypt */ if (ic->ic_rawbpf) bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_IN); #endif if ((ni->ni_flags & IEEE80211_NODE_HT) && hasqos && (qos & IEEE80211_QOS_AMSDU)) ieee80211_amsdu_decap(ic, m, ni, hdrlen, ml); else ieee80211_decap(ic, m, ni, hdrlen, ml); return; case IEEE80211_FC0_TYPE_MGT: if (dir != IEEE80211_FC1_DIR_NODS) { ic->ic_stats.is_rx_wrongdir++; goto err; } #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_AHDEMO) { ic->ic_stats.is_rx_ahdemo_mgt++; goto out; } #endif /* drop frames without interest */ if (ic->ic_state == IEEE80211_S_SCAN) { if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) { ic->ic_stats.is_rx_mgtdiscard++; goto out; } } if (ni->ni_flags & IEEE80211_NODE_RXMGMTPROT) { /* MMPDU protection is on for Rx */ if (subtype == IEEE80211_FC0_SUBTYPE_DISASSOC || subtype == IEEE80211_FC0_SUBTYPE_DEAUTH || subtype == IEEE80211_FC0_SUBTYPE_ACTION) { if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && !(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { /* unicast mgmt not encrypted */ goto out; } /* do software decryption */ m = ieee80211_decrypt(ic, m, ni); if (m == NULL) { /* XXX stats */ goto out; } wh = mtod(m, struct ieee80211_frame *); } } else if ((ic->ic_flags & IEEE80211_F_RSNON) && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { /* encrypted but MMPDU Rx protection off for TA */ goto out; } #if NBPFILTER > 0 if (bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_IN) != 0) { /* * Drop mbuf if it was filtered by bpf. Normally, * this is done in ether_input() but IEEE 802.11 * management frames are a special case. */ mbuf_freem(m); return; } #endif (*ic->ic_recv_mgmt)(ic, m, ni, rxi, subtype); mbuf_freem(m); return; case IEEE80211_FC0_TYPE_CTL: switch (subtype) { #ifndef IEEE80211_STA_ONLY case IEEE80211_FC0_SUBTYPE_PS_POLL: ieee80211_recv_pspoll(ic, m, ni); break; #endif case IEEE80211_FC0_SUBTYPE_BAR: ieee80211_recv_bar(ic, m, ni); break; default: ic->ic_stats.is_rx_ctl++; break; } goto out; default: DPRINTF(("bad frame type %x\n", type)); /* should not come here */ break; } err: ifp->netStat->inputErrors++; out: if (m != NULL) { #if NBPFILTER > 0 if (ic->ic_rawbpf) bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_IN); #endif mbuf_freem(m); } } /* Input handler for drivers which only receive one frame per interrupt. */ void ieee80211_input(struct _ifnet *ifp, mbuf_t m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi) { struct mbuf_list ml = MBUF_LIST_INITIALIZER(); ieee80211_inputm(ifp, m, ni, rxi, &ml); if_input(ifp, &ml); } #ifdef notyet /* * Handle defragmentation (see 9.5 and Annex C). We support the concurrent * reception of fragments of three fragmented MSDUs or MMPDUs. */ mbuf_t ieee80211_defrag(struct ieee80211com *ic, mbuf_t m, int hdrlen) { const struct ieee80211_frame *owh, *wh; struct ieee80211_defrag *df; u_int16_t rxseq, seq; u_int8_t frag; int i; wh = mtod(m, struct ieee80211_frame *); rxseq = letoh16(*(const u_int16_t *)wh->i_seq); seq = rxseq >> IEEE80211_SEQ_SEQ_SHIFT; frag = rxseq & IEEE80211_SEQ_FRAG_MASK; if (frag == 0 && !(wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)) return m; /* not fragmented */ if (frag == 0) { /* first fragment, setup entry in the fragment cache */ if (++ic->ic_defrag_cur == IEEE80211_DEFRAG_SIZE) ic->ic_defrag_cur = 0; df = &ic->ic_defrag[ic->ic_defrag_cur]; mbuf_freem(df->df_m); /* discard old entry */ df->df_seq = seq; df->df_frag = 0; df->df_m = m; /* start receive MSDU timer of aMaxReceiveLifetime */ timeout_add_sec(&df->df_to, 1); return NULL; /* MSDU or MMPDU not yet complete */ } /* find matching entry in the fragment cache */ for (i = 0; i < IEEE80211_DEFRAG_SIZE; i++) { df = &ic->ic_defrag[i]; if (df->df_m == NULL) continue; if (df->df_seq != seq || df->df_frag + 1 != frag) continue; owh = mtod(df->df_m, struct ieee80211_frame *); /* frame type, source and destination must match */ if (((wh->i_fc[0] ^ owh->i_fc[0]) & IEEE80211_FC0_TYPE_MASK) || !IEEE80211_ADDR_EQ(wh->i_addr1, owh->i_addr1) || !IEEE80211_ADDR_EQ(wh->i_addr2, owh->i_addr2)) continue; /* matching entry found */ break; } if (i == IEEE80211_DEFRAG_SIZE) { /* no matching entry found, discard fragment */ ic->ic_if.netStat->inputErrors++; mbuf_freem(m); return NULL; } df->df_frag = frag; /* strip 802.11 header and concatenate fragment */ mbuf_adj(m, hdrlen); m_cat(df->df_m, m); mbuf_pkthdr_setlen(df->df_m, mbuf_pkthdr_len(df->df_m) + mbuf_pkthdr_len(m)); if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) return NULL; /* MSDU or MMPDU not yet complete */ /* MSDU or MMPDU complete */ timeout_del(&df->df_to); m = df->df_m; df->df_m = NULL; return m; } /* * Receive MSDU defragmentation timer exceeds aMaxReceiveLifetime. */ void ieee80211_defrag_timeout(void *arg) { struct ieee80211_defrag *df = (struct ieee80211_defrag *)arg; int s = splnet(); /* discard all received fragments */ mbuf_freem(df->df_m); df->df_m = NULL; splx(s); } #endif /* * Process a received data MPDU related to a specific HT-immediate Block Ack * agreement (see 9.10.7.6). */ void ieee80211_input_ba(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, int tid, struct ieee80211_rxinfo *rxi, struct mbuf_list *ml) { struct _ifnet *ifp = &ic->ic_if; struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; struct ieee80211_frame *wh; int idx, count; u_int16_t sn; wh = mtod(m, struct ieee80211_frame *); sn = letoh16(*(u_int16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT; /* reset Block Ack inactivity timer */ if (ba->ba_timeout_val != 0) timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); if (SEQ_LT(sn, ba->ba_winstart)) { /* SN < WinStartB */ ic->ic_stats.is_ht_rx_frame_below_ba_winstart++; mbuf_freem(m); /* discard the MPDU */ return; } if (ba->ba_buf == NULL) { XYLog("SEVERE !!!! %s %d ba->ba_buf == NULL\n", __FUNCTION__, __LINE__); ifp->netStat->inputErrors++; ic->ic_stats.is_ht_rx_ba_no_buf++; mbuf_freem(m); return; } if (SEQ_LT(ba->ba_winend, sn)) { /* WinEndB < SN */ ic->ic_stats.is_ht_rx_frame_above_ba_winend++; count = (sn - ba->ba_winend) & 0xfff; if (count > ba->ba_winsize) { /* * Check whether we're consistently behind the window, * and let the window move forward if neccessary. */ if (ba->ba_winmiss < IEEE80211_BA_MAX_WINMISS) { if (ba->ba_missedsn == ((sn - 1) & 0xfff)) ba->ba_winmiss++; else ba->ba_winmiss = 0; ba->ba_missedsn = sn; ifp->netStat->inputErrors++; mbuf_freem(m); /* discard the MPDU */ return; } /* It appears the window has moved for real. */ ic->ic_stats.is_ht_rx_ba_window_jump++; ba->ba_winmiss = 0; ba->ba_missedsn = 0; ieee80211_ba_move_window(ic, ni, tid, sn, ml); } else { ic->ic_stats.is_ht_rx_ba_window_slide++; ieee80211_input_ba_seq(ic, ni, tid, (ba->ba_winstart + count) & 0xfff, ml); ieee80211_input_ba_flush(ic, ni, ba, ml); } } /* WinStartB <= SN <= WinEndB */ ba->ba_winmiss = 0; ba->ba_missedsn = 0; idx = (sn - ba->ba_winstart) & 0xfff; idx = (ba->ba_head + idx) % IEEE80211_BA_MAX_WINSZ; /* store the received MPDU in the buffer */ if (ba->ba_buf[idx].m != NULL) { ifp->netStat->inputErrors++; ic->ic_stats.is_ht_rx_ba_no_buf++; mbuf_freem(m); return; } ba->ba_buf[idx].m = m; /* store Rx meta-data too */ rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE; ba->ba_buf[idx].rxi = *rxi; ba->ba_gapwait++; if (ba->ba_buf[ba->ba_head].m == NULL && ba->ba_gapwait == 1) timeout_add_msec(&ba->ba_gap_to, IEEE80211_BA_GAP_TIMEOUT); ieee80211_input_ba_flush(ic, ni, ba, ml); } /* * Forward buffered frames with sequence number lower than max_seq. * See 802.11-2012 9.21.7.6.2 b. */ void ieee80211_input_ba_seq(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid, uint16_t max_seq, struct mbuf_list *ml) { struct _ifnet *ifp = &ic->ic_if; struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; struct ieee80211_frame *wh; uint16_t seq; int i = 0; while (i++ < ba->ba_winsize) { /* gaps may exist */ if (ba->ba_buf[ba->ba_head].m != NULL) { wh = mtod(ba->ba_buf[ba->ba_head].m, struct ieee80211_frame *); _KASSERT(ieee80211_has_seq(wh)); seq = letoh16(*(u_int16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT; if (!SEQ_LT(seq, max_seq)) break; ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni, &ba->ba_buf[ba->ba_head].rxi, ml); ba->ba_buf[ba->ba_head].m = NULL; ba->ba_gapwait--; } else ic->ic_stats.is_ht_rx_ba_frame_lost++; ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ; /* move window forward */ ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff; } ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; } /* Flush a consecutive sequence of frames from the reorder buffer. */ void ieee80211_input_ba_flush(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_rx_ba *ba, struct mbuf_list *ml) { struct _ifnet *ifp = &ic->ic_if; /* Do not re-arm the gap timeout if we made no progress. */ if (ba->ba_buf[ba->ba_head].m == NULL) return; /* pass reordered MPDUs up to the next MAC process */ while (ba->ba_buf[ba->ba_head].m != NULL) { ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni, &ba->ba_buf[ba->ba_head].rxi, ml); ba->ba_buf[ba->ba_head].m = NULL; ba->ba_gapwait--; ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ; /* move window forward */ ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff; } ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; if (timeout_pending(&ba->ba_gap_to)) timeout_del(&ba->ba_gap_to); if (ba->ba_gapwait) timeout_add_msec(&ba->ba_gap_to, IEEE80211_BA_GAP_TIMEOUT); } /* * Forcibly move the BA window forward to remove a leading gap which has * been causing frames to linger in the reordering buffer for too long. * A leading gap will occur if a particular A-MPDU subframe never arrives * or if a bug in the sender causes sequence numbers to jump forward by > 1. */ int ieee80211_input_ba_gap_skip(struct ieee80211_rx_ba *ba) { int skipped = 0; while (skipped < ba->ba_winsize && ba->ba_buf[ba->ba_head].m == NULL) { /* move window forward */ ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ; ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff; skipped++; } if (skipped > 0) ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; return skipped; } void ieee80211_input_ba_gap_timeout(void *arg) { struct ieee80211_rx_ba *ba = (struct ieee80211_rx_ba *)arg; struct ieee80211_node *ni = ba->ba_ni; struct ieee80211com *ic = ni->ni_ic; int s, skipped; ic->ic_stats.is_ht_rx_ba_window_gap_timeout++; s = splnet(); skipped = ieee80211_input_ba_gap_skip(ba); ic->ic_stats.is_ht_rx_ba_frame_lost += skipped; if (skipped) { struct mbuf_list ml = MBUF_LIST_INITIALIZER(); ieee80211_input_ba_flush(ic, ni, ba, &ml); if_input(&ic->ic_if, &ml); } splx(s); } /* * Change the value of WinStartB (move window forward) upon reception of a * BlockAckReq frame or an ADDBA Request (PBAC). */ void ieee80211_ba_move_window(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t tid, u_int16_t ssn, struct mbuf_list *ml) { struct _ifnet *ifp = &ic->ic_if; struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; int count; /* assert(WinStartB <= SSN) */ count = (ssn - ba->ba_winstart) & 0xfff; if (count > ba->ba_winsize) /* no overlap */ count = ba->ba_winsize; while (count-- > 0) { /* gaps may exist */ if (ba->ba_buf[ba->ba_head].m != NULL) { ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni, &ba->ba_buf[ba->ba_head].rxi, ml); ba->ba_buf[ba->ba_head].m = NULL; ba->ba_gapwait--; } else ic->ic_stats.is_ht_rx_ba_frame_lost++; ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ; } /* move window forward */ ba->ba_winstart = ssn; ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; ieee80211_input_ba_flush(ic, ni, ba, ml); } void ieee80211_enqueue_data(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, int mcast, struct mbuf_list *ml) { struct _ifnet *ifp = &ic->ic_if; struct ether_header *eh; mbuf_t m1; mbuf_t m2; eh = mtod(m, struct ether_header *); if ((ic->ic_flags & IEEE80211_F_RSNON) && !ni->ni_port_valid && eh->ether_type != htons(ETHERTYPE_PAE)) { DPRINTF(("port not valid: %s\n", ether_sprintf(eh->ether_dhost))); ic->ic_stats.is_rx_unauth++; mbuf_freem(m); return; } /* * Perform as a bridge within the AP. Notice that we do not * bridge EAPOL frames as suggested in C.1.1 of IEEE Std 802.1X. * And we do not forward unicast frames received on a multicast address. */ m1 = NULL; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP && !(ic->ic_userflags & IEEE80211_F_NOBRIDGE) && eh->ether_type != htons(ETHERTYPE_PAE)) { struct ieee80211_node *ni1; if (ETHER_IS_MULTICAST(eh->ether_dhost)) { m1 = m_dup_pkt(m, ETHER_ALIGN, MBUF_DONTWAIT); if (m1 == NULL) { XYLog("%s %d OUTPUT_ERROR\n", __FUNCTION__, __LINE__); ifp->netStat->outputErrors++; } else mbuf_setflags(m1, mbuf_flags(m1) | MBUF_MCAST); } else if (!mcast) { ni1 = ieee80211_find_node(ic, eh->ether_dhost); if (ni1 != NULL && ni1->ni_state == IEEE80211_STA_ASSOC) { m1 = m; m = NULL; } } if (m1 != NULL) { if (if_enqueue(ifp, m1)) { XYLog("%s %d OUTPUT_ERROR\n", __FUNCTION__, __LINE__); ifp->netStat->outputErrors++; } } } #endif if (m != NULL) { if ((ic->ic_flags & IEEE80211_F_RSNON) && eh->ether_type == htons(ETHERTYPE_PAE)) { ifp->netStat->inputPackets++; #if NBPFILTER > 0 /* * If we forward frame into transmitter of the AP, * we don't need to duplicate for DLT_EN10MB. */ if (ifp->if_bpf && m1 == NULL) bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); #endif #ifdef USE_APPLE_SUPPLICANT ml_enqueue(ml, m); #else #ifdef IO80211FAMILY_V2 if (ieee80211_is_8021x_akm((enum ieee80211_akm)ni->ni_rsnakms)) { XYLog("%s Duplicate EAPOL packet to user space\n", __FUNCTION__); mbuf_dup(m, MBUF_DONTWAIT, &m2); if (m2 != NULL) ifp->iface->inputPacket(m2, mbuf_len(m2)); } #endif ieee80211_eapol_key_input(ic, m, ni); #endif } else { ml_enqueue(ml, m); } } } void ieee80211_decap(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml) { struct ether_header eh; struct ieee80211_frame *wh; struct llc *llc; int mcast; if (mbuf_len(m) < hdrlen + LLC_SNAPFRAMELEN && mbuf_pullup(&m, hdrlen + LLC_SNAPFRAMELEN)) { ic->ic_stats.is_rx_decap++; return; } wh = mtod(m, struct ieee80211_frame *); mcast = IEEE80211_IS_MULTICAST(wh->i_addr1); switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: IEEE80211_ADDR_COPY(eh.ether_dhost, wh->i_addr1); IEEE80211_ADDR_COPY(eh.ether_shost, wh->i_addr2); break; case IEEE80211_FC1_DIR_TODS: IEEE80211_ADDR_COPY(eh.ether_dhost, wh->i_addr3); IEEE80211_ADDR_COPY(eh.ether_shost, wh->i_addr2); break; case IEEE80211_FC1_DIR_FROMDS: IEEE80211_ADDR_COPY(eh.ether_dhost, wh->i_addr1); IEEE80211_ADDR_COPY(eh.ether_shost, wh->i_addr3); break; case IEEE80211_FC1_DIR_DSTODS: IEEE80211_ADDR_COPY(eh.ether_dhost, wh->i_addr3); IEEE80211_ADDR_COPY(eh.ether_shost, ((struct ieee80211_frame_addr4 *)wh)->i_addr4); break; } llc = (struct llc *)((caddr_t)wh + hdrlen); if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP && llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 && llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0) { eh.ether_type = llc->llc_snap.ether_type; mbuf_adj(m, hdrlen + LLC_SNAPFRAMELEN - ETHER_HDR_LEN); } else { eh.ether_type = htons(mbuf_pkthdr_len(m) - hdrlen); mbuf_adj(m, hdrlen - ETHER_HDR_LEN); } memcpy(mtod(m, caddr_t), &eh, ETHER_HDR_LEN); if (!ALIGNED_POINTER(mtod(m, caddr_t) + ETHER_HDR_LEN, u_int32_t)) { mbuf_t m0 = m; m = m_dup_pkt(m0, ETHER_ALIGN, M_NOWAIT); mbuf_freem(m0); if (m == NULL) { ic->ic_stats.is_rx_decap++; return; } } ieee80211_enqueue_data(ic, m, ni, mcast, ml); } int ieee80211_amsdu_decap_validate(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { struct ether_header *eh = mtod(m, struct ether_header *); const uint8_t llc_hdr_mac[ETHER_ADDR_LEN] = { /* MAC address matching the 802.2 LLC header. */ LLC_SNAP_LSAP, LLC_SNAP_LSAP, LLC_UI, 0, 0, 0 }; /* * We are sorry, but this particular MAC address cannot be used. * This mitigates an attack where a single 802.11 frame is interpreted * as an A-MSDU because of a forged AMSDU-present bit in the 802.11 * QoS frame header: https://papers.mathyvanhoef.com/usenix2021.pdf * See Section 7.2, 'Countermeasures for the design flaws' */ if (ETHER_IS_EQ(eh->ether_dhost, llc_hdr_mac)) return 1; switch (ic->ic_opmode) { #ifndef IEEE80211_STA_ONLY case IEEE80211_M_HOSTAP: /* * Subframes must use the source address of the node which * transmitted the A-MSDU. Prevents MAC spoofing. */ if (!ETHER_IS_EQ(ni->ni_macaddr, eh->ether_shost)) return 1; break; #endif case IEEE80211_M_STA: /* Subframes must be addressed to me. */ if (!ETHER_IS_EQ(ic->ic_myaddr, eh->ether_dhost)) return 1; break; default: /* Ignore MONITOR/IBSS modes for now. */ break; } return 0; } /* * Decapsulate an Aggregate MSDU (see 7.2.2.2). */ void ieee80211_amsdu_decap(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml) { mbuf_t n; struct ether_header *eh; struct llc *llc; int len, pad, mcast; struct ieee80211_frame *wh; struct mbuf_list subframes = MBUF_LIST_INITIALIZER(); wh = mtod(m, struct ieee80211_frame *); mcast = IEEE80211_IS_MULTICAST(wh->i_addr1); /* strip 802.11 header */ mbuf_adj(m, hdrlen); while (mbuf_pkthdr_len(m) >= ETHER_HDR_LEN + LLC_SNAPFRAMELEN) { /* process an A-MSDU subframe */ mbuf_pullup(&m, ETHER_HDR_LEN + LLC_SNAPFRAMELEN); if (m == NULL) break; eh = mtod(m, struct ether_header *); /* examine 802.3 header */ len = ntohs(eh->ether_type); if (len < LLC_SNAPFRAMELEN) { DPRINTF(("A-MSDU subframe too short (%d)\n", len)); /* stop processing A-MSDU subframes */ ic->ic_stats.is_rx_decap++; ml_purge(&subframes); mbuf_freem(m); return; } llc = (struct llc *)&eh[1]; /* Examine the 802.2 LLC header after the A-MSDU header. */ if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP && llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 && llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0) { /* convert to Ethernet II header */ eh->ether_type = llc->llc_snap.ether_type; /* strip LLC+SNAP headers */ memmove((u_int8_t *)eh + LLC_SNAPFRAMELEN, eh, ETHER_HDR_LEN); mbuf_adj(m, LLC_SNAPFRAMELEN); len -= LLC_SNAPFRAMELEN; } len += ETHER_HDR_LEN; if (len > mbuf_pkthdr_len(m)) { /* stop processing A-MSDU subframes */ DPRINTF(("A-MSDU subframe too long (%d)\n", len)); ic->ic_stats.is_rx_decap++; ml_purge(&subframes); mbuf_freem(m); return; } /* "detach" our A-MSDU subframe from the others */ mbuf_split(m, len, MBUF_DONTWAIT, &n); if (n == NULL) { /* stop processing A-MSDU subframes */ ic->ic_stats.is_rx_decap++; ml_purge(&subframes); mbuf_freem(m); return; } if (ieee80211_amsdu_decap_validate(ic, m, ni)) { /* stop processing A-MSDU subframes */ ic->ic_stats.is_rx_decap++; ml_purge(&subframes); mbuf_freem(m); return; } ml_enqueue(&subframes, m); m = n; /* remove padding */ pad = ((len + 3) & ~3) - len; mbuf_adj(m, pad); } while ((n = ml_dequeue(&subframes)) != NULL) ieee80211_enqueue_data(ic, n, ni, mcast, ml); mbuf_freem(m); } /* * Parse an EDCA Parameter Set element (see 7.3.2.27). */ int ieee80211_parse_edca_params_body(struct ieee80211com *ic, const u_int8_t *frm) { u_int updtcount; int aci; /* * Check if EDCA parameters have changed XXX if we miss more than * 15 consecutive beacons, we might not detect changes to EDCA * parameters due to wraparound of the 4-bit Update Count field. */ updtcount = frm[0] & 0xf; if (updtcount == ic->ic_edca_updtcount) return 0; /* no changes to EDCA parameters, ignore */ ic->ic_edca_updtcount = updtcount; frm += 2; /* skip QoS Info & Reserved fields */ /* parse AC Parameter Records */ for (aci = 0; aci < EDCA_NUM_AC; aci++) { struct ieee80211_edca_ac_params *ac = &ic->ic_edca_ac[aci]; ac->ac_acm = (frm[0] >> 4) & 0x1; ac->ac_aifsn = frm[0] & 0xf; ac->ac_ecwmin = frm[1] & 0xf; ac->ac_ecwmax = frm[1] >> 4; ac->ac_txoplimit = LE_READ_2(frm + 2); frm += 4; } /* give drivers a chance to update their settings */ if ((ic->ic_flags & IEEE80211_F_QOS) && ic->ic_updateedca != NULL) (*ic->ic_updateedca)(ic); return 0; } int ieee80211_parse_edca_params(struct ieee80211com *ic, const u_int8_t *frm) { if (frm[1] < 18) { ic->ic_stats.is_rx_elem_toosmall++; return IEEE80211_REASON_IE_INVALID; } return ieee80211_parse_edca_params_body(ic, frm + 2); } int ieee80211_parse_wmm_params(struct ieee80211com *ic, const u_int8_t *frm) { if (frm[1] < 24) { ic->ic_stats.is_rx_elem_toosmall++; return IEEE80211_REASON_IE_INVALID; } return ieee80211_parse_edca_params_body(ic, frm + 8); } enum ieee80211_cipher ieee80211_parse_rsn_cipher(const u_int8_t selector[4]) { if (memcmp(selector, MICROSOFT_OUI, 3) == 0) { /* WPA */ switch (selector[3]) { case 0: /* use group data cipher suite */ return IEEE80211_CIPHER_USEGROUP; case 1: /* WEP-40 */ return IEEE80211_CIPHER_WEP40; case 2: /* TKIP */ return IEEE80211_CIPHER_TKIP; case 4: /* CCMP (RSNA default) */ return IEEE80211_CIPHER_CCMP; case 5: /* WEP-104 */ return IEEE80211_CIPHER_WEP104; } } else if (memcmp(selector, IEEE80211_OUI, 3) == 0) { /* RSN */ /* see 802.11-2012 Table 8-99 */ switch (selector[3]) { case 0: /* use group data cipher suite */ return IEEE80211_CIPHER_USEGROUP; case 1: /* WEP-40 */ return IEEE80211_CIPHER_WEP40; case 2: /* TKIP */ return IEEE80211_CIPHER_TKIP; case 4: /* CCMP (RSNA default) */ return IEEE80211_CIPHER_CCMP; case 5: /* WEP-104 */ return IEEE80211_CIPHER_WEP104; case 6: /* BIP */ return IEEE80211_CIPHER_BIP; } } return IEEE80211_CIPHER_NONE; /* ignore unknown ciphers */ } enum ieee80211_akm ieee80211_parse_rsn_akm(const u_int8_t selector[4]) { if (memcmp(selector, MICROSOFT_OUI, 3) == 0) { /* WPA */ switch (selector[3]) { case 1: /* IEEE 802.1X (RSNA default) */ return IEEE80211_AKM_8021X; case 2: /* PSK */ return IEEE80211_AKM_PSK; } } else if (memcmp(selector, IEEE80211_OUI, 3) == 0) { /* RSN */ /* from IEEE Std 802.11i-2004 - Table 20dc */ switch (selector[3]) { case 1: /* IEEE 802.1X (RSNA default) */ return IEEE80211_AKM_8021X; case 2: /* PSK */ return IEEE80211_AKM_PSK; case 5: /* IEEE 802.1X with SHA256 KDF */ return IEEE80211_AKM_SHA256_8021X; case 6: /* PSK with SHA256 KDF */ return IEEE80211_AKM_SHA256_PSK; } } return IEEE80211_AKM_NONE; /* ignore unknown AKMs */ } /* * Parse an RSN element (see 802.11-2012 8.4.2.27) */ int ieee80211_parse_rsn_body(struct ieee80211com *ic, const u_int8_t *frm, u_int len, struct ieee80211_rsnparams *rsn) { const u_int8_t *efrm; u_int16_t m, n, s; efrm = frm + len; /* check Version field */ if (LE_READ_2(frm) != 1) return IEEE80211_STATUS_RSN_IE_VER_UNSUP; frm += 2; /* all fields after the Version field are optional */ /* if Cipher Suite missing, default to CCMP */ rsn->rsn_groupcipher = IEEE80211_CIPHER_CCMP; rsn->rsn_nciphers = 1; rsn->rsn_ciphers = IEEE80211_CIPHER_CCMP; /* if Group Management Cipher Suite missing, defaut to BIP */ rsn->rsn_groupmgmtcipher = IEEE80211_CIPHER_BIP; /* if AKM Suite missing, default to 802.1X */ rsn->rsn_nakms = 1; rsn->rsn_akms = IEEE80211_AKM_8021X; /* if RSN capabilities missing, default to 0 */ rsn->rsn_caps = 0; rsn->rsn_npmkids = 0; /* read Group Data Cipher Suite field */ if (frm + 4 > efrm) return 0; rsn->rsn_groupcipher = ieee80211_parse_rsn_cipher(frm); if (rsn->rsn_groupcipher == IEEE80211_CIPHER_NONE || rsn->rsn_groupcipher == IEEE80211_CIPHER_USEGROUP || rsn->rsn_groupcipher == IEEE80211_CIPHER_BIP) return IEEE80211_STATUS_BAD_GROUP_CIPHER; frm += 4; /* read Pairwise Cipher Suite Count field */ if (frm + 2 > efrm) return 0; m = rsn->rsn_nciphers = LE_READ_2(frm); frm += 2; /* read Pairwise Cipher Suite List */ if (frm + m * 4 > efrm) return IEEE80211_STATUS_IE_INVALID; rsn->rsn_ciphers = IEEE80211_CIPHER_NONE; while (m-- > 0) { rsn->rsn_ciphers |= ieee80211_parse_rsn_cipher(frm); frm += 4; } if (rsn->rsn_ciphers & IEEE80211_CIPHER_USEGROUP) { if (rsn->rsn_ciphers != IEEE80211_CIPHER_USEGROUP) return IEEE80211_STATUS_BAD_PAIRWISE_CIPHER; if (rsn->rsn_groupcipher == IEEE80211_CIPHER_CCMP) return IEEE80211_STATUS_BAD_PAIRWISE_CIPHER; } /* read AKM Suite List Count field */ if (frm + 2 > efrm) return 0; n = rsn->rsn_nakms = LE_READ_2(frm); frm += 2; /* read AKM Suite List */ if (frm + n * 4 > efrm) return IEEE80211_STATUS_IE_INVALID; rsn->rsn_akms = IEEE80211_AKM_NONE; while (n-- > 0) { rsn->rsn_akms |= ieee80211_parse_rsn_akm(frm); frm += 4; } /* read RSN Capabilities field */ if (frm + 2 > efrm) return 0; rsn->rsn_caps = LE_READ_2(frm); frm += 2; /* read PMKID Count field */ if (frm + 2 > efrm) return 0; s = rsn->rsn_npmkids = LE_READ_2(frm); frm += 2; /* read PMKID List */ if (frm + s * IEEE80211_PMKID_LEN > efrm) return IEEE80211_STATUS_IE_INVALID; if (s != 0) { rsn->rsn_pmkids = frm; frm += s * IEEE80211_PMKID_LEN; } /* read Group Management Cipher Suite field */ if (frm + 4 > efrm) return 0; rsn->rsn_groupmgmtcipher = ieee80211_parse_rsn_cipher(frm); if (rsn->rsn_groupmgmtcipher != IEEE80211_CIPHER_BIP) return IEEE80211_STATUS_BAD_GROUP_CIPHER; return IEEE80211_STATUS_SUCCESS; } int ieee80211_parse_rsn(struct ieee80211com *ic, const u_int8_t *frm, struct ieee80211_rsnparams *rsn) { if (frm[1] < 2) { ic->ic_stats.is_rx_elem_toosmall++; return IEEE80211_STATUS_IE_INVALID; } return ieee80211_parse_rsn_body(ic, frm + 2, frm[1], rsn); } int ieee80211_parse_wpa(struct ieee80211com *ic, const u_int8_t *frm, struct ieee80211_rsnparams *rsn) { if (frm[1] < 6) { ic->ic_stats.is_rx_elem_toosmall++; return IEEE80211_STATUS_IE_INVALID; } return ieee80211_parse_rsn_body(ic, frm + 6, frm[1] - 4, rsn); } /* * Create (or update) a copy of an information element. */ int ieee80211_save_ie(const u_int8_t *frm, u_int8_t **ie) { int olen = *ie ? 2 + (*ie)[1] : 0; int len = 2 + frm[1]; if (*ie == NULL || olen != len) { if (*ie != NULL) free(*ie); *ie = (u_int8_t *)malloc(len, 0, 0); if (*ie == NULL) return ENOMEM; } memcpy(*ie, frm, len); return 0; } /* * zxy, save tlv ie for Apple80211 */ int ieee80211_save_ie_tlv(const u_int8_t *frm, u_int8_t **ie, uint32_t *accept_len, uint32_t len) { int olen = *accept_len; if (*ie == NULL || olen != len) { if (*ie != NULL && *accept_len > 0) free(*ie); *ie = (u_int8_t *)malloc(len, 1, 1); if (*ie == NULL) return ENOMEM; } *accept_len = len; memcpy(*ie, frm, len); return 0; } /*- * Beacon/Probe response frame format: * [8] Timestamp * [2] Beacon interval * [2] Capability * [tlv] Service Set Identifier (SSID) * [tlv] Supported rates * [tlv] DS Parameter Set (802.11g) * [tlv] ERP Information (802.11g) * [tlv] Extended Supported Rates (802.11g) * [tlv] RSN (802.11i) * [tlv] EDCA Parameter Set (802.11e) * [tlv] QoS Capability (Beacon only, 802.11e) * [tlv] HT Capabilities (802.11n) * [tlv] HT Operation (802.11n) */ void ieee80211_recv_probe_resp(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *rni, struct ieee80211_rxinfo *rxi, int isprobe) { struct ieee80211_node *ni = NULL; const struct ieee80211_frame *wh; const u_int8_t *frm, *efrm; const u_int8_t *tstamp, *ssid, *rates, *xrates, *edcaie, *wmmie; const u_int8_t *rsnie, *wpaie, *htcaps, *htop; const uint8_t *csa; const uint8_t *vhtcap; const uint8_t *vhtopmode; const uint8_t *hecap; const uint8_t *heopmode; u_int16_t capinfo, bintval; u_int8_t chan, bchan, erp, dtim_count, dtim_period; int is_new; /* * We process beacon/probe response frames for: * o station mode: to collect state * updates such as 802.11g slot time and for passive * scanning of APs * o adhoc mode: to discover neighbors * o hostap mode: for passive scanning of neighbor APs * o when scanning * In other words, in all modes other than monitor (which * does not process incoming frames) and adhoc-demo (which * does not use management frames at all). */ #ifdef DIAGNOSTIC if (ic->ic_opmode != IEEE80211_M_STA && #ifndef IEEE80211_STA_ONLY ic->ic_opmode != IEEE80211_M_IBSS && ic->ic_opmode != IEEE80211_M_HOSTAP && #endif ic->ic_state != IEEE80211_S_SCAN) { panic("%s: impossible operating mode", __func__); } #endif /* make sure all mandatory fixed fields are present */ if (mbuf_len(m) < sizeof(*wh) + 12) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; efrm = mtod(m, u_int8_t *) + mbuf_len(m); tstamp = frm; frm += 8; bintval = LE_READ_2(frm); frm += 2; capinfo = LE_READ_2(frm); frm += 2; ssid = rates = xrates = edcaie = wmmie = rsnie = wpaie = csa = vhtcap = vhtopmode = hecap = heopmode = NULL; htcaps = htop = NULL; if (rxi->rxi_chan) bchan = rxi->rxi_chan; else bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); chan = bchan; erp = 0; dtim_count = dtim_period = 0; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) { ic->ic_stats.is_rx_elem_toosmall++; break; } switch (frm[0]) { case IEEE80211_ELEMID_SSID: ssid = frm; break; case IEEE80211_ELEMID_CSA: csa = frm; break; case IEEE80211_ELEMID_RATES: rates = frm; break; case IEEE80211_ELEMID_DSPARMS: if (frm[1] < 1) { ic->ic_stats.is_rx_elem_toosmall++; break; } chan = frm[2]; break; case IEEE80211_ELEMID_XRATES: xrates = frm; break; case IEEE80211_ELEMID_ERP: if (frm[1] < 1) { ic->ic_stats.is_rx_elem_toosmall++; break; } erp = frm[2]; break; case IEEE80211_ELEMID_VHT_CAP: vhtcap = frm; break; case IEEE80211_ELEMID_VHT_OPMODE: vhtopmode = frm; break; case IEEE80211_ELEMID_RSN: rsnie = frm; break; case IEEE80211_ELEMID_EDCAPARMS: edcaie = frm; break; case IEEE80211_ELEMID_HTCAPS: htcaps = frm; break; case IEEE80211_ELEMID_HTOP: htop = frm; break; case IEEE80211_ELEMID_TIM: if (frm[1] > 3) { dtim_count = frm[2]; dtim_period = frm[3]; } break; case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) { ic->ic_stats.is_rx_elem_toosmall++; break; } if (memcmp(frm + 2, MICROSOFT_OUI, 3) == 0) { if (frm[5] == 1) wpaie = frm; else if (frm[1] >= 5 && frm[5] == 2 && frm[6] == 1) wmmie = frm; } break; case IEEE80211_ELEMID_EXTENSION: switch (frm[2]) { case IEEE80211_ELEMID_EXT_HE_MU_EDCA: break; case IEEE80211_ELEMID_EXT_HE_CAPABILITY: hecap = frm; break; case IEEE80211_ELEMID_EXT_HE_OPERATION: heopmode = frm; break; case IEEE80211_ELEMID_EXT_UORA: break; case IEEE80211_ELEMID_EXT_MAX_CHANNEL_SWITCH_TIME: break; case IEEE80211_ELEMID_EXT_MULTIPLE_BSSID_CONFIGURATION: break; case IEEE80211_ELEMID_EXT_HE_SPR: break; case IEEE80211_ELEMID_EXT_HE_6GHZ_CAPA: break; } break; } frm += 2 + frm[1]; } /* supported rates element is mandatory */ if (rates == NULL || rates[1] > IEEE80211_RATE_MAXSIZE) { DPRINTF(("invalid supported rates element\n")); return; } /* SSID element is mandatory */ if (ssid == NULL || ssid[1] > IEEE80211_NWID_LEN) { DPRINTF(("invalid SSID element\n")); return; } if (csa != NULL && csa[1] < 3 * sizeof(uint8_t)) { DPRINTF(("csa ie too short, got %d, expected %lu\n", csa[1], 3 * sizeof(uint8_t))); csa = NULL; } if (vhtcap != NULL && vhtcap[1] < sizeof(struct ieee80211_ie_vhtcap) - 2) { DPRINTF(("vhtcap ie too short, got %d, expected %lu\n", vhtcap[1], sizeof(struct ieee80211_ie_vhtcap) - 2)); vhtcap = NULL; } if (vhtopmode != NULL && vhtopmode[1] < sizeof(struct ieee80211_ie_vht_operation) - 2) { DPRINTF(("vhtopmode ie too short, got %d, expected %lu\n", vhtopmode[1], sizeof(struct ieee80211_ie_vht_operation) - 2)); vhtopmode = NULL; } if ( #if IEEE80211_CHAN_MAX < 255 chan > IEEE80211_CHAN_MAX || #endif (isclr(ic->ic_chan_active, chan) && ((ic->ic_caps & IEEE80211_C_SCANALL) == 0 || (ic->ic_flags & IEEE80211_F_BGSCAN) == 0))) { DPRINTF(("ignore %s with invalid channel %u\n", isprobe ? "probe response" : "beacon", chan)); ic->ic_stats.is_rx_badchan++; return; } if ((rxi->rxi_chan != 0 && chan != rxi->rxi_chan) || ((ic->ic_state != IEEE80211_S_SCAN || !(ic->ic_caps & IEEE80211_C_SCANALL)) && chan != bchan)) { /* * Frame was received on a channel different from the * one indicated in the DS params element id; * silently discard it. * * NB: this can happen due to signal leakage. */ DPRINTF(("ignore %s on channel %u marked for channel %u\n", isprobe ? "probe response" : "beacon", bchan, chan)); ic->ic_stats.is_rx_chanmismatch++; return; } #ifdef IEEE80211_DEBUG if (ieee80211_debug > 1 && (ni == NULL || ic->ic_state == IEEE80211_S_SCAN || (ic->ic_flags & IEEE80211_F_BGSCAN))) { XYLog("%s: %s%s on chan %u (bss chan %u) ", __func__, (ni == NULL ? "new " : ""), isprobe ? "probe response" : "beacon", chan, bchan); ieee80211_print_essid(ssid + 2, ssid[1]); XYLog(" from %s\n", ether_sprintf((u_int8_t *)wh->i_addr2)); XYLog("%s: caps 0x%x bintval %u erp 0x%x\n", __func__, capinfo, bintval, erp); } #endif if ((ni = ieee80211_find_node(ic, wh->i_addr2)) == NULL) { ni = ieee80211_alloc_node(ic, wh->i_addr2); if (ni == NULL) return; is_new = 1; } else is_new = 0; ni->ni_chan = &ic->ic_channels[chan]; if (htcaps) ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]); if (htop && !ieee80211_setup_htop(ni, htop + 2, htop[1], 1)) htop = NULL; /* invalid HTOP */ if (vhtcap != NULL && vhtopmode != NULL) { ieee80211_setup_vhtcaps(ic, ni, vhtcap); ieee80211_setup_vhtopmode(ni, vhtopmode); } if (hecap != NULL && heopmode != NULL) { ieee80211_setup_hecaps(ni, hecap + 3, hecap[1] - 1); ieee80211_setup_heop(ni, heopmode + 3, heopmode[1] - 1); } ni->ni_dtimcount = dtim_count; ni->ni_dtimperiod = dtim_period; #ifdef AIRPORT ni->ni_age_ts = airport_up_time(); #endif /* * When operating in station mode, check for state updates * while we're associated. */ if (ic->ic_opmode == IEEE80211_M_STA && ic->ic_state == IEEE80211_S_RUN && ni->ni_state == IEEE80211_STA_BSS) { int updateprot = 0; /* * Check if protection mode has changed since last beacon. */ if (ni->ni_erp != erp) { DPRINTF(("[%s] erp change: was 0x%x, now 0x%x\n", ether_sprintf((u_int8_t *)wh->i_addr2), ni->ni_erp, erp)); if ((ic->ic_curmode == IEEE80211_MODE_11G || (ic->ic_curmode == IEEE80211_MODE_11N && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))) && (erp & IEEE80211_ERP_USE_PROTECTION)) ic->ic_flags |= IEEE80211_F_USEPROT; else ic->ic_flags &= ~IEEE80211_F_USEPROT; ic->ic_bss->ni_erp = erp; updateprot = 1; } if (htop && (ic->ic_bss->ni_flags & IEEE80211_NODE_HT)) { enum ieee80211_htprot htprot_last, htprot; htprot_last = (enum ieee80211_htprot)((ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK) >> IEEE80211_HTOP1_PROT_SHIFT); htprot = (enum ieee80211_htprot)((ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK) >> IEEE80211_HTOP1_PROT_SHIFT); if (htprot_last != htprot) { DPRINTF(("[%s] htprot change: was %d, now %d\n", ether_sprintf((u_int8_t *)wh->i_addr2), htprot_last, htprot)); ic->ic_stats.is_ht_prot_change++; ic->ic_bss->ni_htop1 = ni->ni_htop1; updateprot = 1; } } if (updateprot && ic->ic_updateprot != NULL) ic->ic_updateprot(ic); /* * Check if 40MHz channel mode has changed since last beacon. */ if (htop && !(ic->ic_bss->ni_flags & IEEE80211_NODE_VHT) && !(ic->ic_bss->ni_flags & IEEE80211_NODE_HE) && (ic->ic_bss->ni_flags & IEEE80211_NODE_HT) && (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40)) { uint8_t chw_last, chw, sco_last, sco; chw_last = (ic->ic_bss->ni_htop0 & IEEE80211_HTOP0_CHW); chw = (ni->ni_htop0 & IEEE80211_HTOP0_CHW); sco_last = ((ic->ic_bss->ni_htop0 & IEEE80211_HTOP0_SCO_MASK) >> IEEE80211_HTOP0_SCO_SHIFT); sco = ((ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK) >> IEEE80211_HTOP0_SCO_SHIFT); ic->ic_bss->ni_htop0 = ni->ni_htop0; if (chw_last != chw || sco_last != sco) { XYLog("[%s] channel mode change: was %d, now %d, sco was: %d, now: %d\n", ether_sprintf((u_int8_t *)wh->i_addr2), chw_last, chw, sco_last, sco); if (ic->ic_update_chw != NULL) ic->ic_update_chw(ic); } } else if (htop) ic->ic_bss->ni_htop0 = ni->ni_htop0; /* * Check if AP short slot time setting has changed * since last beacon and give the driver a chance to * update the hardware. */ if ((ni->ni_capinfo ^ capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) { ieee80211_set_shortslottime(ic, ic->ic_curmode == IEEE80211_MODE_11A || (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)); } if (!ic->ic_bss->ni_dtimperiod) { ic->ic_bss->ni_dtimcount = ni->ni_dtimcount; ic->ic_bss->ni_dtimperiod = ni->ni_dtimperiod ?: 1; if (ic->ic_updatedtim != NULL) ic->ic_updatedtim(ic); } /* * Reset management timer. If it is non-zero in RUN state, the * driver sent a probe request after a missed beacon event. * This probe response indicates the AP is still serving us * so don't allow ieee80211_watchdog() to move us into SCAN. */ if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0) ic->ic_mgt_timer = 0; } /* * We do not try to update EDCA parameters if QoS was not negotiated * with the AP at association time. */ if (ni->ni_flags & IEEE80211_NODE_QOS) { /* always prefer EDCA IE over Wi-Fi Alliance WMM IE */ if ((edcaie != NULL && ieee80211_parse_edca_params(ic, edcaie) == 0) || (wmmie != NULL && ieee80211_parse_wmm_params(ic, wmmie) == 0)) ni->ni_flags |= IEEE80211_NODE_QOS; else ni->ni_flags &= ~IEEE80211_NODE_QOS; } if (ic->ic_state == IEEE80211_S_SCAN || (ic->ic_flags & IEEE80211_F_BGSCAN)) { struct ieee80211_rsnparams rsn, wpa; uint32_t tlv_len = (mtod(m, u_int8_t *) + mbuf_len(m)) - (u_int8_t *)&wh[1] + 1 - 8 - 2 - 2; ieee80211_save_ie_tlv(((u_int8_t *)&wh[1]) + 8 + 2 + 2, &ni->ni_rsnie_tlv, &ni->ni_rsnie_tlv_len, tlv_len); ni->ni_rsnprotos = IEEE80211_PROTO_NONE; ni->ni_supported_rsnprotos = IEEE80211_PROTO_NONE; ni->ni_rsnakms = 0; ni->ni_supported_rsnakms = 0; ni->ni_rsnciphers = 0; ni->ni_rsngroupcipher = (enum ieee80211_cipher)0; ni->ni_rsngroupmgmtcipher = (enum ieee80211_cipher)0; ni->ni_rsncaps = 0; if (rsnie != NULL && ieee80211_parse_rsn(ic, rsnie, &rsn) == 0) { ni->ni_supported_rsnprotos |= IEEE80211_PROTO_RSN; ni->ni_supported_rsnakms |= rsn.rsn_akms; } if (wpaie != NULL && ieee80211_parse_wpa(ic, wpaie, &wpa) == 0) { ni->ni_supported_rsnprotos |= IEEE80211_PROTO_WPA; ni->ni_supported_rsnakms |= wpa.rsn_akms; } /* * If the AP advertises both WPA and RSN IEs (WPA1+WPA2), * we only use the highest protocol version we support. */ if (rsnie != NULL && (ni->ni_supported_rsnprotos & IEEE80211_PROTO_RSN) && (ic->ic_caps & IEEE80211_C_RSN)) { if (ieee80211_save_ie(rsnie, &ni->ni_rsnie) == 0 #ifndef IEEE80211_STA_ONLY && ic->ic_opmode != IEEE80211_M_HOSTAP #endif ) { ni->ni_rsnprotos = IEEE80211_PROTO_RSN; ni->ni_rsnakms = rsn.rsn_akms; ni->ni_rsnciphers = rsn.rsn_ciphers; ni->ni_rsngroupcipher = rsn.rsn_groupcipher; ni->ni_rsngroupmgmtcipher = rsn.rsn_groupmgmtcipher; ni->ni_rsncaps = rsn.rsn_caps; } } else if (wpaie != NULL && (ni->ni_supported_rsnprotos & IEEE80211_PROTO_WPA) && (ic->ic_caps & IEEE80211_C_RSN)) { if (ieee80211_save_ie(wpaie, &ni->ni_rsnie) == 0 #ifndef IEEE80211_STA_ONLY && ic->ic_opmode != IEEE80211_M_HOSTAP #endif ) { ni->ni_rsnprotos = IEEE80211_PROTO_WPA; ni->ni_rsnakms = wpa.rsn_akms; ni->ni_rsnciphers = wpa.rsn_ciphers; ni->ni_rsngroupcipher = wpa.rsn_groupcipher; ni->ni_rsngroupmgmtcipher = wpa.rsn_groupmgmtcipher; ni->ni_rsncaps = wpa.rsn_caps; } } } /* * Set our SSID if we do not know it yet. * If we are doing a directed scan for an AP with a hidden SSID * we must collect the SSID from a probe response to override * a non-zero-length SSID filled with zeroes that we may have * received earlier in a beacon. */ if (ssid[1] != 0 && ni->ni_essid[0] == '\0') { ni->ni_esslen = ssid[1]; memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); /* we know that ssid[1] <= IEEE80211_NWID_LEN */ memcpy(ni->ni_essid, &ssid[2], ssid[1]); } IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); if (ic->ic_state == IEEE80211_S_SCAN && IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) { /* * During a scan on 5Ghz, prefer RSSI measured for probe * response frames. i.e. don't allow beacons to lower the * measured RSSI. Some 5GHz APs send beacons with much * less Tx power than they use for probe responses. */ if (isprobe || ni->ni_rssi == 0) ni->ni_rssi = rxi->rxi_rssi; else if (ni->ni_rssi < rxi->rxi_rssi) ni->ni_rssi = rxi->rxi_rssi; } else ni->ni_rssi = rxi->rxi_rssi; ni->ni_rstamp = rxi->rxi_tstamp; memcpy(ni->ni_tstamp, tstamp, sizeof(ni->ni_tstamp)); ni->ni_intval = bintval; ni->ni_capinfo = capinfo; ni->ni_erp = erp; /* NB: must be after ni_chan is setup */ ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT); #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS && is_new && isprobe) { /* * Fake an association so the driver can setup it's * private state. The rate set has been setup above; * there is no handshake as in ap/station operation. */ if (ic->ic_newassoc) (*ic->ic_newassoc)(ic, ni, 1); } #endif } #ifndef IEEE80211_STA_ONLY /*- * Probe request frame format: * [tlv] SSID * [tlv] Supported rates * [tlv] Extended Supported Rates (802.11g) * [tlv] HT Capabilities (802.11n) */ void ieee80211_recv_probe_req(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi) { const struct ieee80211_frame *wh; const u_int8_t *frm, *efrm; const u_int8_t *ssid, *rates, *xrates, *htcaps; u_int8_t rate; if (ic->ic_opmode == IEEE80211_M_STA || ic->ic_state != IEEE80211_S_RUN) return; wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; efrm = mtod(m, u_int8_t *) + mbuf_len(m); ssid = rates = xrates = htcaps = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) { ic->ic_stats.is_rx_elem_toosmall++; break; } switch (frm[0]) { case IEEE80211_ELEMID_SSID: ssid = frm; break; case IEEE80211_ELEMID_RATES: rates = frm; break; case IEEE80211_ELEMID_XRATES: xrates = frm; break; case IEEE80211_ELEMID_HTCAPS: htcaps = frm; break; } frm += 2 + frm[1]; } /* supported rates element is mandatory */ if (rates == NULL || rates[1] > IEEE80211_RATE_MAXSIZE) { DPRINTF(("invalid supported rates element\n")); return; } /* SSID element is mandatory */ if (ssid == NULL || ssid[1] > IEEE80211_NWID_LEN) { DPRINTF(("invalid SSID element\n")); return; } /* check that the specified SSID (if not wildcard) matches ours */ if (ssid[1] != 0 && (ssid[1] != ic->ic_bss->ni_esslen || memcmp(&ssid[2], ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen))) { DPRINTF(("SSID mismatch\n")); ic->ic_stats.is_rx_ssidmismatch++; return; } /* refuse wildcard SSID if we're hiding our SSID in beacons */ if (ssid[1] == 0 && (ic->ic_userflags & IEEE80211_F_HIDENWID)) { DPRINTF(("wildcard SSID rejected")); ic->ic_stats.is_rx_ssidmismatch++; return; } if (ni == ic->ic_bss) { ni = ieee80211_find_node(ic, wh->i_addr2); if (ni == NULL) ni = ieee80211_dup_bss(ic, wh->i_addr2); if (ni == NULL) return; DPRINTF(("new probe req from %s\n", ether_sprintf((u_int8_t *)wh->i_addr2))); } ni->ni_rssi = rxi->rxi_rssi; ni->ni_rstamp = rxi->rxi_tstamp; rate = ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (rate & IEEE80211_RATE_BASIC) { DPRINTF(("rate mismatch for %s\n", ether_sprintf((u_int8_t *)wh->i_addr2))); return; } if (htcaps) ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]); else ieee80211_clear_htcaps(ni); IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0); } #endif /* IEEE80211_STA_ONLY */ /*- * Authentication frame format: * [2] Authentication algorithm number * [2] Authentication transaction sequence number * [2] Status code */ void ieee80211_recv_auth(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi) { const struct ieee80211_frame *wh; const u_int8_t *frm; u_int16_t algo, seq, status; /* make sure all mandatory fixed fields are present */ if (mbuf_len(m) < sizeof(*wh) + 6) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; algo = LE_READ_2(frm); frm += 2; seq = LE_READ_2(frm); frm += 2; status = LE_READ_2(frm); frm += 2; DPRINTF(("auth %d seq %d from %s\n", algo, seq, ether_sprintf((u_int8_t *)wh->i_addr2))); /* only "open" auth mode is supported */ if (algo != IEEE80211_AUTH_ALG_OPEN) { DPRINTF(("unsupported auth algorithm %d from %s\n", algo, ether_sprintf((u_int8_t *)wh->i_addr2))); ic->ic_stats.is_rx_auth_unsupported++; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* XXX hack to workaround calling convention */ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, IEEE80211_STATUS_ALG << 16 | ((seq + 1) & 0xfff)); } #endif return; } ic->ic_deauth_reason = IEEE80211_REASON_UNSPECIFIED; ic->ic_assoc_status = 0xffff; ieee80211_auth_open(ic, wh, ni, rxi, seq, status); } #ifndef IEEE80211_STA_ONLY /*- * (Re)Association request frame format: * [2] Capability information * [2] Listen interval * [6*] Current AP address (Reassociation only) * [tlv] SSID * [tlv] Supported rates * [tlv] Extended Supported Rates (802.11g) * [tlv] RSN (802.11i) * [tlv] QoS Capability (802.11e) * [tlv] HT Capabilities (802.11n) */ void ieee80211_recv_assoc_req(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi, int reassoc) { const struct ieee80211_frame *wh; const u_int8_t *frm, *efrm; const u_int8_t *ssid, *rates, *xrates, *rsnie, *wpaie, *wmeie, *htcaps; u_int16_t capinfo, bintval; int resp, status = 0; struct ieee80211_rsnparams rsn; u_int8_t rate; const u_int8_t *saveie = NULL; if (ic->ic_opmode != IEEE80211_M_HOSTAP || ic->ic_state != IEEE80211_S_RUN) return; /* make sure all mandatory fixed fields are present */ if (mbuf_len(m) < sizeof(*wh) + (reassoc ? 10 : 4)) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; efrm = mtod(m, u_int8_t *) + mbuf_len(m); if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) { DPRINTF(("ignore other bss from %s\n", ether_sprintf((u_int8_t *)wh->i_addr2))); ic->ic_stats.is_rx_assoc_bss++; return; } capinfo = LE_READ_2(frm); frm += 2; bintval = LE_READ_2(frm); frm += 2; // uint32_t tlv_len = (mtod(m, u_int8_t *) + mbuf_len(m)) - (u_int8_t *)&wh[1] + 1 - 2 - 2; // ieee80211_save_ie_tlv(frm, &ni->ni_rsnie_tlv, &ni->ni_rsnie_tlv_len, tlv_len); if (reassoc) { frm += IEEE80211_ADDR_LEN; /* skip current AP address */ resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP; } else resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP; ssid = rates = xrates = rsnie = wpaie = wmeie = htcaps = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) { ic->ic_stats.is_rx_elem_toosmall++; break; } switch (frm[0]) { case IEEE80211_ELEMID_SSID: ssid = frm; break; case IEEE80211_ELEMID_RATES: rates = frm; break; case IEEE80211_ELEMID_XRATES: xrates = frm; break; case IEEE80211_ELEMID_RSN: rsnie = frm; break; case IEEE80211_ELEMID_QOS_CAP: break; case IEEE80211_ELEMID_HTCAPS: htcaps = frm; break; case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) { ic->ic_stats.is_rx_elem_toosmall++; break; } if (memcmp(frm + 2, MICROSOFT_OUI, 3) == 0) { if (frm[5] == 1) wpaie = frm; /* WME info IE: len=7 type=2 subtype=0 */ if (frm[1] == 7 && frm[5] == 2 && frm[6] == 0) wmeie = frm; } break; } frm += 2 + frm[1]; } /* supported rates element is mandatory */ if (rates == NULL || rates[1] > IEEE80211_RATE_MAXSIZE) { DPRINTF(("invalid supported rates element\n")); return; } /* SSID element is mandatory */ if (ssid == NULL || ssid[1] > IEEE80211_NWID_LEN) { DPRINTF(("invalid SSID element\n")); return; } /* check that the specified SSID matches ours */ if (ssid[1] != ic->ic_bss->ni_esslen || memcmp(&ssid[2], ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen)) { DPRINTF(("SSID mismatch\n")); ic->ic_stats.is_rx_ssidmismatch++; return; } if (ni->ni_state != IEEE80211_STA_AUTH && ni->ni_state != IEEE80211_STA_ASSOC) { DPRINTF(("deny %sassoc from %s, not authenticated\n", reassoc ? "re" : "", ether_sprintf((u_int8_t *)wh->i_addr2))); ni = ieee80211_find_node(ic, wh->i_addr2); if (ni == NULL) ni = ieee80211_dup_bss(ic, wh->i_addr2); if (ni != NULL) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_ASSOC_NOT_AUTHED); } ic->ic_stats.is_rx_assoc_notauth++; return; } if (ni->ni_state == IEEE80211_STA_ASSOC && (ni->ni_flags & IEEE80211_NODE_MFP)) { if (ni->ni_flags & IEEE80211_NODE_SA_QUERY_FAILED) { /* send a protected Disassociate frame */ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_AUTH_EXPIRE); /* terminate the old SA */ ieee80211_node_leave(ic, ni); } else { /* reject the (Re)Association Request temporarily */ IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_TRY_AGAIN_LATER); /* start SA Query procedure if not already engaged */ if (!(ni->ni_flags & IEEE80211_NODE_SA_QUERY)) ieee80211_sa_query_request(ic, ni); /* do not modify association state */ } return; } if (!(capinfo & IEEE80211_CAPINFO_ESS)) { ic->ic_stats.is_rx_assoc_capmismatch++; status = IEEE80211_STATUS_CAPINFO; goto end; } rate = ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (rate & IEEE80211_RATE_BASIC) { ic->ic_stats.is_rx_assoc_norate++; status = IEEE80211_STATUS_BASIC_RATE; goto end; } ni->ni_rsnprotos = IEEE80211_PROTO_NONE; ni->ni_supported_rsnprotos = IEEE80211_PROTO_NONE; ni->ni_rsnakms = 0; ni->ni_supported_rsnakms = 0; ni->ni_rsnciphers = 0; ni->ni_rsngroupcipher = (enum ieee80211_cipher)0; ni->ni_rsngroupmgmtcipher = (enum ieee80211_cipher)0; ni->ni_rsncaps = 0; /* * A station should never include both a WPA and an RSN IE * in its (Re)Association Requests, but if it does, we only * consider the IE of the highest version of the protocol * that is allowed (ie RSN over WPA). */ if (rsnie != NULL) { status = ieee80211_parse_rsn(ic, rsnie, &rsn); if (status != 0) goto end; ni->ni_supported_rsnprotos = IEEE80211_PROTO_RSN; ni->ni_supported_rsnakms = rsn.rsn_akms; if ((ic->ic_flags & IEEE80211_F_RSNON) && (ic->ic_rsnprotos & IEEE80211_PROTO_RSN)) { ni->ni_rsnprotos = IEEE80211_PROTO_RSN; saveie = rsnie; } } else if (wpaie != NULL) { status = ieee80211_parse_wpa(ic, wpaie, &rsn); if (status != 0) goto end; ni->ni_supported_rsnprotos = IEEE80211_PROTO_WPA; ni->ni_supported_rsnakms = rsn.rsn_akms; if ((ic->ic_flags & IEEE80211_F_RSNON) && (ic->ic_rsnprotos & IEEE80211_PROTO_WPA)) { ni->ni_rsnprotos = IEEE80211_PROTO_WPA; saveie = wpaie; } } if (ic->ic_flags & IEEE80211_F_QOS) { if (wmeie != NULL) ni->ni_flags |= IEEE80211_NODE_QOS; else /* for Reassociation */ ni->ni_flags &= ~IEEE80211_NODE_QOS; } if (ic->ic_flags & IEEE80211_F_RSNON) { if (ni->ni_rsnprotos == IEEE80211_PROTO_NONE) { /* * In an RSN, an AP shall not associate with STAs * that fail to include the RSN IE in the * (Re)Association Request. */ status = IEEE80211_STATUS_IE_INVALID; goto end; } /* * The initiating STA's RSN IE shall include one authentication * and pairwise cipher suite among those advertised by the * targeted AP. It shall also specify the group cipher suite * specified by the targeted AP. */ if (rsn.rsn_nakms != 1 || !(rsn.rsn_akms & ic->ic_bss->ni_rsnakms)) { status = IEEE80211_STATUS_BAD_AKMP; ni->ni_rsnprotos = IEEE80211_PROTO_NONE; goto end; } if (rsn.rsn_nciphers != 1 || !(rsn.rsn_ciphers & ic->ic_bss->ni_rsnciphers)) { status = IEEE80211_STATUS_BAD_PAIRWISE_CIPHER; ni->ni_rsnprotos = IEEE80211_PROTO_NONE; goto end; } if (rsn.rsn_groupcipher != ic->ic_bss->ni_rsngroupcipher) { status = IEEE80211_STATUS_BAD_GROUP_CIPHER; ni->ni_rsnprotos = IEEE80211_PROTO_NONE; goto end; } if ((ic->ic_bss->ni_rsncaps & IEEE80211_RSNCAP_MFPR) && !(rsn.rsn_caps & IEEE80211_RSNCAP_MFPC)) { status = IEEE80211_STATUS_MFP_POLICY; ni->ni_rsnprotos = IEEE80211_PROTO_NONE; goto end; } if ((ic->ic_bss->ni_rsncaps & IEEE80211_RSNCAP_MFPC) && (rsn.rsn_caps & (IEEE80211_RSNCAP_MFPC | IEEE80211_RSNCAP_MFPR)) == IEEE80211_RSNCAP_MFPR) { /* STA advertises an invalid setting */ status = IEEE80211_STATUS_MFP_POLICY; ni->ni_rsnprotos = IEEE80211_PROTO_NONE; goto end; } /* * A STA that has associated with Management Frame Protection * enabled shall not use cipher suite pairwise selector WEP40, * WEP104, TKIP, or "Use Group cipher suite". */ if ((rsn.rsn_caps & IEEE80211_RSNCAP_MFPC) && (rsn.rsn_ciphers != IEEE80211_CIPHER_CCMP || rsn.rsn_groupmgmtcipher != ic->ic_bss->ni_rsngroupmgmtcipher)) { status = IEEE80211_STATUS_MFP_POLICY; ni->ni_rsnprotos = IEEE80211_PROTO_NONE; goto end; } /* * Disallow new associations using TKIP if countermeasures * are active. */ if ((ic->ic_flags & IEEE80211_F_COUNTERM) && (rsn.rsn_ciphers == IEEE80211_CIPHER_TKIP || rsn.rsn_groupcipher == IEEE80211_CIPHER_TKIP)) { status = IEEE80211_STATUS_CIPHER_REJ_POLICY; ni->ni_rsnprotos = IEEE80211_PROTO_NONE; goto end; } /* everything looks fine, save IE and parameters */ if (saveie == NULL || ieee80211_save_ie(saveie, &ni->ni_rsnie) != 0) { status = IEEE80211_STATUS_TOOMANY; ni->ni_rsnprotos = IEEE80211_PROTO_NONE; goto end; } ni->ni_rsnakms = rsn.rsn_akms; ni->ni_rsnciphers = rsn.rsn_ciphers; ni->ni_rsngroupcipher = ic->ic_bss->ni_rsngroupcipher; ni->ni_rsngroupmgmtcipher = ic->ic_bss->ni_rsngroupmgmtcipher; ni->ni_rsncaps = rsn.rsn_caps; if (ieee80211_is_8021x_akm((enum ieee80211_akm)ni->ni_rsnakms)) { struct ieee80211_pmk *pmk = NULL; const u_int8_t *pmkid = rsn.rsn_pmkids; /* * Check if we have a cached PMK entry matching one * of the PMKIDs specified in the RSN IE. */ while (rsn.rsn_npmkids-- > 0) { pmk = ieee80211_pmksa_find(ic, ni, pmkid); if (pmk != NULL) break; pmkid += IEEE80211_PMKID_LEN; } if (pmk != NULL) { memcpy(ni->ni_pmk, pmk->pmk_key, IEEE80211_PMK_LEN); memcpy(ni->ni_pmkid, pmk->pmk_pmkid, IEEE80211_PMKID_LEN); ni->ni_flags |= IEEE80211_NODE_PMK; } } } ni->ni_rssi = rxi->rxi_rssi; ni->ni_rstamp = rxi->rxi_tstamp; ni->ni_intval = bintval; ni->ni_capinfo = capinfo; ni->ni_chan = ic->ic_bss->ni_chan; if (htcaps) ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]); else ieee80211_clear_htcaps(ni); end: if (status != 0) { IEEE80211_SEND_MGMT(ic, ni, resp, status); ieee80211_node_leave(ic, ni); } else ieee80211_node_join(ic, ni, resp); } #endif /* IEEE80211_STA_ONLY */ /*- * (Re)Association response frame format: * [2] Capability information * [2] Status code * [2] Association ID (AID) * [tlv] Supported rates * [tlv] Extended Supported Rates (802.11g) * [tlv] EDCA Parameter Set (802.11e) * [tlv] HT Capabilities (802.11n) * [tlv] HT Operation (802.11n) */ void ieee80211_recv_assoc_resp(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, int reassoc) { XYLog("%s reassoc=%d\n", __FUNCTION__, reassoc); struct _ifnet *ifp = &ic->ic_if; const struct ieee80211_frame *wh; const u_int8_t *frm, *efrm; const u_int8_t *rates, *xrates, *edcaie, *wmmie, *htcaps, *htop; const uint8_t *vhtcap; const uint8_t *vhtopmode; const uint8_t *hecap; const uint8_t *heopmode; u_int16_t capinfo, status, associd; u_int8_t rate; if (ic->ic_opmode != IEEE80211_M_STA || ic->ic_state != IEEE80211_S_ASSOC) { ic->ic_stats.is_rx_mgtdiscard++; return; } /* make sure all mandatory fixed fields are present */ if (mbuf_len(m) < sizeof(*wh) + 6) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; efrm = mtod(m, u_int8_t *) + mbuf_len(m); capinfo = LE_READ_2(frm); frm += 2; status = LE_READ_2(frm); frm += 2; ic->ic_assoc_status = status; if (status == IEEE80211_STATUS_SUCCESS) { if (ic->ic_event_handler) { (*ic->ic_event_handler)(ic, IEEE80211_EVT_STA_ASSOC_DONE, NULL); } } if (status != IEEE80211_STATUS_SUCCESS) { if (ifp->if_flags & IFF_DEBUG) XYLog("%s: %sassociation failed (status %d)" " for %s\n", ifp->if_xname, reassoc ? "re" : "", status, ether_sprintf((u_int8_t *)wh->i_addr3)); if (ni != ic->ic_bss) ni->ni_fails++; ic->ic_stats.is_rx_auth_fail++; return; } associd = LE_READ_2(frm); frm += 2; rates = xrates = edcaie = wmmie = htcaps = htop = vhtcap = vhtopmode = hecap = heopmode = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) { ic->ic_stats.is_rx_elem_toosmall++; break; } switch (frm[0]) { case IEEE80211_ELEMID_RATES: rates = frm; break; case IEEE80211_ELEMID_XRATES: xrates = frm; break; case IEEE80211_ELEMID_EDCAPARMS: edcaie = frm; break; case IEEE80211_ELEMID_HTCAPS: htcaps = frm; break; case IEEE80211_ELEMID_HTOP: htop = frm; break; case IEEE80211_ELEMID_VHT_CAP: vhtcap = frm; break; case IEEE80211_ELEMID_VHT_OPMODE: vhtopmode = frm; break; case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) { ic->ic_stats.is_rx_elem_toosmall++; break; } if (memcmp(frm + 2, MICROSOFT_OUI, 3) == 0) { if (frm[1] >= 5 && frm[5] == 2 && frm[6] == 1) wmmie = frm; } break; case IEEE80211_ELEMID_EXTENSION: switch (frm[2]) { case IEEE80211_ELEMID_EXT_HE_MU_EDCA: break; case IEEE80211_ELEMID_EXT_HE_CAPABILITY: hecap = frm; break; case IEEE80211_ELEMID_EXT_HE_OPERATION: heopmode = frm; break; case IEEE80211_ELEMID_EXT_UORA: break; case IEEE80211_ELEMID_EXT_MAX_CHANNEL_SWITCH_TIME: break; case IEEE80211_ELEMID_EXT_MULTIPLE_BSSID_CONFIGURATION: break; case IEEE80211_ELEMID_EXT_HE_SPR: break; case IEEE80211_ELEMID_EXT_HE_6GHZ_CAPA: break; } break; } frm += 2 + frm[1]; } /* supported rates element is mandatory */ if (rates == NULL || rates[1] > IEEE80211_RATE_MAXSIZE) { DPRINTF(("invalid supported rates element\n")); return; } rate = ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (rate & IEEE80211_RATE_BASIC) { DPRINTF(("rate mismatch for %s\n", ether_sprintf((u_int8_t *)wh->i_addr2))); ic->ic_stats.is_rx_assoc_norate++; return; } ni->ni_capinfo = capinfo; ni->ni_associd = associd; if (edcaie != NULL || wmmie != NULL) { /* force update of EDCA parameters */ ic->ic_edca_updtcount = -1; if ((edcaie != NULL && ieee80211_parse_edca_params(ic, edcaie) == 0) || (wmmie != NULL && ieee80211_parse_wmm_params(ic, wmmie) == 0)) ni->ni_flags |= IEEE80211_NODE_QOS; else /* for Reassociation */ ni->ni_flags &= ~IEEE80211_NODE_QOS; } if (htcaps) ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]); if (htop) ieee80211_setup_htop(ni, htop + 2, htop[1], 0); if (vhtcap != NULL && vhtopmode != NULL) { ieee80211_setup_vhtcaps(ic, ni, vhtcap); ieee80211_setup_vhtopmode(ni, vhtopmode); } if (hecap != NULL && heopmode != NULL) { ieee80211_setup_hecaps(ni, hecap + 3, hecap[1] - 1); ieee80211_setup_heop(ni, heopmode + 3, heopmode[1] - 1); } ieee80211_ht_negotiate(ic, ni); ieee80211_vht_negotiate(ic, ni); if (hecap != NULL && heopmode != NULL) { ieee80211_he_negotiate(ic, ni); } /* Hop into 11n/11ac/11ax mode after associating to an HT AP in a legacy mode. */ if (ni->ni_flags & IEEE80211_NODE_HE) ieee80211_setmode(ic, IEEE80211_MODE_11AX); else if (ni->ni_flags & IEEE80211_NODE_VHT) ieee80211_setmode(ic, IEEE80211_MODE_11AC); else if (ni->ni_flags & IEEE80211_NODE_HT) ieee80211_setmode(ic, IEEE80211_MODE_11N); else ieee80211_setmode(ic, ieee80211_chan2mode(ic, ni->ni_chan)); ieee80211_sta_set_rx_nss(ic, ni); /* * Reset the erp state (mostly the slot time) now that * our operating mode has been nailed down. */ ieee80211_reset_erp(ic); /* * Configure state now that we are associated. */ if (ic->ic_curmode == IEEE80211_MODE_11A || (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) ic->ic_flags |= IEEE80211_F_SHPREAMBLE; else ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; ieee80211_set_shortslottime(ic, ic->ic_curmode == IEEE80211_MODE_11A || (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)); /* * Honor ERP protection. */ if ((ic->ic_curmode == IEEE80211_MODE_11G || (ic->ic_curmode == IEEE80211_MODE_11N && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))) && (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION)) ic->ic_flags |= IEEE80211_F_USEPROT; else ic->ic_flags &= ~IEEE80211_F_USEPROT; /* * If not an RSNA, mark the port as valid, otherwise wait for * 802.1X authentication and 4-way handshake to complete.. */ if (ic->ic_flags & IEEE80211_F_RSNON) { /* XXX ic->ic_mgt_timer = 5; */ ni->ni_rsn_supp_state = RSNA_SUPP_PTKSTART; } else if (ic->ic_flags & IEEE80211_F_WEPON) ni->ni_flags |= IEEE80211_NODE_TXRXPROT; ieee80211_new_state(ic, IEEE80211_S_RUN, IEEE80211_FC0_SUBTYPE_ASSOC_RESP); } /*- * Deauthentication frame format: * [2] Reason code */ void ieee80211_recv_deauth(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); const struct ieee80211_frame *wh; const u_int8_t *frm; u_int16_t reason; /* make sure all mandatory fixed fields are present */ if (mbuf_len(m) < sizeof(*wh) + 2) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; reason = LE_READ_2(frm); XYLog("Deauth received, reason %d\n", reason); ic->ic_deauth_reason = reason; if (ic->ic_event_handler) { (*ic->ic_event_handler)(ic, IEEE80211_EVT_STA_DEAUTH, NULL); } ic->ic_stats.is_rx_deauth++; switch (ic->ic_opmode) { case IEEE80211_M_STA: { int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) && ic->ic_state == IEEE80211_S_RUN); int roamscan = bgscan && (ic->ic_flags & IEEE80211_F_DISABLE_BG_AUTO_CONNECT) == 0; int stay_auth = ((ic->ic_userflags & IEEE80211_F_STAYAUTH) && ic->ic_state >= IEEE80211_S_AUTH); if (!(roamscan || stay_auth)) ieee80211_new_state(ic, IEEE80211_S_AUTH, IEEE80211_FC0_SUBTYPE_DEAUTH); } break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_HOSTAP: if (ni != ic->ic_bss) { int stay_auth = ((ic->ic_userflags & IEEE80211_F_STAYAUTH) && (ni->ni_state == IEEE80211_STA_AUTH || ni->ni_state == IEEE80211_STA_ASSOC)); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: station %s deauthenticated " "by peer (reason %d)\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr), reason); if (!stay_auth) ieee80211_node_leave(ic, ni); } break; #endif default: break; } } /*- * Disassociation frame format: * [2] Reason code */ void ieee80211_recv_disassoc(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); const struct ieee80211_frame *wh; const u_int8_t *frm; u_int16_t reason; /* make sure all mandatory fixed fields are present */ if (mbuf_len(m) < sizeof(*wh) + 2) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; reason = LE_READ_2(frm); XYLog("Disassoc received, reason %d\n", reason); ic->ic_stats.is_rx_disassoc++; switch (ic->ic_opmode) { case IEEE80211_M_STA: { int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) && ic->ic_state == IEEE80211_S_RUN); int roamscan = bgscan && (ic->ic_flags & IEEE80211_F_DISABLE_BG_AUTO_CONNECT) == 0; if (!roamscan) /* ignore disassoc during bgscan */ ieee80211_new_state(ic, IEEE80211_S_ASSOC, IEEE80211_FC0_SUBTYPE_DISASSOC); } break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_HOSTAP: if (ni != ic->ic_bss) { if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: station %s disassociated " "by peer (reason %d)\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr), reason); ieee80211_node_leave(ic, ni); } break; #endif default: break; } } /*- * ADDBA Request frame format: * [1] Category * [1] Action * [1] Dialog Token * [2] Block Ack Parameter Set * [2] Block Ack Timeout Value * [2] Block Ack Starting Sequence Control */ void ieee80211_recv_addba_req(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { const struct ieee80211_frame *wh; const u_int8_t *frm; struct ieee80211_rx_ba *ba; u_int16_t params, ssn, bufsz, timeout; u_int8_t token, tid; int err = 0; /* Ignore if we are not ready to receive data frames. */ if (ic->ic_state != IEEE80211_S_RUN || ((ic->ic_flags & IEEE80211_F_RSNON) && !ni->ni_port_valid)) return; if (!(ni->ni_flags & IEEE80211_NODE_HT)) { DPRINTF(("received ADDBA req from non-HT STA %s\n", ether_sprintf(ni->ni_macaddr))); return; } if (mbuf_len(m) < sizeof(*wh) + 9) { DPRINTF(("frame too short\n")); return; } /* MLME-ADDBA.indication */ wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; token = frm[2]; params = LE_READ_2(&frm[3]); tid = ((params & IEEE80211_ADDBA_TID_MASK) >> IEEE80211_ADDBA_TID_SHIFT); bufsz = (params & IEEE80211_ADDBA_BUFSZ_MASK) >> IEEE80211_ADDBA_BUFSZ_SHIFT; timeout = LE_READ_2(&frm[5]); ssn = LE_READ_2(&frm[7]) >> 4; ba = &ni->ni_rx_ba[tid]; /* The driver is still processing an ADDBA request for this tid. */ if (ba->ba_state == IEEE80211_BA_REQUESTED) return; /* If we are in the process of roaming between APs, ignore. */ if ((ic->ic_flags & IEEE80211_F_BGSCAN) && ((ic->ic_flags & IEEE80211_F_DISABLE_BG_AUTO_CONNECT) == 0) && (ic->ic_xflags & IEEE80211_F_TX_MGMT_ONLY)) return; /* check if we already have a Block Ack agreement for this RA/TID */ if (ba->ba_state == IEEE80211_BA_AGREED) { /* XXX should we update the timeout value? */ /* reset Block Ack inactivity timer */ if (ba->ba_timeout_val != 0) timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); /* check if it's a Protected Block Ack agreement */ if (!(ni->ni_flags & IEEE80211_NODE_MFP) || !(ni->ni_rsncaps & IEEE80211_RSNCAP_PBAC)) return; /* not a PBAC, ignore */ /* PBAC: treat the ADDBA Request like a BlockAckReq */ if (SEQ_LT(ba->ba_winstart, ssn)) { struct mbuf_list ml = MBUF_LIST_INITIALIZER(); ieee80211_ba_move_window(ic, ni, tid, ssn, &ml); if_input(&ic->ic_if, &ml); } return; } /* if PBAC required but RA does not support it, refuse request */ if ((ic->ic_flags & IEEE80211_F_PBAR) && (!(ni->ni_flags & IEEE80211_NODE_MFP) || !(ni->ni_rsncaps & IEEE80211_RSNCAP_PBAC))) goto refuse; /* * If the TID for which the Block Ack agreement is requested is * configured with a no-ACK policy, refuse the agreement. */ if (ic->ic_tid_noack & (1 << tid)) goto refuse; /* check that we support the requested Block Ack Policy */ if (!(ic->ic_htcaps & IEEE80211_HTCAP_DELAYEDBA) && !(params & IEEE80211_ADDBA_BA_POLICY)) goto refuse; /* setup Block Ack agreement */ ba->ba_state = IEEE80211_BA_REQUESTED; ba->ba_timeout_val = timeout * IEEE80211_DUR_TU; ba->ba_ni = ni; ba->ba_token = token; timeout_set(&ba->ba_to, ieee80211_rx_ba_timeout, ba); timeout_set(&ba->ba_gap_to, ieee80211_input_ba_gap_timeout, ba); ba->ba_gapwait = 0; ba->ba_winsize = bufsz; if (ba->ba_winsize == 0 || ba->ba_winsize > IEEE80211_BA_MAX_WINSZ) ba->ba_winsize = IEEE80211_BA_MAX_WINSZ; ba->ba_params = (params & IEEE80211_ADDBA_BA_POLICY); ba->ba_params |= ((ba->ba_winsize << IEEE80211_ADDBA_BUFSZ_SHIFT) | (tid << IEEE80211_ADDBA_TID_SHIFT)); if (ic->ic_caps & IEEE80211_C_AMSDU_IN_AMPDU) { ba->ba_params |= IEEE80211_ADDBA_AMSDU; } ba->ba_winstart = ssn; ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; /* allocate and setup our reordering buffer */ ba->ba_buf = (struct ieee80211_ba_buf*)malloc(IEEE80211_BA_MAX_WINSZ * sizeof(struct ieee80211_ba_buf), 0, 0); if (ba->ba_buf == NULL) goto refuse; ba->ba_head = 0; /* notify drivers of this new Block Ack agreement */ if (ic->ic_ampdu_rx_start != NULL) err = ic->ic_ampdu_rx_start(ic, ni, tid); if (err == EBUSY) { /* driver will accept or refuse agreement when done */ return; } else if (err) { /* driver failed to setup, rollback */ ieee80211_addba_req_refuse(ic, ni, tid); } else ieee80211_addba_req_accept(ic, ni, tid); return; refuse: /* MLME-ADDBA.response */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, IEEE80211_ACTION_ADDBA_RESP, IEEE80211_STATUS_REFUSED << 16 | token << 8 | tid); } void ieee80211_addba_req_accept(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; ba->ba_state = IEEE80211_BA_AGREED; ic->ic_stats.is_ht_rx_ba_agreements++; /* start Block Ack inactivity timer */ if (ba->ba_timeout_val != 0) timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); /* MLME-ADDBA.response */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, IEEE80211_ACTION_ADDBA_RESP, IEEE80211_STATUS_SUCCESS << 16 | ba->ba_token << 8 | tid); } void ieee80211_addba_req_refuse(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; free(ba->ba_buf); ba->ba_buf = NULL; ba->ba_state = IEEE80211_BA_INIT; /* MLME-ADDBA.response */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, IEEE80211_ACTION_ADDBA_RESP, IEEE80211_STATUS_REFUSED << 16 | ba->ba_token << 8 | tid); } /*- * ADDBA Response frame format: * [1] Category * [1] Action * [1] Dialog Token * [2] Status Code * [2] Block Ack Parameter Set * [2] Block Ack Timeout Value */ void ieee80211_recv_addba_resp(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { const struct ieee80211_frame *wh; const u_int8_t *frm; struct ieee80211_tx_ba *ba; u_int16_t status, params, bufsz, timeout; u_int8_t token, tid; int err = 0; if (mbuf_len(m) < sizeof(*wh) + 9) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; token = frm[2]; status = LE_READ_2(&frm[3]); params = LE_READ_2(&frm[5]); tid = (params >> 2) & 0xf; bufsz = (params >> 6) & 0x3ff; timeout = LE_READ_2(&frm[7]); DPRINTF(("received ADDBA resp from %s, TID %d, status %d\n", ether_sprintf(ni->ni_macaddr), tid, status)); /* * Ignore if no ADDBA request has been sent for this RA/TID or * if we already have a Block Ack agreement. */ ba = &ni->ni_tx_ba[tid]; if (ba->ba_state != IEEE80211_BA_REQUESTED) { DPRINTF(("no matching ADDBA req found\n")); return; } if (token != ba->ba_token) { DPRINTF(("ignoring ADDBA resp from %s: token %x!=%x\n", ether_sprintf(ni->ni_macaddr), token, ba->ba_token)); return; } /* we got an ADDBA Response matching our request, stop timeout */ timeout_del(&ba->ba_to); if (status != IEEE80211_STATUS_SUCCESS) { if (ni->ni_addba_req_intval[tid] < IEEE80211_ADDBA_REQ_INTVAL_MAX) ni->ni_addba_req_intval[tid]++; ieee80211_addba_resp_refuse(ic, ni, tid, status); /* * In case the peer believes there is an existing * block ack agreement with us, try to delete it. */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, IEEE80211_ACTION_DELBA, IEEE80211_REASON_SETUP_REQUIRED << 16 | 1 << 8 | tid); return; } /* notify drivers of this new Block Ack agreement */ if (ic->ic_ampdu_tx_start != NULL) err = ic->ic_ampdu_tx_start(ic, ni, tid); if (err == EBUSY) { /* driver will accept or refuse agreement when done */ return; } else if (err) { /* driver failed to setup, rollback */ ieee80211_addba_resp_refuse(ic, ni, tid, IEEE80211_STATUS_UNSPECIFIED); } else ieee80211_addba_resp_accept(ic, ni, tid); } void ieee80211_addba_resp_accept(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; /* MLME-ADDBA.confirm(Success) */ ba->ba_state = IEEE80211_BA_AGREED; ic->ic_stats.is_ht_tx_ba_agreements++; ni->ni_qos_txseqs[tid] = ba->ba_winstart; /* Reset ADDBA request interval. */ ni->ni_addba_req_intval[tid] = 1; /* start Block Ack inactivity timeout */ if (ba->ba_timeout_val != 0) timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); } void ieee80211_addba_resp_refuse(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid, uint16_t status) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; /* MLME-ADDBA.confirm(Failure) */ ba->ba_state = IEEE80211_BA_INIT; } /*- * DELBA frame format: * [1] Category * [1] Action * [2] DELBA Parameter Set * [2] Reason Code */ void ieee80211_recv_delba(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { const struct ieee80211_frame *wh; const u_int8_t *frm; u_int16_t params, reason; u_int8_t tid; int i; if (mbuf_len(m) < sizeof(*wh) + 6) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; params = LE_READ_2(&frm[2]); reason = LE_READ_2(&frm[4]); tid = params >> 12; XYLog("received DELBA from %s, TID %d, reason %d\n", ether_sprintf(ni->ni_macaddr), tid, reason); if (params & IEEE80211_DELBA_INITIATOR) { /* MLME-DELBA.indication(Originator) */ struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; if (ba->ba_state != IEEE80211_BA_AGREED) { DPRINTF(("no matching Block Ack agreement\n")); return; } /* notify drivers of the end of the Block Ack agreement */ if (ic->ic_ampdu_rx_stop != NULL) ic->ic_ampdu_rx_stop(ic, ni, tid); ba->ba_state = IEEE80211_BA_INIT; /* stop Block Ack inactivity timer */ timeout_del(&ba->ba_to); timeout_del(&ba->ba_gap_to); ba->ba_gapwait = 0; if (ba->ba_buf != NULL) { /* free all MSDUs stored in reordering buffer */ for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++) mbuf_freem(ba->ba_buf[i].m); /* free reordering buffer */ free(ba->ba_buf); ba->ba_buf = NULL; } } else { /* MLME-DELBA.indication(Recipient) */ struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; if (ba->ba_state != IEEE80211_BA_AGREED) { DPRINTF(("no matching Block Ack agreement\n")); return; } /* notify drivers of the end of the Block Ack agreement */ if (ic->ic_ampdu_tx_stop != NULL) ic->ic_ampdu_tx_stop(ic, ni, tid); ba->ba_state = IEEE80211_BA_INIT; /* stop Block Ack inactivity timer */ timeout_del(&ba->ba_to); } } /*- * SA Query Request frame format: * [1] Category * [1] Action * [2] Transaction Identifier */ void ieee80211_recv_sa_query_req(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { const struct ieee80211_frame *wh; const u_int8_t *frm; if (ic->ic_opmode != IEEE80211_M_STA || !(ni->ni_flags & IEEE80211_NODE_MFP)) { DPRINTF(("unexpected SA Query req from %s\n", ether_sprintf(ni->ni_macaddr))); return; } if (mbuf_len(m) < sizeof(*wh) + 4) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; /* MLME-SAQuery.indication */ /* save Transaction Identifier for SA Query Response */ ni->ni_sa_query_trid = LE_READ_2(&frm[2]); /* MLME-SAQuery.response */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_SA_QUERY, IEEE80211_ACTION_SA_QUERY_RESP, 0); } #ifndef IEEE80211_STA_ONLY /*- * SA Query Response frame format: * [1] Category * [1] Action * [2] Transaction Identifier */ void ieee80211_recv_sa_query_resp(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { const struct ieee80211_frame *wh; const u_int8_t *frm; /* ignore if we're not engaged in an SA Query with that STA */ if (!(ni->ni_flags & IEEE80211_NODE_SA_QUERY)) { DPRINTF(("unexpected SA Query resp from %s\n", ether_sprintf(ni->ni_macaddr))); return; } if (mbuf_len(m) < sizeof(*wh) + 4) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; /* check that Transaction Identifier matches */ if (ni->ni_sa_query_trid != LE_READ_2(&frm[2])) { DPRINTF(("transaction identifier does not match\n")); return; } /* MLME-SAQuery.confirm */ timeout_del(&ni->ni_sa_query_to); ni->ni_flags &= ~IEEE80211_NODE_SA_QUERY; } #endif /*- * Action frame format: * [1] Category * [1] Action */ void ieee80211_recv_action(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { const struct ieee80211_frame *wh; const u_int8_t *frm; if (mbuf_len(m) < sizeof(*wh) + 2) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame *); frm = (const u_int8_t *)&wh[1]; switch (frm[0]) { case IEEE80211_CATEG_BA: switch (frm[1]) { case IEEE80211_ACTION_ADDBA_REQ: ieee80211_recv_addba_req(ic, m, ni); break; case IEEE80211_ACTION_ADDBA_RESP: ieee80211_recv_addba_resp(ic, m, ni); break; case IEEE80211_ACTION_DELBA: ieee80211_recv_delba(ic, m, ni); break; } break; case IEEE80211_CATEG_SA_QUERY: switch (frm[1]) { case IEEE80211_ACTION_SA_QUERY_REQ: ieee80211_recv_sa_query_req(ic, m, ni); break; #ifndef IEEE80211_STA_ONLY case IEEE80211_ACTION_SA_QUERY_RESP: ieee80211_recv_sa_query_resp(ic, m, ni); break; #endif } break; default: DPRINTF(("action frame category %d not handled\n", frm[0])); break; } } void ieee80211_recv_mgmt(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi, int subtype) { switch (subtype) { case IEEE80211_FC0_SUBTYPE_BEACON: ieee80211_recv_probe_resp(ic, m, ni, rxi, 0); break; case IEEE80211_FC0_SUBTYPE_PROBE_RESP: ieee80211_recv_probe_resp(ic, m, ni, rxi, 1); break; #ifndef IEEE80211_STA_ONLY case IEEE80211_FC0_SUBTYPE_PROBE_REQ: ieee80211_recv_probe_req(ic, m, ni, rxi); break; #endif case IEEE80211_FC0_SUBTYPE_AUTH: ieee80211_recv_auth(ic, m, ni, rxi); break; #ifndef IEEE80211_STA_ONLY case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: ieee80211_recv_assoc_req(ic, m, ni, rxi, 0); break; case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: ieee80211_recv_assoc_req(ic, m, ni, rxi, 1); break; #endif case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: ieee80211_recv_assoc_resp(ic, m, ni, 0); break; case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: ieee80211_recv_assoc_resp(ic, m, ni, 1); break; case IEEE80211_FC0_SUBTYPE_DEAUTH: ieee80211_recv_deauth(ic, m, ni); break; case IEEE80211_FC0_SUBTYPE_DISASSOC: ieee80211_recv_disassoc(ic, m, ni); break; case IEEE80211_FC0_SUBTYPE_ACTION: ieee80211_recv_action(ic, m, ni); break; default: DPRINTF(("mgmt frame with subtype 0x%x not handled\n", subtype)); ic->ic_stats.is_rx_badsubtype++; break; } } #ifndef IEEE80211_STA_ONLY /* * Process an incoming PS-Poll control frame (see 11.2). */ void ieee80211_recv_pspoll(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { struct _ifnet *ifp = &ic->ic_if; struct ieee80211_frame_pspoll *psp; struct ieee80211_frame *wh; u_int16_t aid; if (ic->ic_opmode != IEEE80211_M_HOSTAP || !(ic->ic_caps & IEEE80211_C_APPMGT) || ni->ni_state != IEEE80211_STA_ASSOC) return; if (mbuf_len(m) < sizeof(*psp)) { DPRINTF(("frame too short, len %u\n", mbuf_len(m))); ic->ic_stats.is_rx_tooshort++; return; } psp = mtod(m, struct ieee80211_frame_pspoll *); if (!IEEE80211_ADDR_EQ(psp->i_bssid, ic->ic_bss->ni_bssid)) { DPRINTF(("discard pspoll frame to BSS %s\n", ether_sprintf(psp->i_bssid))); ic->ic_stats.is_rx_wrongbss++; return; } aid = letoh16(*(u_int16_t *)psp->i_aid); if (aid != ni->ni_associd) { DPRINTF(("invalid pspoll aid %x from %s\n", aid, ether_sprintf(psp->i_ta))); return; } /* take the first queued frame and put it out.. */ m = mq_dequeue(&ni->ni_savedq); if (m == NULL) return; if (mq_empty(&ni->ni_savedq)) { /* last queued frame, turn off the TIM bit */ (*ic->ic_set_tim)(ic, ni->ni_associd, 0); } else { /* more queued frames, set the more data bit */ wh = mtod(m, struct ieee80211_frame *); wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; } mq_enqueue(&ic->ic_pwrsaveq, m); ifp->if_start(ifp); } #endif /* IEEE80211_STA_ONLY */ /* * Process an incoming BlockAckReq control frame (see 7.2.1.7). */ void ieee80211_recv_bar(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { const struct ieee80211_frame_min *wh; const u_int8_t *frm; u_int16_t ctl, ssn; u_int8_t tid, ntids; if (!(ni->ni_flags & IEEE80211_NODE_HT)) { DPRINTF(("received BlockAckReq from non-HT STA %s\n", ether_sprintf(ni->ni_macaddr))); return; } if (mbuf_len(m) < sizeof(*wh) + 4) { DPRINTF(("frame too short\n")); return; } wh = mtod(m, struct ieee80211_frame_min *); frm = (const u_int8_t *)&wh[1]; /* read BlockAckReq Control field */ ctl = LE_READ_2(&frm[0]); tid = ctl >> 12; /* determine BlockAckReq frame variant */ if (ctl & IEEE80211_BA_MULTI_TID) { /* Multi-TID BlockAckReq variant (PSMP only) */ ntids = tid + 1; if (mbuf_len(m) < sizeof(*wh) + 2 + 4 * ntids) { DPRINTF(("MTBAR frame too short\n")); return; } frm += 2; /* skip BlockAckReq Control field */ while (ntids-- > 0) { /* read MTBAR Information field */ tid = LE_READ_2(&frm[0]) >> 12; ssn = LE_READ_2(&frm[2]) >> 4; ieee80211_bar_tid(ic, ni, tid, ssn); frm += 4; } } else { /* Basic or Compressed BlockAckReq variants */ ssn = LE_READ_2(&frm[2]) >> 4; ieee80211_bar_tid(ic, ni, tid, ssn); } } /* * Process a BlockAckReq for a specific TID (see 9.10.7.6.3). * This is the common back-end for all BlockAckReq frame variants. */ void ieee80211_bar_tid(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t tid, u_int16_t ssn) { struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; /* check if we have a Block Ack agreement for RA/TID */ if (ba->ba_state != IEEE80211_BA_AGREED) { /* XXX not sure in PBAC case */ /* send a DELBA with reason code UNKNOWN-BA */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, IEEE80211_ACTION_DELBA, IEEE80211_REASON_SETUP_REQUIRED << 16 | tid); return; } /* check if it is a Protected Block Ack agreement */ if ((ni->ni_flags & IEEE80211_NODE_MFP) && (ni->ni_rsncaps & IEEE80211_RSNCAP_PBAC)) { /* ADDBA Requests must be used in PBAC case */ if (SEQ_LT(ssn, ba->ba_winstart) || SEQ_LT(ba->ba_winend, ssn)) ic->ic_stats.is_pbac_errs++; return; /* PBAC, do not move window */ } /* reset Block Ack inactivity timer */ if (ba->ba_timeout_val != 0) timeout_add_usec(&ba->ba_to, ba->ba_timeout_val); if (SEQ_LT(ba->ba_winstart, ssn)) { struct mbuf_list ml = MBUF_LIST_INITIALIZER(); ieee80211_ba_move_window(ic, ni, tid, ssn, &ml); if_input(&ic->ic_if, &ml); } } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_ioctl.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. */ /* $OpenBSD: ieee80211_ioctl.c,v 1.75 2019/09/02 12:54:21 stsp Exp $ */ /* $NetBSD: ieee80211_ioctl.c,v 1.15 2004/05/06 02:58:16 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * IEEE 802.11 ioctl support */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include void ieee80211_node2req(struct ieee80211com *, const struct ieee80211_node *, struct ieee80211_nodereq *); void ieee80211_req2node(struct ieee80211com *, const struct ieee80211_nodereq *, struct ieee80211_node *); static int kernel_copyin(const user_addr_t dest, void *src, size_t len) { memcpy(src, (void *)dest, len); return 0; } static int kernel_copyout(void *src, const user_addr_t dest, size_t len) { memcpy((void *)dest, src, len); return 0; } void ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni, struct ieee80211_nodereq *nr) { uint8_t rssi; memset(nr, 0, sizeof(*nr)); strlcpy(nr->nr_ifname, ic->ic_if.if_xname, sizeof(nr->nr_ifname)); /* Node address and name information */ IEEE80211_ADDR_COPY(nr->nr_macaddr, ni->ni_macaddr); IEEE80211_ADDR_COPY(nr->nr_bssid, ni->ni_bssid); nr->nr_nwid_len = ni->ni_esslen; bcopy(ni->ni_essid, nr->nr_nwid, IEEE80211_NWID_LEN); /* Channel and rates */ nr->nr_channel = ieee80211_chan2ieee(ic, ni->ni_chan); if (ni->ni_chan != IEEE80211_CHAN_ANYC) nr->nr_chan_flags = ni->ni_chan->ic_flags; if (ic->ic_curmode != IEEE80211_MODE_11N) nr->nr_chan_flags &= ~IEEE80211_CHAN_HT; nr->nr_nrates = ni->ni_rates.rs_nrates; bcopy(ni->ni_rates.rs_rates, nr->nr_rates, IEEE80211_RATE_MAXSIZE); /* Node status information */ rssi = (*ic->ic_node_getrssi)(ic, ni); if (ic->ic_max_rssi) { /* Driver reports RSSI relative to ic_max_rssi. */ nr->nr_rssi = rssi; } else { /* * Driver reports RSSI value in dBm. * Convert from unsigned to signed. * Some drivers report a negative value, some don't. * Reasonable range is -20dBm to -80dBm. */ nr->nr_rssi = (rssi < 128) ? -rssi : rssi; } nr->nr_max_rssi = ic->ic_max_rssi; bcopy(ni->ni_tstamp, nr->nr_tstamp, sizeof(nr->nr_tstamp)); nr->nr_intval = ni->ni_intval; nr->nr_capinfo = ni->ni_capinfo; nr->nr_erp = ni->ni_erp; nr->nr_pwrsave = ni->ni_pwrsave; nr->nr_associd = ni->ni_associd; nr->nr_txseq = ni->ni_txseq; nr->nr_rxseq = ni->ni_rxseq; nr->nr_fails = ni->ni_fails; nr->nr_assoc_fail = ni->ni_assoc_fail; /* flag values are the same */ nr->nr_inact = ni->ni_inact; nr->nr_txrate = ni->ni_txrate; nr->nr_state = ni->ni_state; /* RSN */ nr->nr_rsnciphers = ni->ni_rsnciphers; nr->nr_rsnakms = 0; nr->nr_rsnprotos = 0; if (ni->ni_supported_rsnprotos & IEEE80211_PROTO_RSN) nr->nr_rsnprotos |= IEEE80211_WPA_PROTO_WPA2; if (ni->ni_supported_rsnprotos & IEEE80211_PROTO_WPA) nr->nr_rsnprotos |= IEEE80211_WPA_PROTO_WPA1; if (ni->ni_supported_rsnakms & IEEE80211_AKM_8021X) nr->nr_rsnakms |= IEEE80211_WPA_AKM_8021X; if (ni->ni_supported_rsnakms & IEEE80211_AKM_PSK) nr->nr_rsnakms |= IEEE80211_WPA_AKM_PSK; if (ni->ni_supported_rsnakms & IEEE80211_AKM_SHA256_8021X) nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_8021X; if (ni->ni_supported_rsnakms & IEEE80211_AKM_SHA256_PSK) nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_PSK; /* Node flags */ nr->nr_flags = 0; if (bcmp(nr->nr_macaddr, nr->nr_bssid, IEEE80211_ADDR_LEN) == 0) nr->nr_flags |= IEEE80211_NODEREQ_AP; if (ni == ic->ic_bss) nr->nr_flags |= IEEE80211_NODEREQ_AP_BSS; /* HT */ nr->nr_htcaps = ni->ni_htcaps; memcpy(nr->nr_rxmcs, ni->ni_rxmcs, sizeof(nr->nr_rxmcs)); nr->nr_max_rxrate = ni->ni_max_rxrate; nr->nr_tx_mcs_set = ni->ni_tx_mcs_set; if (ni->ni_flags & IEEE80211_NODE_HT) nr->nr_flags |= IEEE80211_NODEREQ_HT; /* HT / VHT */ nr->nr_txmcs = ni->ni_txmcs; /* VHT */ nr->nr_vht_ss = ni->ni_vht_ss; if (ni->ni_flags & IEEE80211_NODE_VHT) nr->nr_flags |= IEEE80211_NODEREQ_VHT; } void ieee80211_req2node(struct ieee80211com *ic, const struct ieee80211_nodereq *nr, struct ieee80211_node *ni) { /* Node address and name information */ IEEE80211_ADDR_COPY(ni->ni_macaddr, nr->nr_macaddr); IEEE80211_ADDR_COPY(ni->ni_bssid, nr->nr_bssid); ni->ni_esslen = nr->nr_nwid_len; bcopy(nr->nr_nwid, ni->ni_essid, IEEE80211_NWID_LEN); /* Rates */ ni->ni_rates.rs_nrates = nr->nr_nrates; bcopy(nr->nr_rates, ni->ni_rates.rs_rates, IEEE80211_RATE_MAXSIZE); /* Node information */ ni->ni_intval = nr->nr_intval; ni->ni_capinfo = nr->nr_capinfo; ni->ni_erp = nr->nr_erp; ni->ni_pwrsave = nr->nr_pwrsave; ni->ni_associd = nr->nr_associd; ni->ni_txseq = nr->nr_txseq; ni->ni_rxseq = nr->nr_rxseq; ni->ni_fails = nr->nr_fails; ni->ni_inact = nr->nr_inact; ni->ni_txrate = nr->nr_txrate; ni->ni_state = nr->nr_state; } void ieee80211_disable_wep(struct ieee80211com *ic) { struct ieee80211_key *k; int i; for (i = 0; i < IEEE80211_WEP_NKID; i++) { k = &ic->ic_nw_keys[i]; if (k->k_cipher != IEEE80211_CIPHER_NONE) (*ic->ic_delete_key)(ic, NULL, k); memset(k, 0, sizeof(*k)); } ic->ic_flags &= ~IEEE80211_F_WEPON; } void ieee80211_disable_rsn(struct ieee80211com *ic) { ic->ic_flags &= ~(IEEE80211_F_PSK | IEEE80211_F_RSNON); memset(ic->ic_psk, 0, sizeof(ic->ic_psk)); ic->ic_rsnprotos = 0; ic->ic_rsnakms = 0; ic->ic_rsngroupcipher = (enum ieee80211_cipher)0; ic->ic_rsnciphers = 0; } /* Keep in sync with ieee80211_node.c:ieee80211_ess_setnwkeys() */ int ieee80211_ioctl_setnwkeys(struct ieee80211com *ic, const struct ieee80211_nwkey *nwkey) { XYLog("%s\n", __FUNCTION__); struct ieee80211_key *k; int error, i; if (!(ic->ic_caps & IEEE80211_C_WEP)) return ENODEV; if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) { if (!(ic->ic_flags & IEEE80211_F_WEPON)) return 0; ic->ic_flags &= ~IEEE80211_F_WEPON; return ENETRESET; } if (nwkey->i_defkid < 1 || nwkey->i_defkid > IEEE80211_WEP_NKID) return EINVAL; for (i = 0; i < IEEE80211_WEP_NKID; i++) { if (nwkey->i_key[i].i_keylen == 0 || nwkey->i_key[i].i_keydat == NULL) continue; /* entry not set */ if (nwkey->i_key[i].i_keylen > IEEE80211_KEYBUF_SIZE) return EINVAL; /* map wep key to ieee80211_key */ k = &ic->ic_nw_keys[i]; if (k->k_cipher != IEEE80211_CIPHER_NONE) (*ic->ic_delete_key)(ic, NULL, k); memset(k, 0, sizeof(*k)); if (nwkey->i_key[i].i_keylen <= 5) k->k_cipher = IEEE80211_CIPHER_WEP40; else k->k_cipher = IEEE80211_CIPHER_WEP104; k->k_len = ieee80211_cipher_keylen(k->k_cipher); k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX; error = kernel_copyin((const user_addr_t)nwkey->i_key[i].i_keydat, k->k_key, k->k_len); if (error != 0) return error; error = (*ic->ic_set_key)(ic, NULL, k); switch (error) { case 0: case EBUSY: break; default: return error; } } ic->ic_def_txkey = nwkey->i_defkid - 1; ic->ic_flags |= IEEE80211_F_WEPON; if (ic->ic_flags & IEEE80211_F_RSNON) ieee80211_disable_rsn(ic); return ENETRESET; } static int ieee80211_ioctl_getnwkeys(struct ieee80211com *ic, struct ieee80211_nwkey *nwkey) { int i; if (ic->ic_flags & IEEE80211_F_WEPON) nwkey->i_wepon = IEEE80211_NWKEY_WEP; else nwkey->i_wepon = IEEE80211_NWKEY_OPEN; nwkey->i_defkid = ic->ic_wep_txkey + 1; for (i = 0; i < IEEE80211_WEP_NKID; i++) { if (nwkey->i_key[i].i_keydat == NULL) continue; /* do not show any keys to userland */ return EPERM; } return 0; } /* Keep in sync with ieee80211_node.c:ieee80211_ess_setwpaparms() */ int ieee80211_ioctl_setwpaparms(struct ieee80211com *ic, const struct ieee80211_wpaparams *wpa) { if (!(ic->ic_caps & IEEE80211_C_RSN)) return ENODEV; if (!wpa->i_enabled) { if (!(ic->ic_flags & IEEE80211_F_RSNON)) return 0; ic->ic_flags &= ~IEEE80211_F_RSNON; ic->ic_rsnprotos = 0; ic->ic_rsnakms = 0; ic->ic_rsngroupcipher = (enum ieee80211_cipher)0; ic->ic_rsnciphers = 0; return ENETRESET; } ic->ic_rsnprotos = 0; if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA1) ic->ic_rsnprotos |= IEEE80211_PROTO_WPA; if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA2) ic->ic_rsnprotos |= IEEE80211_PROTO_RSN; if (ic->ic_rsnprotos == 0) /* set to default (RSN) */ ic->ic_rsnprotos = IEEE80211_PROTO_RSN; ic->ic_rsnakms = 0; if (wpa->i_akms & IEEE80211_WPA_AKM_PSK) ic->ic_rsnakms |= IEEE80211_AKM_PSK; if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_PSK) ic->ic_rsnakms |= IEEE80211_AKM_SHA256_PSK; if (wpa->i_akms & IEEE80211_WPA_AKM_8021X) ic->ic_rsnakms |= IEEE80211_AKM_8021X; if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_8021X) ic->ic_rsnakms |= IEEE80211_AKM_SHA256_8021X; if (ic->ic_rsnakms == 0) /* set to default (PSK) */ ic->ic_rsnakms = IEEE80211_AKM_PSK; if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP40) ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP40; else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_TKIP) ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP; else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_CCMP) ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP; else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP104) ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP104; else { /* set to default */ if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA) ic->ic_rsngroupcipher = IEEE80211_CIPHER_TKIP; else ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP; } ic->ic_rsnciphers = 0; if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_TKIP) ic->ic_rsnciphers |= IEEE80211_CIPHER_TKIP; if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_CCMP) ic->ic_rsnciphers |= IEEE80211_CIPHER_CCMP; if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_USEGROUP) ic->ic_rsnciphers = IEEE80211_CIPHER_USEGROUP; if (ic->ic_rsnciphers == 0) { /* set to default (CCMP, TKIP if WPA1) */ ic->ic_rsnciphers = IEEE80211_CIPHER_CCMP; if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA) ic->ic_rsnciphers |= IEEE80211_CIPHER_TKIP; } ic->ic_flags |= IEEE80211_F_RSNON; return ENETRESET; } int ieee80211_ioctl_getwpaparms(struct ieee80211com *ic, struct ieee80211_wpaparams *wpa) { wpa->i_enabled = (ic->ic_flags & IEEE80211_F_RSNON) ? 1 : 0; wpa->i_protos = 0; if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA) wpa->i_protos |= IEEE80211_WPA_PROTO_WPA1; if (ic->ic_rsnprotos & IEEE80211_PROTO_RSN) wpa->i_protos |= IEEE80211_WPA_PROTO_WPA2; wpa->i_akms = 0; if (ic->ic_rsnakms & IEEE80211_AKM_PSK) wpa->i_akms |= IEEE80211_WPA_AKM_PSK; if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_PSK) wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_PSK; if (ic->ic_rsnakms & IEEE80211_AKM_8021X) wpa->i_akms |= IEEE80211_WPA_AKM_8021X; if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_8021X) wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_8021X; if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP40) wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP40; else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_TKIP) wpa->i_groupcipher = IEEE80211_WPA_CIPHER_TKIP; else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_CCMP) wpa->i_groupcipher = IEEE80211_WPA_CIPHER_CCMP; else if (ic->ic_rsngroupcipher == IEEE80211_CIPHER_WEP104) wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP104; else wpa->i_groupcipher = IEEE80211_WPA_CIPHER_NONE; wpa->i_ciphers = 0; if (ic->ic_rsnciphers & IEEE80211_CIPHER_TKIP) wpa->i_ciphers |= IEEE80211_WPA_CIPHER_TKIP; if (ic->ic_rsnciphers & IEEE80211_CIPHER_CCMP) wpa->i_ciphers |= IEEE80211_WPA_CIPHER_CCMP; if (ic->ic_rsnciphers & IEEE80211_CIPHER_USEGROUP) wpa->i_ciphers = IEEE80211_WPA_CIPHER_USEGROUP; return 0; } void ieee80211_ess_getwpaparms(struct ieee80211_ess *ess, struct ieee80211_wpaparams *wpa) { wpa->i_enabled = (ess->flags & IEEE80211_F_RSNON) ? 1 : 0; wpa->i_protos = 0; if (ess->rsnprotos & IEEE80211_PROTO_WPA) wpa->i_protos |= IEEE80211_WPA_PROTO_WPA1; if (ess->rsnprotos & IEEE80211_PROTO_RSN) wpa->i_protos |= IEEE80211_WPA_PROTO_WPA2; wpa->i_akms = 0; if (ess->rsnakms & IEEE80211_AKM_PSK) wpa->i_akms |= IEEE80211_WPA_AKM_PSK; if (ess->rsnakms & IEEE80211_AKM_SHA256_PSK) wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_PSK; if (ess->rsnakms & IEEE80211_AKM_8021X) wpa->i_akms |= IEEE80211_WPA_AKM_8021X; if (ess->rsnakms & IEEE80211_AKM_SHA256_8021X) wpa->i_akms |= IEEE80211_WPA_AKM_SHA256_8021X; if (ess->rsngroupcipher == IEEE80211_CIPHER_WEP40) wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP40; else if (ess->rsngroupcipher == IEEE80211_CIPHER_TKIP) wpa->i_groupcipher = IEEE80211_WPA_CIPHER_TKIP; else if (ess->rsngroupcipher == IEEE80211_CIPHER_CCMP) wpa->i_groupcipher = IEEE80211_WPA_CIPHER_CCMP; else if (ess->rsngroupcipher == IEEE80211_CIPHER_WEP104) wpa->i_groupcipher = IEEE80211_WPA_CIPHER_WEP104; else wpa->i_groupcipher = IEEE80211_WPA_CIPHER_NONE; wpa->i_ciphers = 0; if (ess->rsnciphers & IEEE80211_CIPHER_TKIP) wpa->i_ciphers |= IEEE80211_WPA_CIPHER_TKIP; if (ess->rsnciphers & IEEE80211_CIPHER_CCMP) wpa->i_ciphers |= IEEE80211_WPA_CIPHER_CCMP; if (ess->rsnciphers & IEEE80211_CIPHER_USEGROUP) wpa->i_ciphers = IEEE80211_WPA_CIPHER_USEGROUP; } int ieee80211_ioctl(struct _ifnet *ifp, u_long cmd, caddr_t data) { struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ifreq *ifr = (struct ifreq *)data; int i, error = 0; size_t len; struct ieee80211_nwid nwid; struct ieee80211_join join; struct ieee80211_joinreq_all *ja; struct ieee80211_ess *ess; struct ieee80211_wpapsk *psk; struct ieee80211_keyavail *ka; struct ieee80211_keyrun *kr; struct ieee80211_power *power; struct ieee80211_bssid *bssid; struct ieee80211chanreq *chanreq; struct ieee80211_channel *chan; struct ieee80211_txpower *txpower; static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct ieee80211_nodereq *nr, nrbuf; struct ieee80211_nodereq_all *na; struct ieee80211_node *ni; u_int32_t flags; switch (cmd) { // case SIOCSIFMEDIA: // case SIOCGIFMEDIA: // error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); // break; case SIOCS80211NWID: // if ((error = suser(curproc)) != 0) // break; if ((error = kernel_copyin((const user_addr_t)ifr->ifr_data, &nwid, sizeof(nwid))) != 0) break; if (nwid.i_len > IEEE80211_NWID_LEN) { error = EINVAL; break; } memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); ic->ic_des_esslen = nwid.i_len; memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len); if (ic->ic_des_esslen > 0) { /* 'nwid' disables auto-join magic */ ic->ic_flags &= ~IEEE80211_F_AUTO_JOIN; } else if (!TAILQ_EMPTY(&ic->ic_ess)) { /* '-nwid' re-enables auto-join */ ic->ic_flags |= IEEE80211_F_AUTO_JOIN; } /* disable WPA/WEP */ ieee80211_disable_rsn(ic); ieee80211_disable_wep(ic); error = ENETRESET; break; case SIOCG80211NWID: memset(&nwid, 0, sizeof(nwid)); switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: nwid.i_len = ic->ic_des_esslen; memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len); break; default: nwid.i_len = ic->ic_bss->ni_esslen; memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len); break; } error = kernel_copyout((void *)&nwid, (user_addr_t)ifr->ifr_data, sizeof(nwid)); break; case SIOCS80211JOIN: // if ((error = suser(curproc)) != 0) // break; if ((error = kernel_copyin((user_addr_t)ifr->ifr_data, &join, sizeof(join))) != 0) break; if (join.i_len > IEEE80211_NWID_LEN) { error = EINVAL; break; } if (join.i_flags & IEEE80211_JOIN_DEL) { int update_ic = 0; if (ic->ic_des_esslen == join.i_len && memcmp(join.i_nwid, ic->ic_des_essid, join.i_len) == 0) update_ic = 1; if (join.i_flags & IEEE80211_JOIN_DEL_ALL && ieee80211_get_ess(ic, (const char *)ic->ic_des_essid, ic->ic_des_esslen) != NULL) update_ic = 1; ieee80211_del_ess(ic, (char *)join.i_nwid, join.i_len, join.i_flags & IEEE80211_JOIN_DEL_ALL ? 1 : 0); if (update_ic == 1) { /* Unconfigure this essid */ memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); ic->ic_des_esslen = 0; /* disable WPA/WEP */ ieee80211_disable_rsn(ic); ieee80211_disable_wep(ic); error = ENETRESET; } } else { if (ic->ic_des_esslen == join.i_len && memcmp(join.i_nwid, ic->ic_des_essid, join.i_len) == 0) { struct ieee80211_node *ni; ieee80211_deselect_ess(ic); ni = ieee80211_find_node(ic, ic->ic_bss->ni_bssid); if (ni != NULL) ieee80211_free_node(ic, ni); error = ENETRESET; } /* save nwid for auto-join */ if (ieee80211_add_ess(ic, &join) == 0) ic->ic_flags |= IEEE80211_F_AUTO_JOIN; } break; case SIOCG80211JOIN: memset(&join, 0, sizeof(join)); error = ENOENT; if (ic->ic_bss == NULL) break; TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) { if (memcmp(ess->essid, ic->ic_bss->ni_essid, IEEE80211_NWID_LEN) == 0) { join.i_len = ic->ic_bss->ni_esslen; memcpy(join.i_nwid, ic->ic_bss->ni_essid, join.i_len); if (ic->ic_flags & IEEE80211_F_AUTO_JOIN) join.i_flags = IEEE80211_JOIN_FOUND; error = kernel_copyout(&join, (user_addr_t)ifr->ifr_data, sizeof(join)); break; } } break; case SIOCG80211JOINALL: ja = (struct ieee80211_joinreq_all *)data; ja->ja_nodes = len = 0; TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) { if (len + sizeof(ja->ja_node[0]) >= ja->ja_size) { error = E2BIG; break; } memset(&join, 0, sizeof(join)); join.i_len = ess->esslen; memcpy(&join.i_nwid, ess->essid, join.i_len); if (ess->flags & IEEE80211_F_RSNON) join.i_flags |= IEEE80211_JOIN_WPA; if (ess->flags & IEEE80211_F_PSK) join.i_flags |= IEEE80211_JOIN_WPAPSK; if (ess->flags & IEEE80211_JOIN_8021X) join.i_flags |= IEEE80211_JOIN_8021X; if (ess->flags & IEEE80211_F_WEPON) join.i_flags |= IEEE80211_JOIN_NWKEY; if (ess->flags & IEEE80211_JOIN_ANY) join.i_flags |= IEEE80211_JOIN_ANY; ieee80211_ess_getwpaparms(ess, &join.i_wpaparams); error = kernel_copyout(&join, (user_addr_t)&ja->ja_node[ja->ja_nodes], sizeof(ja->ja_node[0])); if (error) break; len += sizeof(join); ja->ja_nodes++; } break; case SIOCS80211NWKEY: // if ((error = suser(curproc)) != 0) // break; error = ieee80211_ioctl_setnwkeys(ic, (const struct ieee80211_nwkey *)data); break; case SIOCG80211NWKEY: error = ieee80211_ioctl_getnwkeys(ic, (struct ieee80211_nwkey *)data); break; case SIOCS80211WPAPARMS: // if ((error = suser(curproc)) != 0) // break; error = ieee80211_ioctl_setwpaparms(ic, (const struct ieee80211_wpaparams *)data); break; case SIOCG80211WPAPARMS: error = ieee80211_ioctl_getwpaparms(ic, (struct ieee80211_wpaparams *)data); break; case SIOCS80211WPAPSK: // if ((error = suser(curproc)) != 0) // break; psk = (struct ieee80211_wpapsk *)data; if (psk->i_enabled) { ic->ic_flags |= IEEE80211_F_PSK; memcpy(ic->ic_psk, psk->i_psk, sizeof(ic->ic_psk)); if (ic->ic_flags & IEEE80211_F_WEPON) ieee80211_disable_wep(ic); } else { ic->ic_flags &= ~IEEE80211_F_PSK; memset(ic->ic_psk, 0, sizeof(ic->ic_psk)); } error = ENETRESET; break; case SIOCG80211WPAPSK: psk = (struct ieee80211_wpapsk *)data; if (ic->ic_flags & IEEE80211_F_PSK) { /* do not show any keys to userland */ psk->i_enabled = 2; memset(psk->i_psk, 0, sizeof(psk->i_psk)); break; /* return ok but w/o key */ } else psk->i_enabled = 0; break; case SIOCS80211KEYAVAIL: // if ((error = suser(curproc)) != 0) // break; ka = (struct ieee80211_keyavail *)data; (void)ieee80211_pmksa_add(ic, IEEE80211_AKM_8021X, ka->i_macaddr, ka->i_key, ka->i_lifetime); break; case SIOCS80211KEYRUN: // if ((error = suser(curproc)) != 0) // break; kr = (struct ieee80211_keyrun *)data; error = ieee80211_keyrun(ic, kr->i_macaddr); if (error == 0 && (ic->ic_flags & IEEE80211_F_WEPON)) ieee80211_disable_wep(ic); break; case SIOCS80211POWER: // if ((error = suser(curproc)) != 0) // break; power = (struct ieee80211_power *)data; ic->ic_lintval = power->i_maxsleep; if (power->i_enabled != 0) { if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) error = EINVAL; else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) { ic->ic_flags |= IEEE80211_F_PMGTON; error = ENETRESET; } } else { if (ic->ic_flags & IEEE80211_F_PMGTON) { ic->ic_flags &= ~IEEE80211_F_PMGTON; error = ENETRESET; } } break; case SIOCG80211POWER: power = (struct ieee80211_power *)data; power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0; power->i_maxsleep = ic->ic_lintval; break; case SIOCS80211BSSID: // if ((error = suser(curproc)) != 0) // break; bssid = (struct ieee80211_bssid *)data; if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr)) ic->ic_flags &= ~IEEE80211_F_DESBSSID; else { ic->ic_flags |= IEEE80211_F_DESBSSID; IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid); } #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) break; #endif switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: error = ENETRESET; break; default: if ((ic->ic_flags & IEEE80211_F_DESBSSID) && !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ic->ic_bss->ni_bssid)) error = ENETRESET; break; } break; case SIOCG80211BSSID: bssid = (struct ieee80211_bssid *)data; switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) IEEE80211_ADDR_COPY(bssid->i_bssid, ic->ic_myaddr); else #endif if (ic->ic_flags & IEEE80211_F_DESBSSID) IEEE80211_ADDR_COPY(bssid->i_bssid, ic->ic_des_bssid); else memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN); break; default: IEEE80211_ADDR_COPY(bssid->i_bssid, ic->ic_bss->ni_bssid); break; } break; case SIOCS80211CHANNEL: // if ((error = suser(curproc)) != 0) // break; chanreq = (struct ieee80211chanreq *)data; if (chanreq->i_channel == IEEE80211_CHAN_ANY) ic->ic_des_chan = IEEE80211_CHAN_ANYC; else if (chanreq->i_channel > IEEE80211_CHAN_MAX || isclr(ic->ic_chan_active, chanreq->i_channel)) { error = EINVAL; break; } else ic->ic_ibss_chan = ic->ic_des_chan = &ic->ic_channels[chanreq->i_channel]; switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: error = ENETRESET; break; default: if (ic->ic_opmode == IEEE80211_M_STA) { if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && ic->ic_bss->ni_chan != ic->ic_des_chan) error = ENETRESET; } else { if (ic->ic_bss->ni_chan != ic->ic_ibss_chan) error = ENETRESET; } break; } break; case SIOCG80211CHANNEL: chanreq = (struct ieee80211chanreq *)data; switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: if (ic->ic_opmode == IEEE80211_M_STA) chan = ic->ic_des_chan; else chan = ic->ic_ibss_chan; break; default: chan = ic->ic_bss->ni_chan; break; } chanreq->i_channel = ieee80211_chan2ieee(ic, chan); break; case SIOCG80211ALLCHANS: error = kernel_copyout(ic->ic_channels, (user_addr_t)((struct ieee80211_chanreq_all *)data)->i_chans, sizeof(ic->ic_channels)); break; #if 0 case SIOCG80211ZSTATS: #endif case SIOCG80211STATS: ifr = (struct ifreq *)data; error = kernel_copyout(&ic->ic_stats, (user_addr_t)ifr->ifr_data, sizeof(ic->ic_stats)); #if 0 if (cmd == SIOCG80211ZSTATS) memset(&ic->ic_stats, 0, sizeof(ic->ic_stats)); #endif break; case SIOCS80211TXPOWER: // if ((error = suser(curproc)) != 0) // break; txpower = (struct ieee80211_txpower *)data; if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) { error = EINVAL; break; } if (!(IEEE80211_TXPOWER_MIN <= txpower->i_val && txpower->i_val <= IEEE80211_TXPOWER_MAX)) { error = EINVAL; break; } ic->ic_txpower = txpower->i_val; error = ENETRESET; break; case SIOCG80211TXPOWER: txpower = (struct ieee80211_txpower *)data; if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) error = EINVAL; else txpower->i_val = ic->ic_txpower; break; case SIOCSIFMTU: // ifr = (struct ifreq *)data; // if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu && // ifr->ifr_mtu <= IEEE80211_MTU_MAX)) // error = EINVAL; // else // ifp->if_mtu = ifr->ifr_mtu; break; case SIOCS80211SCAN: /* Disabled. SIOCG80211ALLNODES is enough. */ break; case SIOCG80211NODE: nr = (struct ieee80211_nodereq *)data; if (ic->ic_bss && IEEE80211_ADDR_EQ(nr->nr_macaddr, ic->ic_bss->ni_macaddr)) ni = ic->ic_bss; else ni = ieee80211_find_node(ic, nr->nr_macaddr); if (ni == NULL) { error = ENOENT; break; } ieee80211_node2req(ic, ni, nr); break; case SIOCS80211NODE: // if ((error = suser(curproc)) != 0) // break; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) { error = EINVAL; break; } #endif nr = (struct ieee80211_nodereq *)data; ni = ieee80211_find_node(ic, nr->nr_macaddr); if (ni == NULL) ni = ieee80211_alloc_node(ic, nr->nr_macaddr); if (ni == NULL) { error = ENOENT; break; } if (nr->nr_flags & IEEE80211_NODEREQ_COPY) ieee80211_req2node(ic, nr, ni); break; #ifndef IEEE80211_STA_ONLY case SIOCS80211DELNODE: // if ((error = suser(curproc)) != 0) // break; nr = (struct ieee80211_nodereq *)data; ni = ieee80211_find_node(ic, nr->nr_macaddr); if (ni == NULL) error = ENOENT; else if (ni == ic->ic_bss) error = EPERM; else { if (ni->ni_state == IEEE80211_STA_COLLECT) break; /* Disassociate station. */ if (ni->ni_state == IEEE80211_STA_ASSOC) IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_ASSOC_LEAVE); /* Deauth station. */ if (ni->ni_state >= IEEE80211_STA_AUTH) IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); ieee80211_node_leave(ic, ni); } break; #endif case SIOCG80211ALLNODES: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) { error = ENETDOWN; break; } na = (struct ieee80211_nodereq_all *)data; na->na_nodes = i = 0; ni = RB_MIN(ieee80211_tree, &ic->ic_tree); while (ni && na->na_size >= i + sizeof(struct ieee80211_nodereq)) { ieee80211_node2req(ic, ni, &nrbuf); error = kernel_copyout(&nrbuf, (user_addr_t)(caddr_t)na->na_node + i, sizeof(struct ieee80211_nodereq)); if (error) break; i += sizeof(struct ieee80211_nodereq); na->na_nodes++; ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); } break; case SIOCG80211FLAGS: flags = ic->ic_userflags; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_HOSTAP) #endif flags &= ~IEEE80211_F_HOSTAPMASK; ifr->ifr_flags = flags; break; case SIOCS80211FLAGS: // if ((error = suser(curproc)) != 0) // break; flags = ifr->ifr_flags; if ( #ifndef IEEE80211_STA_ONLY ic->ic_opmode != IEEE80211_M_HOSTAP && #endif (flags & IEEE80211_F_HOSTAPMASK)) { error = EINVAL; break; } ic->ic_userflags = flags; error = ENETRESET; break; // case SIOCADDMULTI: // case SIOCDELMULTI: // error = (cmd == SIOCADDMULTI) ? // ether_addmulti(ifr, &ic->ic_ac) : // ether_delmulti(ifr, &ic->ic_ac); // if (error == ENETRESET) // error = 0; // break; default: // error = ether_ioctl(ifp, &ic->ic_ac, cmd, data); break; } return error; } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_ioctl.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_ioctl.h,v 1.41 2020/10/06 07:23:15 gerhard Exp $ */ /* $NetBSD: ieee80211_ioctl.h,v 1.7 2004/04/30 22:51:04 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_ioctl.h,v 1.5 2004/03/30 22:57:57 sam Exp $ */ #ifndef _NET80211_IEEE80211_IOCTL_H_ #define _NET80211_IEEE80211_IOCTL_H_ /* * IEEE 802.11 ioctls. */ /* per-interface statistics */ struct ieee80211_stats { u_int32_t is_rx_badversion; /* rx frame with bad version */ u_int32_t is_rx_tooshort; /* rx frame too short */ u_int32_t is_rx_wrongbss; /* rx from wrong bssid */ u_int32_t is_rx_dup; /* rx discard 'cuz dup */ u_int32_t is_rx_wrongdir; /* rx w/ wrong direction */ u_int32_t is_rx_mcastecho; /* rx discard 'cuz mcast echo */ u_int32_t is_rx_notassoc; /* rx discard 'cuz sta !assoc */ u_int32_t is_rx_nowep; /* rx w/ wep but wep !config */ u_int32_t is_rx_unencrypted; /* rx w/o wep but wep config */ u_int32_t is_rx_wepfail; /* rx wep processing failed */ u_int32_t is_rx_decap; /* rx decapsulation failed */ u_int32_t is_rx_mgtdiscard; /* rx discard mgt frames */ u_int32_t is_rx_ctl; /* rx discard ctrl frames */ u_int32_t is_rx_rstoobig; /* rx rate set truncated */ u_int32_t is_rx_elem_missing; /* rx required element missing*/ u_int32_t is_rx_elem_toobig; /* rx element too big */ u_int32_t is_rx_elem_toosmall; /* rx element too small */ u_int32_t is_rx_badchan; /* rx frame w/ invalid chan */ u_int32_t is_rx_chanmismatch; /* rx frame chan mismatch */ u_int32_t is_rx_nodealloc; /* rx frame dropped */ u_int32_t is_rx_ssidmismatch; /* rx frame ssid mismatch */ u_int32_t is_rx_auth_unsupported; /* rx w/ unsupported auth alg */ u_int32_t is_rx_auth_fail; /* rx sta auth failure */ u_int32_t is_rx_assoc_bss; /* rx assoc from wrong bssid */ u_int32_t is_rx_assoc_notauth; /* rx assoc w/o auth */ u_int32_t is_rx_assoc_capmismatch;/* rx assoc w/ cap mismatch */ u_int32_t is_rx_assoc_norate; /* rx assoc w/ no rate match */ u_int32_t is_rx_deauth; /* rx deauthentication */ u_int32_t is_rx_disassoc; /* rx disassociation */ u_int32_t is_rx_badsubtype; /* rx frame w/ unknown subtype*/ u_int32_t is_rx_nombuf; /* rx failed for lack of mbuf */ u_int32_t is_rx_decryptcrc; /* rx decrypt failed on crc */ u_int32_t is_rx_ahdemo_mgt; /* rx discard ahdemo mgt frame*/ u_int32_t is_rx_bad_auth; /* rx bad auth request */ u_int32_t is_tx_nombuf; /* tx failed for lack of mbuf */ u_int32_t is_tx_nonode; /* tx failed for no node */ u_int32_t is_tx_unknownmgt; /* tx of unknown mgt frame */ u_int32_t is_scan_active; /* active scans started */ u_int32_t is_scan_passive; /* passive scans started */ u_int32_t is_node_timeout; /* nodes timed out inactivity */ u_int32_t is_crypto_nomem; /* no memory for crypto ctx */ u_int32_t is_rx_assoc_badrsnie; /* rx assoc w/ bad RSN IE */ u_int32_t is_rx_unauth; /* rx port not valid */ u_int32_t is_tx_noauth; /* tx port not valid */ u_int32_t is_rx_eapol_key; /* rx eapol-key frames */ u_int32_t is_rx_eapol_replay; /* rx replayed eapol frames */ u_int32_t is_rx_eapol_badmic; /* rx eapol frames w/ bad mic */ u_int32_t is_rx_remmicfail; /* rx tkip remote mic fails */ u_int32_t is_rx_locmicfail; /* rx tkip local mic fails */ u_int32_t is_tkip_replays; u_int32_t is_tkip_icv_errs; u_int32_t is_ccmp_replays; u_int32_t is_ccmp_dec_errs; u_int32_t is_cmac_replays; u_int32_t is_cmac_icv_errs; u_int32_t is_pbac_errs; u_int32_t is_ht_nego_no_mandatory_mcs; u_int32_t is_ht_nego_no_basic_mcs; u_int32_t is_ht_nego_bad_crypto; u_int32_t is_ht_prot_change; u_int32_t is_ht_rx_ba_agreements; u_int32_t is_ht_tx_ba_agreements; u_int32_t is_ht_rx_frame_below_ba_winstart; u_int32_t is_ht_rx_frame_above_ba_winend; u_int32_t is_ht_rx_ba_window_slide; u_int32_t is_ht_rx_ba_window_jump; u_int32_t is_ht_rx_ba_no_buf; u_int32_t is_ht_rx_ba_frame_lost; u_int32_t is_ht_rx_ba_window_gap_timeout; u_int32_t is_ht_rx_ba_timeout; u_int32_t is_ht_tx_ba_timeout; u_int32_t is_vht_nego_no_mandatory_mcs; u_int32_t is_vht_nego_bad_crypto; }; #define SIOCG80211STATS _IOWR('i', 242, struct ifreq) /* network identifier (ESSID), nwid is pointed at by ifr.ifr_data */ struct ieee80211_nwid { u_int8_t i_len; u_int8_t i_nwid[IEEE80211_NWID_LEN]; }; #define SIOCS80211NWID _IOWR('i', 230, struct ifreq) #define SIOCG80211NWID _IOWR('i', 231, struct ifreq) /* network key (WEP), the first member must be matched with struct ifreq */ struct ieee80211_nwkey { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ int i_wepon; /* wep enabled flag */ int i_defkid; /* default encrypt key id */ struct { int i_keylen; u_int8_t *i_keydat; } i_key[IEEE80211_WEP_NKID]; }; #define IEEE80211_NWKEY_OPEN 0 /* No privacy */ #define IEEE80211_NWKEY_WEP 1 /* WEP enabled */ #define IEEE80211_NWKEY_EAP 2 /* EAP enabled */ #define IEEE80211_NWKEY_PERSIST 0x100 /* designate persist keyset */ #define SIOCS80211NWKEY _IOW('i', 232, struct ieee80211_nwkey) #define SIOCG80211NWKEY _IOWR('i', 233, struct ieee80211_nwkey) /* power management parameters */ struct ieee80211_power { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ int i_enabled; /* 1 == on, 0 == off */ int i_maxsleep; /* max sleep in ms */ }; #define SIOCS80211POWER _IOW('i', 234, struct ieee80211_power) #define SIOCG80211POWER _IOWR('i', 235, struct ieee80211_power) #define IEEE80211_AUTH_NONE 0 #define IEEE80211_AUTH_OPEN 1 #define IEEE80211_AUTH_SHARED 2 /* channel request */ struct ieee80211chanreq { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ u_int16_t i_channel; }; #ifndef _KERNEL /* * Channels are specified by frequency and attributes. */ struct ieee80211_channel { u_int16_t ic_freq; /* setting in MHz */ u_int16_t ic_flags; /* see below */ }; /* * Channel attributes (XXX must keep in sync with radiotap flags). */ #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel */ #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_XR 0x1000 /* Extended range OFDM channel */ #define IEEE80211_CHAN_HT 0x2000 /* 11n/HT channel */ #endif /* !_KERNEL */ struct ieee80211_chanreq_all { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ struct ieee80211_channel *i_chans; }; #ifndef IEEE80211_CHAN_ANY #define IEEE80211_CHAN_ANY 0xffff #endif #define SIOCS80211CHANNEL _IOW('i', 238, struct ieee80211chanreq) #define SIOCG80211CHANNEL _IOWR('i', 239, struct ieee80211chanreq) #define SIOCG80211ALLCHANS _IOWR('i', 215, struct ieee80211_chanreq_all) /* BSS identifier */ struct ieee80211_bssid { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ u_int8_t i_bssid[IEEE80211_ADDR_LEN]; }; #define SIOCS80211BSSID _IOW('i', 240, struct ieee80211_bssid) #define SIOCG80211BSSID _IOWR('i', 241, struct ieee80211_bssid) /* transmit power */ struct ieee80211_txpower { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ int i_mode; /* auto, manual */ int16_t i_val; /* dBm */ }; #define SIOCS80211TXPOWER _IOW('i', 243, struct ieee80211_txpower) #define SIOCG80211TXPOWER _IOWR('i', 244, struct ieee80211_txpower) #define IEEE80211_TXPOWER_MODE_FIXED 0 /* fixed tx power value */ #define IEEE80211_TXPOWER_MODE_AUTO 1 /* auto level control */ struct ieee80211_wpapsk { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ int i_enabled; u_int8_t i_psk[32]; }; #define SIOCS80211WPAPSK _IOW('i', 245, struct ieee80211_wpapsk) #define SIOCG80211WPAPSK _IOWR('i', 246, struct ieee80211_wpapsk) #define IEEE80211_WPA_PROTO_WPA1 0x01 #define IEEE80211_WPA_PROTO_WPA2 0x02 #define IEEE80211_WPA_CIPHER_NONE 0x00 #define IEEE80211_WPA_CIPHER_USEGROUP 0x01 #define IEEE80211_WPA_CIPHER_WEP40 0x02 #define IEEE80211_WPA_CIPHER_TKIP 0x04 #define IEEE80211_WPA_CIPHER_CCMP 0x08 #define IEEE80211_WPA_CIPHER_WEP104 0x10 #define IEEE80211_WPA_CIPHER_BIP 0x20 #define IEEE80211_WPA_AKM_PSK 0x01 #define IEEE80211_WPA_AKM_8021X 0x02 #define IEEE80211_WPA_AKM_SHA256_PSK 0x04 #define IEEE80211_WPA_AKM_SHA256_8021X 0x08 struct ieee80211_wpaparams { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ int i_enabled; u_int i_protos; u_int i_akms; u_int i_ciphers; u_int i_groupcipher; }; #define SIOCS80211WPAPARMS _IOW('i', 247, struct ieee80211_wpaparams) #define SIOCG80211WPAPARMS _IOWR('i', 248, struct ieee80211_wpaparams) struct ieee80211_keyavail { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ u_int8_t i_macaddr[IEEE80211_ADDR_LEN]; u_int8_t i_key[32]; u_int32_t i_lifetime; }; struct ieee80211_keyrun { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ u_int8_t i_macaddr[IEEE80211_ADDR_LEN]; }; #define SIOCS80211KEYAVAIL _IOW('i', 251, struct ieee80211_keyavail) #define SIOCS80211KEYRUN _IOW('i', 252, struct ieee80211_keyrun) /* scan request (will block) */ #define IEEE80211_SCAN_TIMEOUT 30 /* timeout in seconds */ #define SIOCS80211SCAN _IOW('i', 210, struct ifreq) #define SIOCG80211JOINALL _IOWR('i', 218, struct ieee80211_joinreq_all) #define SIOCS80211JOIN _IOWR('i', 255, struct ifreq) #define SIOCG80211JOIN _IOWR('i', 0, struct ifreq) /* join is pointed at by ifr.ifr_data */ struct ieee80211_join { u_int8_t i_len; /* length of i_nwid */ u_int8_t i_nwid[IEEE80211_NWID_LEN]; u_int32_t i_flags; struct ieee80211_wpaparams i_wpaparams; struct ieee80211_wpapsk i_wpapsk; struct ieee80211_nwkey i_nwkey; }; struct ieee80211_joinreq_all { char ja_ifname[IFNAMSIZ]; int ja_nodes; /* returned count */ size_t ja_size; /* size of node buffer */ struct ieee80211_join *ja_node; /* allocated node buffer */ }; #define IEEE80211_JOIN_SHOW 0x01 #define IEEE80211_JOIN_FOUND 0x02 #define IEEE80211_JOIN_DEL 0x04 #define IEEE80211_JOIN_NWKEY 0x08 #define IEEE80211_JOIN_WPA 0x10 #define IEEE80211_JOIN_WPAPSK 0x20 #define IEEE80211_JOIN_8021X 0x40 #define IEEE80211_JOIN_ANY 0x80 #define IEEE80211_JOIN_DEL_ALL 0x100 /* node and requests */ struct ieee80211_nodereq { char nr_ifname[IFNAMSIZ]; /* e.g. "ath0" */ /* Node address and name information */ u_int8_t nr_macaddr[IEEE80211_ADDR_LEN]; /* node lladdr */ u_int8_t nr_bssid[IEEE80211_ADDR_LEN]; /* bssid */ u_int8_t nr_nwid_len; /* ESSID length */ u_int8_t nr_nwid[IEEE80211_NWID_LEN]; /* ESSID */ /* Channel and rates */ u_int16_t nr_channel; /* last channel */ u_int32_t nr_chan_flags; /* channel flags */ u_int8_t nr_nrates; /* rate count */ u_int8_t nr_rates[IEEE80211_RATE_MAXSIZE]; /* rate set */ /* Node status information */ int8_t nr_rssi; /* received signal strength */ int8_t nr_max_rssi; /* maximum rssi */ u_int8_t nr_tstamp[8]; /* from last received beacon */ u_int16_t nr_intval; /* beacon interval */ u_int16_t nr_capinfo; /* capabilities */ u_int8_t nr_erp; /* 11g only */ u_int8_t nr_pwrsave; /* power saving mode */ u_int16_t nr_associd; /* assoc response */ u_int16_t nr_txseq; /* seq to be transmitted */ u_int16_t nr_rxseq; /* seq previous received */ u_int32_t nr_fails; /* failure count to associate */ u_int32_t nr_inact; /* inactivity mark count */ u_int8_t nr_txrate; /* index to nr_rates[] */ u_int16_t nr_state; /* node state in the cache */ /* RSN */ u_int nr_rsnprotos; u_int nr_rsnciphers; u_int nr_rsnakms; /* Node flags */ u_int8_t nr_flags; /* HT */ uint16_t nr_htcaps; uint8_t nr_rxmcs[howmany(80,NBBY)]; uint16_t nr_max_rxrate; /* in Mb/s, 0 <= rate <= 1023 */ uint8_t nr_tx_mcs_set; /* HT / VHT */ uint8_t nr_txmcs; /* VHT */ uint8_t nr_vht_ss; u_int32_t nr_assoc_fail; /* association failure reasons */ }; #define IEEE80211_NODEREQ_STATE(_s) (1 << _s) #define IEEE80211_NODEREQ_STATE_BITS \ "\20\01CACHE\02BSS\03AUTH\04ASSOC\05COLLECT" #define IEEE80211_NODEREQ_RSSI(_nr) \ ((u_int)(((float)(_nr)->nr_rssi / (_nr)->nr_max_rssi) * 100)) #define IEEE80211_NODEREQ_STA 0x00 /* station */ #define IEEE80211_NODEREQ_AP 0x01 /* access point */ #define IEEE80211_NODEREQ_AP_BSS 0x02 /* current bss access point */ #define IEEE80211_NODEREQ_COPY 0x04 /* add node with flags */ #define IEEE80211_NODEREQ_HT 0x08 /* HT negotiated */ #define IEEE80211_NODEREQ_VHT 0x10 /* VHT negotiated */ #define SIOCG80211NODE _IOWR('i', 211, struct ieee80211_nodereq) #define SIOCS80211NODE _IOW('i', 212, struct ieee80211_nodereq) #define SIOCS80211DELNODE _IOW('i', 213, struct ieee80211_nodereq) #define IEEE80211_NODEREQ_ASSOCFAIL_CHAN 0x01 #define IEEE80211_NODEREQ_ASSOCFAIL_IBSS 0x02 #define IEEE80211_NODEREQ_ASSOCFAIL_PRIVACY 0x04 #define IEEE80211_NODEREQ_ASSOCFAIL_BASIC_RATE 0x08 #define IEEE80211_NODEREQ_ASSOCFAIL_ESSID 0x10 #define IEEE80211_NODEREQ_ASSOCFAIL_BSSID 0x20 #define IEEE80211_NODEREQ_ASSOCFAIL_WPA_PROTO 0x40 #define IEEE80211_NODEREQ_ASSOCFAIL_WPA_KEY 0x80 #define IEEE80211_NODEREQ_ASSOCFAIL_BITS \ "\20\1!CHAN\2!IBSS\3!PRIVACY\4!BASICRATE\5!ESSID\6!BSSID\7!WPAPROTO" \ "\10!WPAKEY" /* get the entire node cache */ struct ieee80211_nodereq_all { char na_ifname[IFNAMSIZ]; /* e.g. "ath0" */ int na_nodes; /* returned count */ size_t na_size; /* size of node buffer */ struct ieee80211_nodereq *na_node; /* allocated node buffer */ /* Match nodes by flag */ u_int8_t na_flags; /* IEEE80211_NODEREQ_* */ }; #define SIOCG80211ALLNODES _IOWR('i', 214, struct ieee80211_nodereq_all) /* net80211 specific interface flags */ #define IEEE80211_F_HIDENWID 0x00000001 /* CONF: hidden ssid mode */ #define IEEE80211_F_NOBRIDGE 0x00000002 /* CONF: no internal bridging */ #define IEEE80211_F_HOSTAPMASK 0x00000003 #define IEEE80211_F_STAYAUTH 0x00000004 /* CONF: ignore deauth */ #define IEEE80211_F_NOMIMO 0x00000008 /* CONF: disable MIMO */ #define IEEE80211_F_NOVHT 0x00000010 /* CONF: disable 11ac */ #define IEEE80211_F_NOHT40 0x00000020 /* CONF: disable 40mhz on 2.4Ghz channel */ #define IEEE80211_F_USERBITS "\20\01HIDENWID\02NOBRIDGE\03STAYAUTH\04NOMIMO" struct ieee80211_flags { const char *f_name; u_int f_flag; }; #define IEEE80211_FLAGS { \ { "hidenwid", IEEE80211_F_HIDENWID }, \ { "nobridge", IEEE80211_F_NOBRIDGE }, \ { "stayauth", IEEE80211_F_STAYAUTH }, \ { "nomimo", IEEE80211_F_NOMIMO }, \ { "novht", IEEE80211_F_NOVHT }, \ { "noht40", IEEE80211_F_NOHT40 }, \ } #define SIOCG80211FLAGS _IOWR('i', 216, struct ifreq) #define SIOCS80211FLAGS _IOW('i', 217, struct ifreq) int ieee80211_ioctl_setnwkeys(struct ieee80211com *ic, const struct ieee80211_nwkey *nwkey); int ieee80211_ioctl_setwpaparms(struct ieee80211com *ic, const struct ieee80211_wpaparams *wpa); int ieee80211_ioctl_getwpaparms(struct ieee80211com *ic, struct ieee80211_wpaparams *wpa); void ieee80211_ess_getwpaparms(struct ieee80211_ess *ess, struct ieee80211_wpaparams *wpa); #endif /* _NET80211_IEEE80211_IOCTL_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_mira.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. */ /* $OpenBSD: ieee80211_mira.c,v 1.30 2020/05/01 14:04:17 stsp Exp $ */ /* * Copyright (c) 2016 Stefan Sperling * Copyright (c) 2016 Theo Buehler * Copyright (c) 2006 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include /* Allow for aggressive down probing when channel quality changes. */ #define MIRA_AGGRESSIVE_DOWNWARDS_PROBING const struct ieee80211_ht_rateset * ieee80211_mira_get_rateset(int, int, bool); void ieee80211_mira_probe_timeout_up(void *); void ieee80211_mira_probe_timeout_down(void *); uint64_t ieee80211_mira_get_txrate(int, int, bool is_40mhz); uint16_t ieee80211_mira_legacy_txtime(uint32_t, int, struct ieee80211com *); uint32_t ieee80211_mira_ht_txtime(uint32_t, int, int, int, bool is_40mhz); int ieee80211_mira_best_basic_rate(struct ieee80211_node *); int ieee80211_mira_ack_rate(struct ieee80211_node *); uint64_t ieee80211_mira_toverhead(struct ieee80211_mira_node *, struct ieee80211com *, struct ieee80211_node *); void ieee80211_mira_update_stats(struct ieee80211_mira_node *, struct ieee80211com *, struct ieee80211_node *); void ieee80211_mira_reset_goodput_stats(struct ieee80211_mira_node *); void ieee80211_mira_reset_driver_stats(struct ieee80211_mira_node *); int ieee80211_mira_next_lower_intra_rate(struct ieee80211_mira_node *, struct ieee80211_node *); int ieee80211_mira_next_intra_rate(struct ieee80211_mira_node *, struct ieee80211_node *); const struct ieee80211_ht_rateset * ieee80211_mira_next_rateset( struct ieee80211_mira_node *, struct ieee80211_node *); int ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *, const struct ieee80211_ht_rateset *); void ieee80211_mira_probe_next_rateset(struct ieee80211_mira_node *, struct ieee80211_node *, const struct ieee80211_ht_rateset *); int ieee80211_mira_next_mcs(struct ieee80211_mira_node *, struct ieee80211_node *); int ieee80211_mira_prev_mcs(struct ieee80211_mira_node *, struct ieee80211_node *); int ieee80211_mira_probe_valid(struct ieee80211_mira_node *, struct ieee80211_node *); void ieee80211_mira_probe_done(struct ieee80211_mira_node *); int ieee80211_mira_intra_mode_ra_finished( struct ieee80211_mira_node *, struct ieee80211_node *); void ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn, struct ieee80211_node *); int ieee80211_mira_inter_mode_ra_finished( struct ieee80211_mira_node *, struct ieee80211_node *); int ieee80211_mira_best_rate(struct ieee80211_mira_node *, struct ieee80211_node *); void ieee80211_mira_update_probe_interval( struct ieee80211_mira_goodput_stats *); void ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *, struct ieee80211_node *); int ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *, struct ieee80211_node *); void ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *, struct ieee80211_node *); int ieee80211_mira_valid_tx_mcs(struct ieee80211com *, int); uint32_t ieee80211_mira_valid_rates(struct ieee80211com *, struct ieee80211_node *); uint32_t ieee80211_mira_mcs_below(struct ieee80211_mira_node *, int, int, bool); void ieee80211_mira_set_rts_threshold(struct ieee80211_mira_node *, struct ieee80211com *, struct ieee80211_node *); void ieee80211_mira_reset_collision_stats(struct ieee80211_mira_node *); /* We use fixed point arithmetic with 64 bit integers. */ #define MIRA_FP_SHIFT 21 #define MIRA_FP_INT(x) (x ## ULL << MIRA_FP_SHIFT) /* the integer x */ #define MIRA_FP_1 MIRA_FP_INT(1) /* Multiply two fixed point numbers. */ #define MIRA_FP_MUL(a, b) \ (((a) * (b)) >> MIRA_FP_SHIFT) /* Divide two fixed point numbers. */ #define MIRA_FP_DIV(a, b) \ (b == 0 ? (uint64_t)-1 : (((a) << MIRA_FP_SHIFT) / (b))) #ifdef MIRA_DEBUG #define DPRINTF(x) do { if (mira_debug > 0) printf x; } while (0) #define DPRINTFN(n, x) do { if (mira_debug >= (n)) printf x; } while (0) int mira_debug = 1; #else #define DPRINTF(x) do { ; } while (0) #define DPRINTFN(n, x) do { ; } while (0) #endif #ifdef MIRA_DEBUG void mira_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp) { uint64_t tmp; /* integer part */ *i = (fp >> MIRA_FP_SHIFT); /* fractional part */ tmp = (fp & ((uint64_t)-1 >> (64 - MIRA_FP_SHIFT))); tmp *= 100; *f = (uint32_t)(tmp >> MIRA_FP_SHIFT); } char * mira_fp_sprintf(uint64_t fp) { uint32_t i, f; static char buf[64]; int ret; mira_fixedp_split(&i, &f, fp); ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f); if (ret == -1 || ret >= sizeof(buf)) return "ERR"; return buf; } void mira_print_driver_stats(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { DPRINTF(("%s driver stats:\n", ether_sprintf(ni->ni_macaddr))); DPRINTF(("mn->frames = %u\n", mn->frames)); DPRINTF(("mn->retries = %u\n", mn->retries)); DPRINTF(("mn->txfail = %u\n", mn->txfail)); DPRINTF(("mn->ampdu_size = %u\n", mn->ampdu_size)); DPRINTF(("mn->agglen = %u\n", mn->agglen)); } #endif /* MIRA_DEBUG */ const struct ieee80211_ht_rateset * ieee80211_mira_get_rateset(int mcs, int sgi, bool is_40mhz) { const struct ieee80211_ht_rateset *rs; int i; int first = 0; int last = IEEE80211_HT_RATESET_MIMO4_SGI; if (is_40mhz) { first = IEEE80211_HT_RATESET_CBW40_SISO; last = IEEE80211_HT_RATESET_CBW40_MIMO4_SGI; } for (i = first; i <= last; i++) { rs = &ieee80211_std_ratesets_11n[i]; if (sgi != rs->sgi) continue; if (mcs >= rs->min_mcs && mcs <= rs->max_mcs) return rs; } panic("MCS %d is not part of any rateset", mcs); return NULL; } /* * Probe timers. */ /* Constants related to timeouts for time-driven rate probing. */ #define IEEE80211_MIRA_PROBE_TIMEOUT_MIN 2 /* in msec */ #define IEEE80211_MIRA_PROBE_INTVAL_MAX (1 << 10) /* 2^10 */ void ieee80211_mira_probe_timeout_up(void *arg) { struct ieee80211_mira_node *mn = (struct ieee80211_mira_node *)arg; int s; s = splnet(); mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] = 1; DPRINTFN(3, ("probe up timeout fired\n")); splx(s); } void ieee80211_mira_probe_timeout_down(void *arg) { struct ieee80211_mira_node *mn = (struct ieee80211_mira_node *)arg; int s; s = splnet(); mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN] = 1; DPRINTFN(3, ("probe down timeout fired\n")); splx(s); } /* * Update goodput statistics. */ uint64_t ieee80211_mira_get_txrate(int mcs, int sgi, bool is_40mhz) { const struct ieee80211_ht_rateset *rs; uint64_t txrate; rs = ieee80211_mira_get_rateset(mcs, sgi, is_40mhz); txrate = rs->rates[mcs - rs->min_mcs]; txrate <<= MIRA_FP_SHIFT; /* convert to fixed-point */ txrate *= 500; /* convert to kbit/s */ txrate /= 1000; /* convert to mbit/s */ return txrate; } /* Based on rt2661_txtime in the ral(4) driver. */ uint16_t ieee80211_mira_legacy_txtime(uint32_t len, int rate, struct ieee80211com *ic) { #define MIRA_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) uint16_t txtime; if (MIRA_RATE_IS_OFDM(rate)) { /* IEEE Std 802.11g-2003, pp. 44 */ txtime = (8 + 4 * len + 3 + rate - 1) / rate; txtime = 16 + 4 + 4 * txtime + 6; } else { /* IEEE Std 802.11b-1999, pp. 28 */ txtime = (16 * len + rate - 1) / rate; if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txtime += 72 + 24; else txtime += 144 + 48; } return txtime; } uint32_t ieee80211_mira_ht_txtime(uint32_t len, int mcs, int is2ghz, int sgi, bool is_40mhz) { const struct ieee80211_ht_rateset *rs; /* XXX These constants should be macros in ieee80211.h instead. */ const uint32_t t_lstf = 8; /* usec legacy short training field */ const uint32_t t_lltf = 8; /* usec legacy long training field */ const uint32_t t_lsig = 4; /* usec legacy signal field */ const uint32_t t_htstf = 4; /* usec HT short training field */ const uint32_t t_ltstf = 4; /* usec HT long training field */ const uint32_t t_htsig = 8; /* usec HT signal field */ const uint32_t t_sym = 4; /* usec symbol interval */ const uint32_t t_syms_n = 36; /* usec symbol interval for sgi numerator */ const uint32_t t_syms_d = 10; /* usec symbol interval for sgi denominator */ uint32_t n_sym, n_dbps; uint32_t t_plcp; uint32_t t_data; uint32_t txtime; /* * Calculate approximate frame Tx time in usec. * See 802.11-2012, 20.4.3 "TXTIME calculation" and * 20.3.11.1 "Equation (20-32)". * XXX Assumes a 20MHz channel, HT-mixed frame format, no STBC. */ t_plcp = t_lstf + t_lltf + t_lsig + t_htstf + 4 * t_ltstf + t_htsig; rs = ieee80211_mira_get_rateset(mcs, sgi, is_40mhz); n_dbps = rs->rates[mcs - rs->min_mcs] * 2; n_sym = ((8 * len + 16 + 6) / n_dbps); /* "Equation (20-32)" */ if (sgi) t_data = (t_syms_n * n_sym) / t_syms_d; else t_data = t_sym * n_sym; txtime = t_plcp + t_data; if (is2ghz) txtime += 6; /* aSignalExtension */ return txtime; } int ieee80211_mira_best_basic_rate(struct ieee80211_node *ni) { struct ieee80211_rateset *rs = &ni->ni_rates; int i, best, rval; /* Default to 1 Mbit/s on 2GHz and 6 Mbit/s on 5GHz. */ best = IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ? 2 : 12; for (i = 0; i < rs->rs_nrates; i++) { if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0) continue; rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL); if (rval > best) best = rval; } return best; } /* * See 802.11-2012, 9.7.6.5 "Rate selection for control response frames". */ int ieee80211_mira_ack_rate(struct ieee80211_node *ni) { /* * Assume the ACK was sent at a mandatory ERP OFDM rate. * In the worst case, the driver has retried at non-HT rates, * so for MCS 0 assume we didn't actually send an OFDM frame * and ACKs arrived at a basic rate. */ if (ni->ni_txmcs == 0) return ieee80211_mira_best_basic_rate(ni); else if (ni->ni_txmcs == 1) return 12; /* 6 Mbit/s */ else if (ni->ni_txmcs >= 2) return 24; /* 12 Mbit/s */ else return 48; /* 24 Mbit/s */ } uint64_t ieee80211_mira_toverhead(struct ieee80211_mira_node *mn, struct ieee80211com *ic, struct ieee80211_node *ni) { /* XXX These should be macros in ieee80211.h. */ #define MIRA_RTSLEN IEEE80211_MIN_LEN #define MIRA_CTSLEN (sizeof(struct ieee80211_frame_cts) + IEEE80211_CRC_LEN) uint32_t overhead; uint64_t toverhead; int rate, rts; enum ieee80211_htprot htprot; int sgi = (ni->ni_flags & (IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40)) ? 1 : 0; overhead = ieee80211_mira_ht_txtime(0, ni->ni_txmcs, IEEE80211_IS_CHAN_2GHZ(ni->ni_chan), sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); htprot = (enum ieee80211_htprot)(ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK); if (htprot == IEEE80211_HTPROT_NONMEMBER || htprot == IEEE80211_HTPROT_NONHT_MIXED) rts = 1; else if (htprot == IEEE80211_HTPROT_20MHZ && (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40)) rts = 1; else rts = (mn->ampdu_size > ieee80211_mira_get_rts_threshold(mn, ic, ni, mn->ampdu_size)); if (rts) { /* Assume RTS/CTS were sent at a basic rate. */ rate = ieee80211_min_basic_rate(ic); overhead += ieee80211_mira_legacy_txtime(MIRA_RTSLEN, rate, ic); overhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN, rate, ic); } if (mn->agglen == 1) { /* Single-frame transmissions must wait for an ACK frame. */ rate = ieee80211_mira_ack_rate(ni); overhead += ieee80211_mira_legacy_txtime(IEEE80211_ACK_LEN, rate, ic); } toverhead = overhead; toverhead <<= MIRA_FP_SHIFT; /* convert to fixed-point */ toverhead /= 1000; /* convert to msec */ toverhead /= 1000; /* convert to sec */ #ifdef MIRA_DEBUG if (mira_debug > 3) { uint32_t txtime; txtime = ieee80211_mira_ht_txtime(mn->ampdu_size, ni->ni_txmcs, IEEE80211_IS_CHAN_2GHZ(ni->ni_chan), sgi, ni->ni_chw == 40); txtime += overhead - ieee80211_mira_ht_txtime(0, ni->ni_txmcs, IEEE80211_IS_CHAN_2GHZ(ni->ni_chan), sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); DPRINTFN(4, ("txtime: %u usec\n", txtime)); DPRINTFN(4, ("overhead: %u usec\n", overhead)); DPRINTFN(4, ("toverhead: %s\n", mira_fp_sprintf(toverhead))); } #endif return toverhead; } void ieee80211_mira_update_stats(struct ieee80211_mira_node *mn, struct ieee80211com *ic, struct ieee80211_node *ni) { /* Magic numbers from MiRA paper. */ static const uint64_t alpha = MIRA_FP_1 / 8; /* 1/8 = 0.125 */ static const uint64_t beta = MIRA_FP_1 / 4; /* 1/4 = 0.25 */ uint64_t sfer, delta, toverhead; uint64_t agglen = mn->agglen; uint64_t ampdu_size = mn->ampdu_size * 8; /* convert to bits */ int sgi = (ni->ni_flags & (IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40)) ? 1 : 0; uint64_t rate = ieee80211_mira_get_txrate(ni->ni_txmcs, sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs]; if (mn->frames == 0) return; /* avoid divide-by-zero in sfer calculation below */ g->nprobes += mn->agglen; g->nprobe_bytes += mn->ampdu_size; ampdu_size <<= MIRA_FP_SHIFT; /* convert to fixed-point */ agglen <<= MIRA_FP_SHIFT; /* XXX range checks? */ ampdu_size = ampdu_size / 1000; /* kbit */ ampdu_size = ampdu_size / 1000; /* mbit */ /* Compute Sub-Frame Error Rate (see section 2.2 in MiRA paper). */ sfer = mn->frames * mn->txfail + mn->retries; if ((sfer >> MIRA_FP_SHIFT) != 0) { /* bug in wifi driver */ if (ic->ic_if.if_flags & IFF_DEBUG) { #ifdef DIAGNOSTIC printf("%s: mira sfer overflow\n", ether_sprintf(ni->ni_macaddr)); #endif #ifdef MIRA_DEBUG mira_print_driver_stats(mn, ni); #endif } ieee80211_mira_probe_done(mn); return; } sfer <<= MIRA_FP_SHIFT; /* convert to fixed-point */ sfer /= (mn->txfail + 1) * mn->frames; if (sfer > MIRA_FP_1) { /* bug in wifi driver */ if (ic->ic_if.if_flags & IFF_DEBUG) { #ifdef DIAGNOSTIC printf("%s: mira sfer > 1\n", ether_sprintf(ni->ni_macaddr)); #endif #ifdef MIRA_DEBUG mira_print_driver_stats(mn, ni); #endif } sfer = MIRA_FP_1; /* round down */ } /* Store current loss percentage SFER. */ g->loss = sfer * 100; #ifdef MIRA_DEBUG if (g->loss && ieee80211_mira_probe_valid(mn, ni)) DPRINTFN(2, ("frame error rate at MCS %d: %s%%\n", ni->ni_txmcs, mira_fp_sprintf(g->loss))); #endif /* * Update goodput statistics (see section 5.1.2 in MiRA paper). * We use a slightly modified but equivalent calculation which * is tuned towards our fixed-point number format. */ g->average_agg = MIRA_FP_MUL(MIRA_FP_1 - alpha, g->average_agg); g->average_agg += MIRA_FP_MUL(alpha, agglen); toverhead = ieee80211_mira_toverhead(mn, ic, ni); toverhead = MIRA_FP_MUL(toverhead, rate); g->measured = MIRA_FP_DIV(MIRA_FP_1 - sfer, MIRA_FP_1 + MIRA_FP_DIV(toverhead, MIRA_FP_MUL(ampdu_size, g->average_agg))); g->measured = MIRA_FP_MUL(g->measured, rate); g->average = MIRA_FP_MUL(MIRA_FP_1 - alpha, g->average); g->average += MIRA_FP_MUL(alpha, g->measured); g->stddeviation = MIRA_FP_MUL(MIRA_FP_1 - beta, g->stddeviation); if (g->average > g->measured) delta = g->average - g->measured; else delta = g->measured - g->average; g->stddeviation += MIRA_FP_MUL(beta, delta); } void ieee80211_mira_reset_goodput_stats(struct ieee80211_mira_node *mn) { int i; for (i = 0; i < nitems(mn->g); i++) { struct ieee80211_mira_goodput_stats *g = &mn->g[i]; memset(g, 0, sizeof(*g)); g->average_agg = 1; g->probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN; } } void ieee80211_mira_reset_driver_stats(struct ieee80211_mira_node *mn) { mn->frames = 0; mn->retries = 0; mn->txfail = 0; mn->ampdu_size = 0; mn->agglen = 1; } /* * Rate selection. */ /* A rate's goodput has to be at least this much larger to be "better". */ #define IEEE80211_MIRA_RATE_THRESHOLD (MIRA_FP_1 / 64) /* ~ 0.015 */ #define IEEE80211_MIRA_LOSS_THRESHOLD 10 /* in percent */ /* Number of (sub-)frames which render a probe valid. */ #define IEEE80211_MIRA_MIN_PROBE_FRAMES 4 /* Number of bytes which, alternatively, render a probe valid. */ #define IEEE80211_MIRA_MIN_PROBE_BYTES (2 * IEEE80211_MAX_LEN) /* Number of Tx failures which, alternatively, render a probe valid. */ #define IEEE80211_MIRA_MAX_PROBE_TXFAIL 1 /* Number of Tx retries which, alternatively, render a probe valid. */ #define IEEE80211_MIRA_MAX_PROBE_RETRIES 4 int ieee80211_mira_next_lower_intra_rate(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { const struct ieee80211_ht_rateset *rs; int i, next; int sgi = (ni->ni_flags & (IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40)) ? 1 : 0; rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); if (ni->ni_txmcs == rs->min_mcs) return rs->min_mcs; next = ni->ni_txmcs; for (i = rs->nrates - 1; i >= 0; i--) { if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0) continue; if (i + rs->min_mcs < ni->ni_txmcs) { next = i + rs->min_mcs; break; } } return next; } int ieee80211_mira_next_intra_rate(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { const struct ieee80211_ht_rateset *rs; int i, next; int sgi = (ni->ni_flags & (IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40)) ? 1 : 0; rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); if (ni->ni_txmcs == rs->max_mcs) return rs->max_mcs; next = ni->ni_txmcs; for (i = 0; i < rs->nrates; i++) { if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0) continue; if (i + rs->min_mcs > ni->ni_txmcs) { next = i + rs->min_mcs; break; } } return next; } const struct ieee80211_ht_rateset * ieee80211_mira_next_rateset(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { const struct ieee80211_ht_rateset *rs, *rsnext; int next; int mcs = ni->ni_txmcs; int sgi = (ni->ni_flags & (IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40)) ? 1 : 0; rs = ieee80211_mira_get_rateset(mcs, sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); if (mn->probing & IEEE80211_MIRA_PROBING_UP) { if (rs->max_mcs == 7) /* MCS 0-7 */ next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI : IEEE80211_HT_RATESET_MIMO2; else if (rs->max_mcs == 15) /* MCS 8-15 */ next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI : IEEE80211_HT_RATESET_MIMO3; else if (rs->max_mcs == 23) /* MCS 16-23 */ next = sgi ? IEEE80211_HT_RATESET_MIMO4_SGI : IEEE80211_HT_RATESET_MIMO4; else /* MCS 24-31 */ return NULL; } else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) { if (rs->min_mcs == 24) /* MCS 24-31 */ next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI : IEEE80211_HT_RATESET_MIMO3; else if (rs->min_mcs == 16) /* MCS 16-23 */ next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI : IEEE80211_HT_RATESET_MIMO2; else if (rs->min_mcs == 8) /* MCS 8-15 */ next = sgi ? IEEE80211_HT_RATESET_SISO_SGI : IEEE80211_HT_RATESET_SISO; else /* MCS 0-7 */ return NULL; } else panic("%s: invalid probing mode %d", __func__, mn->probing); rsnext = &ieee80211_std_ratesets_11n[next]; if ((rsnext->mcs_mask & mn->valid_rates) == 0) return NULL; return rsnext; } int ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *mn, const struct ieee80211_ht_rateset *rs) { uint64_t gmax = 0; int i, best_mcs = rs->min_mcs; for (i = 0; i < rs->nrates; i++) { int mcs = rs->min_mcs + i; struct ieee80211_mira_goodput_stats *g = &mn->g[mcs]; if (((1 << mcs) & mn->valid_rates) == 0) continue; if (g->measured > gmax + IEEE80211_MIRA_RATE_THRESHOLD) { gmax = g->measured; best_mcs = mcs; } } return best_mcs; } void ieee80211_mira_probe_next_rateset(struct ieee80211_mira_node *mn, struct ieee80211_node *ni, const struct ieee80211_ht_rateset *rsnext) { const struct ieee80211_ht_rateset *rs; struct ieee80211_mira_goodput_stats *g; int best_mcs, i; int sgi = (ni->ni_flags & (IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40)) ? 1 : 0; /* Find most recently measured best MCS from the current rateset. */ rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs); /* Switch to the next rateset. */ ni->ni_txmcs = rsnext->min_mcs; if ((mn->valid_rates & (1 << rsnext->min_mcs)) == 0) ni->ni_txmcs = ieee80211_mira_next_intra_rate(mn, ni); /* Select the lowest rate from the next rateset with loss-free * goodput close to the current best measurement. */ g = &mn->g[best_mcs]; for (i = 0; i < rsnext->nrates; i++) { int mcs = rsnext->min_mcs + i; uint64_t txrate = rsnext->rates[i]; if ((mn->valid_rates & (1 << mcs)) == 0) continue; txrate = txrate * 500; /* convert to kbit/s */ txrate <<= MIRA_FP_SHIFT; /* convert to fixed-point */ txrate /= 1000; /* convert to mbit/s */ if (txrate > g->measured + IEEE80211_MIRA_RATE_THRESHOLD) { ni->ni_txmcs = mcs; break; } } /* If all rates are lower the maximum rate is the closest match. */ if (i == rsnext->nrates) ni->ni_txmcs = rsnext->max_mcs; /* Add rates from the next rateset as candidates. */ mn->candidate_rates |= (1 << ni->ni_txmcs); if (mn->probing & IEEE80211_MIRA_PROBING_UP) { mn->candidate_rates |= (1 << ieee80211_mira_next_intra_rate(mn, ni)); } else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) { #ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING mn->candidate_rates |= ieee80211_mira_mcs_below(mn, ni->ni_txmcs, sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); #else mn->candidate_rates |= (1 << ieee80211_mira_next_lower_intra_rate(mn, ni)); #endif } else panic("%s: invalid probing mode %d", __func__, mn->probing); } int ieee80211_mira_next_mcs(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { int next; if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) next = ieee80211_mira_next_lower_intra_rate(mn, ni); else if (mn->probing & IEEE80211_MIRA_PROBING_UP) next = ieee80211_mira_next_intra_rate(mn, ni); else panic("%s: invalid probing mode %d", __func__, mn->probing); return next; } int ieee80211_mira_prev_mcs(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { int next; if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) next = ieee80211_mira_next_intra_rate(mn, ni); else if (mn->probing & IEEE80211_MIRA_PROBING_UP) next = ieee80211_mira_next_lower_intra_rate(mn, ni); else panic("%s: invalid probing mode %d", __func__, mn->probing); return next; } int ieee80211_mira_probe_valid(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs]; return (g->nprobes >= IEEE80211_MIRA_MIN_PROBE_FRAMES || g->nprobe_bytes >= IEEE80211_MIRA_MIN_PROBE_BYTES || mn->txfail >= IEEE80211_MIRA_MAX_PROBE_TXFAIL || mn->retries >= IEEE80211_MIRA_MAX_PROBE_RETRIES); } void ieee80211_mira_probe_done(struct ieee80211_mira_node *mn) { int mcs; /* Reset probe interval of the best rate. */ mn->g[mn->best_mcs].probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN; mn->g[mn->best_mcs].nprobes = 0; mn->g[mn->best_mcs].nprobe_bytes = 0; /* Update probing interval of other probed rates. */ for (mcs = 0; mcs < IEEE80211_HT_RATESET_NUM_MCS; mcs++) { if (mcs != mn->best_mcs && (mn->probed_rates & (1 << mcs))) ieee80211_mira_update_probe_interval(&mn->g[mcs]); } ieee80211_mira_cancel_timeouts(mn); ieee80211_mira_reset_driver_stats(mn); ieee80211_mira_reset_collision_stats(mn); mn->probing = IEEE80211_MIRA_NOT_PROBING; mn->probed_rates = 0; mn->candidate_rates = 0; } int ieee80211_mira_intra_mode_ra_finished(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { const struct ieee80211_ht_rateset *rs; struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs]; int next_mcs, best_mcs, probed_rates; uint64_t next_rate; int sgi = (ni->ni_flags & (IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40)) ? 1 : 0; bool is_40mhz = (ni->ni_chw == IEEE80211_CHAN_WIDTH_40); if (!ieee80211_mira_probe_valid(mn, ni)) return 0; probed_rates = (mn->probed_rates | (1 << ni->ni_txmcs)); /* Check if the min/max MCS in this rateset has been probed. */ rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi, is_40mhz); if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) { if (ni->ni_txmcs == rs->min_mcs || probed_rates & (1 << rs->min_mcs)) { ieee80211_mira_trigger_next_rateset(mn, ni); return 1; } } else if (mn->probing & IEEE80211_MIRA_PROBING_UP) { if (ni->ni_txmcs == rs->max_mcs || probed_rates & (1 << rs->max_mcs)) { ieee80211_mira_trigger_next_rateset(mn, ni); return 1; } } /* * Check if the measured goodput is loss-free and better than the * loss-free goodput of the candidate rate. */ next_mcs = ieee80211_mira_next_mcs(mn, ni); if (next_mcs == ni->ni_txmcs) { ieee80211_mira_trigger_next_rateset(mn, ni); return 1; } next_rate = ieee80211_mira_get_txrate(next_mcs, sgi, is_40mhz); if (g->loss == 0 && g->measured >= next_rate + IEEE80211_MIRA_RATE_THRESHOLD) { ieee80211_mira_trigger_next_rateset(mn, ni); return 1; } /* Check if we had a better measurement at a previously probed MCS. */ best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs); if (best_mcs != ni->ni_txmcs && (probed_rates & (1 << best_mcs))) { if ((mn->probing & IEEE80211_MIRA_PROBING_UP) && best_mcs < ni->ni_txmcs) { ieee80211_mira_trigger_next_rateset(mn, ni); return 1; } if ((mn->probing & IEEE80211_MIRA_PROBING_DOWN) && best_mcs > ni->ni_txmcs) { ieee80211_mira_trigger_next_rateset(mn, ni); return 1; } } /* Check if all rates in the set of candidate rates have been probed. */ if ((mn->candidate_rates & probed_rates) == mn->candidate_rates) { /* Remain in the current rateset until above checks trigger. */ return 1; } return 0; } void ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { const struct ieee80211_ht_rateset *rsnext; rsnext = ieee80211_mira_next_rateset(mn, ni); if (rsnext) { ieee80211_mira_probe_next_rateset(mn, ni, rsnext); mn->probing |= IEEE80211_MIRA_PROBING_INTER; } else mn->probing &= ~IEEE80211_MIRA_PROBING_INTER; } int ieee80211_mira_inter_mode_ra_finished(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { return ((mn->probing & IEEE80211_MIRA_PROBING_INTER) == 0); } int ieee80211_mira_best_rate(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { int i, best = 0; uint64_t gmax = 0; for (i = 0; i < nitems(mn->g); i++) { struct ieee80211_mira_goodput_stats *g = &mn->g[i]; if (((1 << i) & mn->valid_rates) == 0) continue; if (g->measured > gmax + IEEE80211_MIRA_RATE_THRESHOLD) { gmax = g->measured; best = i; } } #ifdef MIRA_DEBUG if (mn->best_mcs != best) { DPRINTF(("MCS %d is best; MCS{Mbps|probe interval}:", best)); for (i = 0; i < IEEE80211_HT_RATESET_NUM_MCS; i++) { struct ieee80211_mira_goodput_stats *g = &mn->g[i]; if ((mn->valid_rates & (1 << i)) == 0) continue; DPRINTF((" %d{%s|%dms}", i, mira_fp_sprintf(g->measured), g->probe_interval)); } DPRINTF(("\n")); } #endif return best; } /* See section 5.1.1 (at "Adaptive probing interval") in MiRA paper. */ void ieee80211_mira_update_probe_interval(struct ieee80211_mira_goodput_stats *g) { uint64_t lt; int intval; lt = g->loss / IEEE80211_MIRA_LOSS_THRESHOLD; if (lt < MIRA_FP_1) lt = MIRA_FP_1; lt >>= MIRA_FP_SHIFT; /* round to integer */ intval = (1 << g->nprobes); /* 2^nprobes */ if (intval > IEEE80211_MIRA_PROBE_INTVAL_MAX) intval = IEEE80211_MIRA_PROBE_INTVAL_MAX; g->probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN * intval * lt; } void ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { struct ieee80211_mira_goodput_stats *g; CTimeout **to; int mcs; mcs = ieee80211_mira_next_intra_rate(mn, ni); to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP]; g = &mn->g[mcs]; if (mcs != ni->ni_txmcs && !timeout_pending(to) && !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP]) { timeout_add_msec(to, g->probe_interval); DPRINTFN(3, ("start probing up for node %s at MCS %d in at " "least %d msec\n", ether_sprintf(ni->ni_macaddr), mcs, g->probe_interval)); } mcs = ieee80211_mira_next_lower_intra_rate(mn, ni); to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_DOWN]; g = &mn->g[mcs]; if (mcs != ni->ni_txmcs && !timeout_pending(to) && !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) { timeout_add_msec(to, g->probe_interval); DPRINTFN(3, ("start probing down for node %s at MCS %d in at " "least %d msec\n", ether_sprintf(ni->ni_macaddr), mcs, g->probe_interval)); } } int ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { int ret = 0, expired_timer = IEEE80211_MIRA_PROBE_TO_INVALID; int mcs; if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] && mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) { if (arc4random_uniform(2)) expired_timer = IEEE80211_MIRA_PROBE_TO_UP; else expired_timer = IEEE80211_MIRA_PROBE_TO_DOWN; } else if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) expired_timer = IEEE80211_MIRA_PROBE_TO_DOWN; else if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP]) expired_timer = IEEE80211_MIRA_PROBE_TO_UP; if (expired_timer != IEEE80211_MIRA_PROBE_TO_INVALID) mn->probe_timer_expired[expired_timer] = 0; switch (expired_timer) { case IEEE80211_MIRA_PROBE_TO_UP: /* Do time-based upwards probing on next frame. */ DPRINTFN(2, ("probe timer expired: probe upwards\n")); mn->probing = IEEE80211_MIRA_PROBING_UP; mcs = ieee80211_mira_next_intra_rate(mn, ni); mn->candidate_rates = (1 << mcs); ret = 1; break; case IEEE80211_MIRA_PROBE_TO_DOWN: /* Do time-based downwards probing on next frame. */ DPRINTFN(2, ("probe timer expired: probe downwards\n")); mn->probing = IEEE80211_MIRA_PROBING_DOWN; mcs = ieee80211_mira_next_lower_intra_rate(mn, ni); mn->candidate_rates = (1 << mcs); ret = 1; break; case IEEE80211_MIRA_PROBE_TO_INVALID: default: ret = 0; break; } return ret; } void ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *mn, struct ieee80211_node *ni) { /* Select the next rate to probe. */ mn->probed_rates |= (1 << ni->ni_txmcs); ni->ni_txmcs = ieee80211_mira_next_mcs(mn, ni); } int ieee80211_mira_valid_tx_mcs(struct ieee80211com *ic, int mcs) { uint32_t ntxstreams = 1; static const int max_mcs[] = { 7, 15, 23, 31 }; if ((ic->ic_tx_mcs_set & IEEE80211_TX_RX_MCS_NOT_EQUAL) == 0) return isset(ic->ic_sup_mcs, mcs); ntxstreams += ((ic->ic_tx_mcs_set & IEEE80211_TX_SPATIAL_STREAMS) >> 2); if (ntxstreams < 1 || ntxstreams > 4) panic("invalid number of Tx streams: %u", ntxstreams); return (mcs <= max_mcs[ntxstreams - 1] && isset(ic->ic_sup_mcs, mcs)); } uint32_t ieee80211_mira_valid_rates(struct ieee80211com *ic, struct ieee80211_node *ni) { uint32_t valid_mcs = 0; int i; for (i = 0; i < IEEE80211_HT_RATESET_NUM_MCS; i++) { if (!isset(ni->ni_rxmcs, i)) continue; if (!ieee80211_mira_valid_tx_mcs(ic, i)) continue; valid_mcs |= (1 << i); } return valid_mcs; } uint32_t ieee80211_mira_mcs_below(struct ieee80211_mira_node *mn, int mcs, int sgi, bool is_40mhz) { const struct ieee80211_ht_rateset *rs; uint32_t mcs_mask; int i; rs = ieee80211_mira_get_rateset(mcs, sgi, is_40mhz); mcs_mask = (1 << rs->min_mcs); for (i = rs->min_mcs + 1; i < mcs; i++) { if ((mn->valid_rates & (1 << i)) == 0) continue; mcs_mask |= (1 << i); } return mcs_mask; } /* * Constants involved in detecting suspected frame collisions. * See section 5.2 of MiRA paper */ #define MIRA_COLLISION_LOSS_PERCENTAGE 10 /* from MiRA paper */ #define MIRA_COLLISION_DETECTED 3 /* from MiRA paper */ /* * XXX The paper's algorithm assumes aggregated frames. This is particularly * important for the detection of consecutive frame collisions which indicate * high competition for air time. Because we do not yet support Tx aggregation, * we run the algorithm over the result of several frames instead. * We also aggregate retries across all frames and act upon a percentage of * retried frames, rather than acting on retries seen for one aggregated frame. * * The collision window size (number of frames sent) needs to be short to * ensure our detection of consecutive collisions remains somewhat accurate. * We really have no idea how much time passes between frames in the window! * The good news is that users will only care about collision detection during * a transmit burst anyway, and we have this case more or less covered. */ #define MIRA_COLLISION_MIN_FRAMES 6 /* XXX magic number */ #define MIRA_COLLISION_RETRY_PERCENTAGE 60 /* XXX magic number */ /* Set RTS threshold based on suspected collision from other STAs. */ void ieee80211_mira_set_rts_threshold(struct ieee80211_mira_node *mn, struct ieee80211com *ic, struct ieee80211_node *ni) { uint16_t rtsthreshold = mn->rts_threshold; uint32_t loss, retry; /* Update collision window stats. */ mn->ifwnd_frames += mn->frames; mn->ifwnd_retries += mn->retries; mn->ifwnd_txfail += mn->txfail; if (mn->ifwnd_frames < MIRA_COLLISION_MIN_FRAMES) return; /* not enough frames yet */ /* Check whether the loss pattern indicates frame collisions. */ loss = (mn->ifwnd_txfail * 100) / mn->ifwnd_frames; retry = (mn->ifwnd_retries * 100) / mn->ifwnd_frames; if (retry > MIRA_COLLISION_RETRY_PERCENTAGE && loss < MIRA_COLLISION_LOSS_PERCENTAGE) { if (mn->ifwnd == 0) { /* First frame collision confirmed. */ mn->ifwnd = MIRA_COLLISION_DETECTED; } else if (mn->ifwnd == MIRA_COLLISION_DETECTED) { /* Successive frame collision confirmed. Use RTS. */ rtsthreshold = IEEE80211_RTS_DEFAULT; } } else { if (mn->ifwnd > 0) mn->ifwnd--; if (mn->ifwnd == 0) rtsthreshold = IEEE80211_RTS_MAX; } mn->rts_threshold = rtsthreshold; ieee80211_mira_reset_collision_stats(mn); } int ieee80211_mira_get_rts_threshold(struct ieee80211_mira_node *mn, struct ieee80211com *ic, struct ieee80211_node *ni, size_t framelen) { int rtsrate = ieee80211_min_basic_rate(ic); uint64_t txtime, rtsoverhead; /* Magic number from MiRA paper ("cost/benefit ratio"). */ static const uint64_t k = MIRA_FP_1 + (MIRA_FP_1 / 2); /* 1.5 */ if (mn->probing || mn->rts_threshold >= IEEE80211_RTS_MAX) return IEEE80211_RTS_MAX; /* Use RTS only if potential gains outweigh overhead. */ txtime = ieee80211_mira_ht_txtime(framelen, ni->ni_txmcs, IEEE80211_IS_CHAN_2GHZ(ni->ni_chan), (ni->ni_flags & (IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40)) ? 1 : 0, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); rtsoverhead = ieee80211_mira_legacy_txtime(MIRA_RTSLEN, rtsrate, ic); rtsoverhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN, rtsrate, ic); /* convert to fixed-point */ txtime <<= MIRA_FP_SHIFT; rtsoverhead <<= MIRA_FP_SHIFT; if (txtime >= MIRA_FP_MUL(k, rtsoverhead)) return mn->rts_threshold; return IEEE80211_RTS_MAX; } void ieee80211_mira_reset_collision_stats(struct ieee80211_mira_node *mn) { mn->ifwnd_frames = 0; mn->ifwnd_retries = 0; mn->ifwnd_txfail = 0; } void ieee80211_mira_choose(struct ieee80211_mira_node *mn, struct ieee80211com *ic, struct ieee80211_node *ni) { struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs]; int s; int sgi = (ni->ni_flags & (IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40)) ? 1 : 0; const struct ieee80211_ht_rateset *rs; s = splnet(); if (mn->valid_rates == 0) mn->valid_rates = ieee80211_mira_valid_rates(ic, ni); #ifdef MIRA_DEBUG if (mira_debug >= 5) mira_print_driver_stats(mn, ni); #endif ieee80211_mira_update_stats(mn, ic, ni); if (mn->probing) { /* Probe another rate or settle at the best rate. */ if (!ieee80211_mira_intra_mode_ra_finished(mn, ni)) { if (ieee80211_mira_probe_valid(mn, ni)) { ieee80211_mira_probe_next_rate(mn, ni); ieee80211_mira_reset_driver_stats(mn); } DPRINTFN(4, ("probing MCS %d\n", ni->ni_txmcs)); } else if (ieee80211_mira_inter_mode_ra_finished(mn, ni)) { mn->best_mcs = ieee80211_mira_best_rate(mn, ni); ni->ni_txmcs = mn->best_mcs; ieee80211_mira_probe_done(mn); } splx(s); return; } else { ieee80211_mira_set_rts_threshold(mn, ic, ni); ieee80211_mira_reset_driver_stats(mn); ieee80211_mira_schedule_probe_timers(mn, ni); } if (ieee80211_mira_check_probe_timers(mn, ni)) { /* Time-based probing has triggered. */ splx(s); return; } /* Check if event-based probing should be triggered. */ rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); if (g->measured < g->average - 2 * g->stddeviation && ni->ni_txmcs != rs->min_mcs) { /* Channel becomes bad. Probe downwards. */ DPRINTFN(2, ("channel becomes bad; probe downwards\n")); DPRINTFN(3, ("measured: %s Mbit/s\n", mira_fp_sprintf(g->measured))); DPRINTFN(3, ("average: %s Mbit/s\n", mira_fp_sprintf(g->average))); DPRINTFN(3, ("stddeviation: %s\n", mira_fp_sprintf(g->stddeviation))); mn->probing = IEEE80211_MIRA_PROBING_DOWN; mn->probed_rates = 0; #ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING /* Allow for probing all the way down within this rateset. */ mn->candidate_rates = ieee80211_mira_mcs_below(mn, ni->ni_txmcs, sgi, ni->ni_chw == IEEE80211_CHAN_WIDTH_40); #else /* Probe the lower candidate rate to see if it's any better. */ mn->candidate_rates = (1 << ieee80211_mira_next_lower_intra_rate(mn, ni)); #endif ieee80211_mira_cancel_timeouts(mn); } else if (g->measured > g->average + 2 * g->stddeviation && ni->ni_txmcs != rs->max_mcs) { /* Channel becomes good. */ DPRINTFN(2, ("channel becomes good; probe upwards\n")); DPRINTFN(3, ("measured: %s Mbit/s\n", mira_fp_sprintf(g->measured))); DPRINTFN(3, ("average: %s Mbit/s\n", mira_fp_sprintf(g->average))); DPRINTFN(3, ("stddeviation: %s\n", mira_fp_sprintf(g->stddeviation))); mn->probing = IEEE80211_MIRA_PROBING_UP; mn->probed_rates = 0; /* Probe the upper candidate rate to see if it's any better. */ mn->candidate_rates = (1 << ieee80211_mira_next_intra_rate(mn, ni)); ieee80211_mira_cancel_timeouts(mn); } else { /* Remain at current rate. */ mn->probing = IEEE80211_MIRA_NOT_PROBING; mn->probed_rates = 0; mn->candidate_rates = 0; } splx(s); } void ieee80211_mira_node_init(struct ieee80211_mira_node *mn) { memset(mn, 0, sizeof(*mn)); mn->agglen = 1; mn->rts_threshold = IEEE80211_RTS_MAX; ieee80211_mira_reset_goodput_stats(mn); ieee80211_mira_reset_collision_stats(mn); memset(mn->probe_to, 0, sizeof(mn->probe_to) * nitems(mn->probe_to)); timeout_set(&mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP], ieee80211_mira_probe_timeout_up, mn); timeout_set(&mn->probe_to[IEEE80211_MIRA_PROBE_TO_DOWN], ieee80211_mira_probe_timeout_down, mn); } void ieee80211_mira_cancel_timeouts(struct ieee80211_mira_node *mn) { int t; for (t = 0; t < nitems(mn->probe_to); t++) timeout_del(&mn->probe_to[t]); } void ieee80211_mira_node_free(struct ieee80211_mira_node *mn) { int t; for (t = 0; t < nitems(mn->probe_to); t++) { timeout_del(&mn->probe_to[t]); timeout_free(&mn->probe_to[t]); } } int ieee80211_mira_is_probing(struct ieee80211_mira_node *mn) { return mn->probing != IEEE80211_MIRA_NOT_PROBING; } int ieee80211_mira_get_best_mcs(struct ieee80211_mira_node *mn) { return mn->best_mcs; } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_mira.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_mira.h,v 1.5 2019/02/27 04:10:40 stsp Exp $ */ /* * Copyright (c) 2016 Stefan Sperling * Copyright (c) 2016 Theo Buehler * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _NET80211_IEEE80211_MIRA_H_ #define _NET80211_IEEE80211_MIRA_H_ /* * MiRA - "MIMO Rate Adaptation in 802.11n Wireless Networks" * Ioannis Pefkianakis, Yun Hu, Starsky H.Y. Wong, Hao Yang, Songwu Lu * http://www.cs.ucla.edu/wing/publication/papers/Pefkianakis.MOBICOM10.pdf */ /* * Goodput statistics struct. Measures the effective data rate of an MCS * index and contains data related to time-based probing to a new rate. * All uint64_t numbers in this struct use fixed-point arithmetic. */ struct ieee80211_mira_goodput_stats { uint64_t measured; /* Most recently measured goodput. */ uint64_t average; /* Average measured goodput. */ uint64_t average_agg; /* Average number of subframes per frame. */ uint64_t stddeviation; /* Goodput standard deviation. */ /* These fields are used while calculating probe intervals: */ uint64_t loss; /* This rate's loss percentage SFER. */ uint32_t nprobes; /* Number of probe attempts. */ uint32_t nprobe_bytes; /* Number of bytes sent while probing. */ int probe_interval; /* Probe interval for this rate. */ int probe_timeout_triggered; /* It is time to probe this rate. */ }; /* * Rate control state. */ struct ieee80211_mira_node { /* * Fields set by drivers before calling ieee80211_mira_choose(). */ uint32_t frames; /* Increment per (sub-)frame transmitted. */ uint32_t retries; /* Increment per Tx retry (frame not ACKed). */ uint32_t txfail; /* Increment per Tx failure (also not ACKed). */ uint32_t ampdu_size; /* Length of last (aggregated) frame sent. */ uint32_t agglen; /* Number of subframes in last frame (1-64). */ /* * Private fields for use by the rate control algorithm. */ /* Bitmaps MCS 0-31. */ uint32_t valid_rates; uint32_t candidate_rates; uint32_t probed_rates; /* Timeouts which trigger time-driven probing. */ CTimeout* probe_to[2]; #define IEEE80211_MIRA_PROBE_TO_INVALID -1 #define IEEE80211_MIRA_PROBE_TO_UP 0 #define IEEE80211_MIRA_PROBE_TO_DOWN 1 int probe_timer_expired[2]; /* Probing state. */ int probing; #define IEEE80211_MIRA_NOT_PROBING 0x0 #define IEEE80211_MIRA_PROBING_DOWN 0x1 #define IEEE80211_MIRA_PROBING_UP 0x2 #define IEEE80211_MIRA_PROBING_INTER 0x4 /* combined with UP or DOWN */ /* The current best MCS found by probing. */ int best_mcs; /* Goodput statistics for each MCS. */ struct ieee80211_mira_goodput_stats g[IEEE80211_HT_RATESET_NUM_MCS]; /* Interference observation window (see MiRA paper section 5.2). */ int ifwnd; uint32_t ifwnd_frames; uint32_t ifwnd_retries; uint32_t ifwnd_txfail; /* Current RTS threshold for this node. */ int rts_threshold; }; /* Initialize rate control state. */ void ieee80211_mira_node_init(struct ieee80211_mira_node *); /* Called by drivers from the Tx completion interrupt handler. */ void ieee80211_mira_choose(struct ieee80211_mira_node *, struct ieee80211com *, struct ieee80211_node *); /* Cancel timeouts scheduled by ieee80211_mira_choose(). */ void ieee80211_mira_cancel_timeouts(struct ieee80211_mira_node *); /* Release rate control state. */ void ieee80211_mira_node_free(struct ieee80211_mira_node *); /* Returns RTS threshold to be used for a frame about to be transmitted. */ int ieee80211_mira_get_rts_threshold(struct ieee80211_mira_node *, struct ieee80211com *, struct ieee80211_node *, size_t); int ieee80211_mira_is_probing(struct ieee80211_mira_node *); int ieee80211_mira_get_best_mcs(struct ieee80211_mira_node *mn); #endif /* _NET80211_IEEE80211_MIRA_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_node.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. */ /* $OpenBSD: ieee80211_node.c,v 1.173 2019/09/02 12:54:21 stsp Exp $ */ /* $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * Copyright (c) 2008 Damien Bergamini * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if NBRIDGE > 0 #include #endif #include #include struct ieee80211_node *ieee80211_node_alloc(struct ieee80211com *); void ieee80211_node_free(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_copy(struct ieee80211com *, struct ieee80211_node *, const struct ieee80211_node *); void ieee80211_choose_rsnparams(struct ieee80211com *); u_int8_t ieee80211_node_getrssi(struct ieee80211com *, const struct ieee80211_node *); int ieee80211_node_checkrssi(struct ieee80211com *, const struct ieee80211_node *); int ieee80211_ess_is_better(struct ieee80211com *ic, struct ieee80211_node *, struct ieee80211_node *); void ieee80211_node_set_timeouts(struct ieee80211_node *); void ieee80211_setup_node(struct ieee80211com *, struct ieee80211_node *, const u_int8_t *); struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *); void ieee80211_node_switch_bss(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_addba_request(struct ieee80211_node *, int); void ieee80211_node_addba_request_ac_be_to(void *); void ieee80211_node_addba_request_ac_bk_to(void *); void ieee80211_node_addba_request_ac_vi_to(void *); void ieee80211_node_addba_request_ac_vo_to(void *); void ieee80211_needs_auth(struct ieee80211com *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_node_join_ht(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_join_rsn(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_join_11g(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_leave_ht(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_leave_vht(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_leave_rsn(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_leave_11g(struct ieee80211com *, struct ieee80211_node *); void ieee80211_inact_timeout(void *); void ieee80211_node_cache_timeout(void *); #endif void ieee80211_clean_inactive_nodes(struct ieee80211com *, int); #ifndef IEEE80211_STA_ONLY void ieee80211_inact_timeout(void *arg) { struct ieee80211com *ic = (struct ieee80211com *)arg; struct ieee80211_node *ni, *next_ni; int s; s = splnet(); for (ni = RB_MIN(ieee80211_tree, &ic->ic_tree); ni != NULL; ni = next_ni) { next_ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); if (ni->ni_refcnt > 0) continue; if (ni->ni_inact < IEEE80211_INACT_MAX) ni->ni_inact++; } splx(s); timeout_add_sec(&ic->ic_inact_timeout, IEEE80211_INACT_WAIT); } void ieee80211_node_cache_timeout(void *arg) { struct ieee80211com *ic = (struct ieee80211com *)arg; ieee80211_clean_nodes(ic, 1); timeout_add_sec(&ic->ic_node_cache_timeout, IEEE80211_CACHE_WAIT); } #endif /* * For debug purposes */ void ieee80211_print_ess(struct ieee80211_ess *ess) { ieee80211_print_essid(ess->essid, ess->esslen); if (ess->flags & IEEE80211_F_RSNON) { XYLog(" wpa"); if (ess->rsnprotos & IEEE80211_PROTO_RSN) XYLog(",wpa2"); if (ess->rsnprotos & IEEE80211_PROTO_WPA) XYLog(",wpa1"); if (ess->rsnakms & IEEE80211_AKM_8021X || ess->rsnakms & IEEE80211_AKM_SHA256_8021X) XYLog(",802.1x"); XYLog(" "); if (ess->rsnciphers & IEEE80211_CIPHER_USEGROUP) XYLog(" usegroup"); if (ess->rsnciphers & IEEE80211_CIPHER_WEP40) XYLog(" wep40"); if (ess->rsnciphers & IEEE80211_CIPHER_WEP104) XYLog(" wep104"); if (ess->rsnciphers & IEEE80211_CIPHER_TKIP) XYLog(" tkip"); if (ess->rsnciphers & IEEE80211_CIPHER_CCMP) XYLog(" ccmp"); } if (ess->flags & IEEE80211_F_WEPON) { int i = ess->def_txkey; XYLog(" wep,"); if (ess->nw_keys[i].k_cipher & IEEE80211_CIPHER_WEP40) XYLog("wep40"); if (ess->nw_keys[i].k_cipher & IEEE80211_CIPHER_WEP104) XYLog("wep104"); } if (ess->flags == 0) XYLog(" clear"); XYLog("\n"); } void ieee80211_print_ess_list(struct ieee80211com *ic) { struct _ifnet *ifp = &ic->ic_if; struct ieee80211_ess *ess; XYLog("%s: known networks\n", ifp->if_xname); TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) { ieee80211_print_ess(ess); } } struct ieee80211_ess * ieee80211_get_ess(struct ieee80211com *ic, const char *nwid, int len) { struct ieee80211_ess *ess; TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) { if (len == ess->esslen && memcmp(ess->essid, nwid, ess->esslen) == 0) return ess; } return NULL; } void ieee80211_del_ess(struct ieee80211com *ic, char *nwid, int len, int all) { struct ieee80211_ess *ess, *next; TAILQ_FOREACH_SAFE(ess, &ic->ic_ess, ess_next, next) { if (ess == NULL) { XYLog("%s: ess == NULL!!!\n", __FUNCTION__); continue; } if (all == 1 || (ess->esslen == len && memcmp(ess->essid, nwid, len) == 0)) { TAILQ_REMOVE(&ic->ic_ess, ess, ess_next); explicit_bzero(ess, sizeof(*ess)); free(ess); if (TAILQ_EMPTY(&ic->ic_ess)) ic->ic_flags &= ~IEEE80211_F_AUTO_JOIN; if (all != 1) return; } } } /* Keep in sync with ieee80211_ioctl.c:ieee80211_ioctl_setnwkeys() */ static int ieee80211_ess_setnwkeys(struct ieee80211_ess *ess, const struct ieee80211_nwkey *nwkey) { struct ieee80211_key *k; int error, i; if (nwkey->i_wepon == IEEE80211_NWKEY_OPEN) { if (!(ess->flags & IEEE80211_F_WEPON)) return 0; ess->flags &= ~IEEE80211_F_WEPON; return ENETRESET; } if (nwkey->i_defkid < 1 || nwkey->i_defkid > IEEE80211_WEP_NKID) return EINVAL; for (i = 0; i < IEEE80211_WEP_NKID; i++) { if (nwkey->i_key[i].i_keylen == 0 || nwkey->i_key[i].i_keydat == NULL) continue; /* entry not set */ if (nwkey->i_key[i].i_keylen > IEEE80211_KEYBUF_SIZE) return EINVAL; /* map wep key to ieee80211_key */ k = &ess->nw_keys[i]; memset(k, 0, sizeof(*k)); if (nwkey->i_key[i].i_keylen <= 5) k->k_cipher = IEEE80211_CIPHER_WEP40; else k->k_cipher = IEEE80211_CIPHER_WEP104; k->k_len = ieee80211_cipher_keylen(k->k_cipher); k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX; error = copyin((const user_addr_t)nwkey->i_key[i].i_keydat, k->k_key, k->k_len); if (error != 0) return error; } ess->def_txkey = nwkey->i_defkid - 1; ess->flags |= IEEE80211_F_WEPON; return ENETRESET; } /* Keep in sync with ieee80211_ioctl.c:ieee80211_ioctl_setwpaparms() */ static int ieee80211_ess_setwpaparms(struct ieee80211_ess *ess, const struct ieee80211_wpaparams *wpa) { if (!wpa->i_enabled) { if (!(ess->flags & IEEE80211_F_RSNON)) return 0; ess->flags &= ~IEEE80211_F_RSNON; ess->rsnprotos = 0; ess->rsnakms = 0; ess->rsngroupcipher = (enum ieee80211_cipher)0; ess->rsnciphers = 0; return ENETRESET; } ess->rsnprotos = 0; if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA1) ess->rsnprotos |= IEEE80211_PROTO_WPA; if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA2) ess->rsnprotos |= IEEE80211_PROTO_RSN; if (ess->rsnprotos == 0) /* set to default (RSN) */ ess->rsnprotos = IEEE80211_PROTO_RSN; ess->rsnakms = 0; if (wpa->i_akms & IEEE80211_WPA_AKM_PSK) ess->rsnakms |= IEEE80211_AKM_PSK; if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_PSK) ess->rsnakms |= IEEE80211_AKM_SHA256_PSK; if (wpa->i_akms & IEEE80211_WPA_AKM_8021X) ess->rsnakms |= IEEE80211_AKM_8021X; if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_8021X) ess->rsnakms |= IEEE80211_AKM_SHA256_8021X; if (ess->rsnakms == 0) /* set to default (PSK) */ ess->rsnakms = IEEE80211_AKM_PSK; if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP40) ess->rsngroupcipher = IEEE80211_CIPHER_WEP40; else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_TKIP) ess->rsngroupcipher = IEEE80211_CIPHER_TKIP; else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_CCMP) ess->rsngroupcipher = IEEE80211_CIPHER_CCMP; else if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP104) ess->rsngroupcipher = IEEE80211_CIPHER_WEP104; else { /* set to default */ if (ess->rsnprotos & IEEE80211_PROTO_WPA) ess->rsngroupcipher = IEEE80211_CIPHER_TKIP; else ess->rsngroupcipher = IEEE80211_CIPHER_CCMP; } ess->rsnciphers = 0; if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_TKIP) ess->rsnciphers |= IEEE80211_CIPHER_TKIP; if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_CCMP) ess->rsnciphers |= IEEE80211_CIPHER_CCMP; if (wpa->i_ciphers & IEEE80211_WPA_CIPHER_USEGROUP) ess->rsnciphers = IEEE80211_CIPHER_USEGROUP; if (ess->rsnciphers == 0) { /* set to default (CCMP, TKIP if WPA1) */ ess->rsnciphers = IEEE80211_CIPHER_CCMP; if (ess->rsnprotos & IEEE80211_PROTO_WPA) ess->rsnciphers |= IEEE80211_CIPHER_TKIP; } ess->flags |= IEEE80211_F_RSNON; if (ess->rsnakms & (IEEE80211_AKM_8021X|IEEE80211_AKM_SHA256_8021X)) ess->flags |= IEEE80211_JOIN_8021X; return ENETRESET; } static void ieee80211_ess_clear_wep(struct ieee80211_ess *ess) { int i; /* Disable WEP */ for (i = 0; i < IEEE80211_WEP_NKID; i++) { explicit_bzero(&ess->nw_keys[i], sizeof(ess->nw_keys[0])); } ess->def_txkey = 0; ess->flags &= ~IEEE80211_F_WEPON; } static void ieee80211_ess_clear_wpa(struct ieee80211_ess *ess) { /* Disable WPA */ ess->rsnprotos = ess->rsnakms = ess->rsnciphers = 0; ess->rsngroupcipher = (enum ieee80211_cipher)0; explicit_bzero(ess->psk, sizeof(ess->psk)); ess->flags &= ~(IEEE80211_F_PSK | IEEE80211_F_RSNON); } int ieee80211_add_ess(struct ieee80211com *ic, struct ieee80211_join *join) { struct ieee80211_ess *ess; int new_value = 0, ness = 0; /* only valid for station (aka, client) mode */ if (ic->ic_opmode != IEEE80211_M_STA) return (0); TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) { if (ess->esslen == join->i_len && memcmp(ess->essid, join->i_nwid, ess->esslen) == 0) break; ness++; } if (ess == NULL) { /* if not found, and wpa/wep are set, then return */ if ((join->i_flags & IEEE80211_JOIN_WPA) && (join->i_flags & IEEE80211_JOIN_NWKEY)) { return (EINVAL); } if (ness > IEEE80211_CACHE_SIZE) return (ERANGE); new_value = 1; ess = (struct ieee80211_ess *)malloc(sizeof(*ess), 0, 0); if (ess == NULL) return (ENOMEM); memcpy(ess->essid, join->i_nwid, join->i_len); ess->esslen = join->i_len; } if (join->i_flags & IEEE80211_JOIN_WPA) { if (join->i_wpaparams.i_enabled) { if (!(ic->ic_caps & IEEE80211_C_RSN)) { free(ess); return ENODEV; } ieee80211_ess_setwpaparms(ess, &join->i_wpaparams); if (join->i_flags & IEEE80211_JOIN_WPAPSK) { ess->flags |= IEEE80211_F_PSK; explicit_bzero(ess->psk, sizeof(ess->psk)); memcpy(ess->psk, &join->i_wpapsk.i_psk, sizeof(ess->psk)); } ieee80211_ess_clear_wep(ess); } else { ieee80211_ess_clear_wpa(ess); } } else if (join->i_flags & IEEE80211_JOIN_NWKEY) { if (join->i_nwkey.i_wepon) { if (!(ic->ic_caps & IEEE80211_C_WEP)) { free(ess); return ENODEV; } ieee80211_ess_setnwkeys(ess, &join->i_nwkey); ieee80211_ess_clear_wpa(ess); } else { ieee80211_ess_clear_wep(ess); } } if (new_value) TAILQ_INSERT_TAIL(&ic->ic_ess, ess, ess_next); return (0); } uint8_t ieee80211_ess_adjust_rssi(struct ieee80211com *ic, struct ieee80211_node *ni) { uint8_t rssi = ni->ni_rssi; /* * Slightly punish 2 GHz RSSI values since they are usually * stronger than 5 GHz RSSI values. */ if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { if (ic->ic_max_rssi) { uint8_t p = (5 * ic->ic_max_rssi) / 100; if (rssi >= p) rssi -= p; /* punish by 5% */ } else { if (rssi >= 8) rssi -= 8; /* punish by 8 dBm */ } } return rssi; } int ieee80211_ess_calculate_score(struct ieee80211com *ic, struct ieee80211_node *ni) { int score = 0; uint8_t min_5ghz_rssi; if (ic->ic_max_rssi) min_5ghz_rssi = IEEE80211_RSSI_THRES_RATIO_5GHZ; else min_5ghz_rssi = (uint8_t)IEEE80211_RSSI_THRES_5GHZ; /* not using join any */ if (ieee80211_get_ess(ic, (const char*)ni->ni_essid, ni->ni_esslen)) score += 32; /* Calculate the crypto score */ if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN) score += 16; if (ni->ni_rsnprotos & IEEE80211_PROTO_WPA) score += 8; if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) score += 4; /* 5GHz with a good signal */ if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) && ni->ni_rssi > min_5ghz_rssi) score += 2; /* HT/VHT available */ if (ieee80211_node_supports_ht(ni)) score++; if (ieee80211_node_supports_vht(ni)) score++; /* Boost this AP if it had no auth/assoc failures in the past. */ if (ni->ni_fails == 0) score += 21; return score; } /* * Given two APs, determine the "better" one of the two. * We compute a score based on the following attributes: * * crypto: wpa2 > wpa1 > wep > open * band: 5 GHz > 2 GHz provided 5 GHz rssi is above threshold * supported standard revisions: 11ac > 11n > 11a/b/g * rssi: rssi1 > rssi2 as a numeric comparison with a slight * disadvantage for 2 GHz APs * * Crypto carries most weight, followed by band, followed by rssi. */ int ieee80211_ess_is_better(struct ieee80211com *ic, struct ieee80211_node *nicur, struct ieee80211_node *nican) { struct _ifnet *ifp = &ic->ic_if; int score_cur = 0, score_can = 0; int cur_rssi, can_rssi; score_cur = ieee80211_ess_calculate_score(ic, nicur); score_can = ieee80211_ess_calculate_score(ic, nican); cur_rssi = ieee80211_ess_adjust_rssi(ic, nicur); can_rssi = ieee80211_ess_adjust_rssi(ic, nican); if (can_rssi > cur_rssi) score_can++; if ((ifp->if_flags & IFF_DEBUG) && (score_can <= score_cur)) { XYLog("%s: AP %s ", ifp->if_xname, ether_sprintf(nican->ni_bssid)); ieee80211_print_essid(nican->ni_essid, nican->ni_esslen); XYLog(" score %d\n", score_can); } return score_can > score_cur; } /* Determine whether a candidate AP belongs to a given ESS. */ int ieee80211_match_ess(struct ieee80211_ess *ess, struct ieee80211_node *ni) { if (ess->esslen != 0 && (ess->esslen != ni->ni_esslen || memcmp(ess->essid, ni->ni_essid, ess->esslen) != 0)) { ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_ESSID; return 0; } if (ess->flags & (IEEE80211_F_PSK | IEEE80211_F_RSNON)) { /* Ensure same WPA version. */ if ((ni->ni_rsnprotos & IEEE80211_PROTO_RSN) && (ess->rsnprotos & IEEE80211_PROTO_RSN) == 0) { ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; return 0; } if ((ni->ni_rsnprotos & IEEE80211_PROTO_WPA) && (ess->rsnprotos & IEEE80211_PROTO_WPA) == 0) { ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; return 0; } } else if (ess->flags & IEEE80211_F_WEPON) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) { ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY; return 0; } } else { if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0) { ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY; return 0; } } if (ess->esslen == 0 && (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) != 0) { ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY; return 0; } return 1; } void ieee80211_switch_ess(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct _ifnet *ifp = &ic->ic_if; struct ieee80211_ess *ess, *seless = NULL; struct ieee80211_node *ni, *selni = NULL; if (!ISSET(ifp->if_flags, IFF_RUNNING)) return; /* Find the best AP matching an entry on our ESS join list. */ RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) { if ((ic->ic_flags & IEEE80211_F_DESBSSID) && !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) continue; TAILQ_FOREACH(ess, &ic->ic_ess, ess_next) { if (ieee80211_match_ess(ess, ni)) break; } if (ess == NULL) continue; /* * Operate only on ic_des_essid if auto-join is disabled. * We might have a password stored for this network. */ if (!ISSET(ic->ic_flags, IEEE80211_F_AUTO_JOIN)) { if (ic->ic_des_esslen == ni->ni_esslen && memcmp(ic->ic_des_essid, ni->ni_essid, ni->ni_esslen) == 0 && ni->ni_esslen > 0) { ieee80211_set_ess(ic, ess, ni); return; } continue; } if (selni == NULL) { seless = ess; selni = ni; continue; } if (ieee80211_ess_is_better(ic, selni, ni)) { seless = ess; selni = ni; } } if (selni && seless && !(selni->ni_esslen == ic->ic_des_esslen && (memcmp(ic->ic_des_essid, selni->ni_essid, IEEE80211_NWID_LEN) == 0))) { if (ifp->if_flags & IFF_DEBUG) { XYLog("%s: best AP %s ", ifp->if_xname, ether_sprintf(selni->ni_bssid)); ieee80211_print_essid(selni->ni_essid, selni->ni_esslen); XYLog(" score %d\n", ieee80211_ess_calculate_score(ic, selni)); XYLog("%s: switching to network ", ifp->if_xname); ieee80211_print_essid(selni->ni_essid, selni->ni_esslen); if (seless->esslen == 0) XYLog(" via join any"); XYLog("\n"); } ieee80211_set_ess(ic, seless, selni); } } void ieee80211_set_ess(struct ieee80211com *ic, struct ieee80211_ess *ess, struct ieee80211_node *ni) { memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); ic->ic_des_esslen = ni->ni_esslen; memcpy(ic->ic_des_essid, ni->ni_essid, ic->ic_des_esslen); ieee80211_disable_wep(ic); ieee80211_disable_rsn(ic); if (ess->flags & IEEE80211_F_RSNON) { explicit_bzero(ic->ic_psk, sizeof(ic->ic_psk)); memcpy(ic->ic_psk, ess->psk, sizeof(ic->ic_psk)); ic->ic_rsnprotos = ess->rsnprotos; ic->ic_rsnakms = ess->rsnakms; ic->ic_rsngroupcipher = ess->rsngroupcipher; ic->ic_rsnciphers = ess->rsnciphers; ic->ic_flags |= IEEE80211_F_RSNON; if (ess->flags & IEEE80211_F_PSK) ic->ic_flags |= IEEE80211_F_PSK; } else if (ess->flags & IEEE80211_F_WEPON) { struct ieee80211_key *k; int i; for (i = 0; i < IEEE80211_WEP_NKID; i++) { k = &ic->ic_nw_keys[i]; if (k->k_cipher != IEEE80211_CIPHER_NONE) (*ic->ic_delete_key)(ic, NULL, k); memcpy(&ic->ic_nw_keys[i], &ess->nw_keys[i], sizeof(struct ieee80211_key)); (*ic->ic_set_key)(ic, NULL, k); } ic->ic_def_txkey = ess->def_txkey; ic->ic_flags |= IEEE80211_F_WEPON; } } void ieee80211_deselect_ess(struct ieee80211com *ic) { memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); ic->ic_des_esslen = 0; ieee80211_disable_wep(ic); ieee80211_disable_rsn(ic); } void ieee80211_node_attach(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; #ifndef IEEE80211_STA_ONLY int size; #endif RB_INIT(&ic->ic_tree); ic->ic_node_alloc = ieee80211_node_alloc; ic->ic_node_free = ieee80211_node_free; ic->ic_node_copy = ieee80211_node_copy; ic->ic_node_getrssi = ieee80211_node_getrssi; ic->ic_node_checkrssi = ieee80211_node_checkrssi; ic->ic_scangen = 1; ic->ic_max_nnodes = ieee80211_cache_size; if (ic->ic_max_aid == 0) ic->ic_max_aid = IEEE80211_AID_DEF; else if (ic->ic_max_aid > IEEE80211_AID_MAX) ic->ic_max_aid = IEEE80211_AID_MAX; #ifndef IEEE80211_STA_ONLY size = howmany(ic->ic_max_aid, 32) * sizeof(u_int32_t); ic->ic_aid_bitmap = (u_int32_t *)malloc(size, 0, 0); if (ic->ic_aid_bitmap == NULL) { /* XXX no way to recover */ XYLog("%s: no memory for AID bitmap!\n", __FUNCTION__); ic->ic_max_aid = 0; } if (ic->ic_caps & (IEEE80211_C_HOSTAP | IEEE80211_C_IBSS)) { ic->ic_tim_len = howmany(ic->ic_max_aid, 8); ic->ic_tim_bitmap = (u_int8_t*)malloc(ic->ic_tim_len, 0, 0); if (ic->ic_tim_bitmap == NULL) { XYLog("%s: no memory for TIM bitmap!\n", __FUNCTION__); ic->ic_tim_len = 0; } else ic->ic_set_tim = ieee80211_set_tim; timeout_set(&ic->ic_rsn_timeout, ieee80211_gtk_rekey_timeout, ic); timeout_set(&ic->ic_inact_timeout, ieee80211_inact_timeout, ic); timeout_set(&ic->ic_node_cache_timeout, ieee80211_node_cache_timeout, ic); } #endif TAILQ_INIT(&ic->ic_ess); } struct ieee80211_node * ieee80211_alloc_node_helper(struct ieee80211com *ic) { struct ieee80211_node *ni; if (ic->ic_nnodes >= ic->ic_max_nnodes) ieee80211_clean_nodes(ic, 0); if (ic->ic_nnodes >= ic->ic_max_nnodes) return NULL; ni = (*ic->ic_node_alloc)(ic); return ni; } void ieee80211_node_lateattach(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ieee80211_node *ni; ni = ieee80211_alloc_node_helper(ic); if (ni == NULL) panic("unable to setup inital BSS node"); ni->ni_chan = IEEE80211_CHAN_ANYC; ic->ic_bss = ieee80211_ref_node(ni); ic->ic_txpower = IEEE80211_TXPOWER_MAX; #ifndef IEEE80211_STA_ONLY mq_init(&ni->ni_savedq, IEEE80211_PS_MAX_QUEUE, IPL_NET); #endif } void ieee80211_node_detach(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = (struct ieee80211com *)ifp; if (ic->ic_bss != NULL) { (*ic->ic_node_free)(ic, ic->ic_bss); ic->ic_bss = NULL; } ieee80211_del_ess(ic, NULL, 0, 1); ieee80211_free_allnodes(ic, 1); #ifndef IEEE80211_STA_ONLY free(ic->ic_aid_bitmap); free(ic->ic_tim_bitmap); timeout_del(&ic->ic_inact_timeout); timeout_free(&ic->ic_inact_timeout); timeout_del(&ic->ic_node_cache_timeout); timeout_free(&ic->ic_node_cache_timeout); timeout_del(&ic->ic_tkip_micfail_timeout); timeout_free(&ic->ic_tkip_micfail_timeout); #endif timeout_del(&ic->ic_rsn_timeout); timeout_free(&ic->ic_rsn_timeout); } /* * AP scanning support. */ /* * Initialize the active channel set based on the set * of available channels and the current PHY mode. */ void ieee80211_reset_scan(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = (struct ieee80211com *)ifp; memcpy(ic->ic_chan_scan, ic->ic_chan_active, sizeof(ic->ic_chan_active)); /* NB: hack, setup so next_scan starts with the first channel */ if (ic->ic_bss != NULL && ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC) ic->ic_bss->ni_chan = &ic->ic_channels[IEEE80211_CHAN_MAX]; } /* * Increase a node's inactivity counter. * This counter get reset to zero if a frame is received. * This function is intended for station mode only. * See ieee80211_node_cache_timeout() for hostap mode. */ void ieee80211_node_raise_inact(void *arg, struct ieee80211_node *ni) { if (ni->ni_refcnt == 0 && ni->ni_inact < IEEE80211_INACT_SCAN) ni->ni_inact++; } /* * Begin an active scan. */ void ieee80211_begin_scan(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = (struct ieee80211com *)ifp; /* * In all but hostap mode scanning starts off in * an active mode before switching to passive. */ #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_HOSTAP) #endif { ic->ic_flags |= IEEE80211_F_ASCAN; ic->ic_stats.is_scan_active++; } #ifndef IEEE80211_STA_ONLY else ic->ic_stats.is_scan_passive++; #endif if (ifp->if_flags & IFF_DEBUG) XYLog("%s: begin %s scan\n", ifp->if_xname, (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); if (ic->ic_opmode == IEEE80211_M_STA) { ieee80211_node_cleanup(ic, ic->ic_bss); ieee80211_iterate_nodes(ic, ieee80211_node_raise_inact, NULL); } /* * Reset the current mode. Setting the current mode will also * reset scan state. */ if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ic->ic_curmode = IEEE80211_MODE_AUTO; ieee80211_setmode(ic, (enum ieee80211_phymode)ic->ic_curmode); ic->ic_scan_count = 0; /* Scan the next channel. */ ieee80211_next_scan(ifp); } /* * Switch to the next channel marked for scanning. */ void ieee80211_next_scan(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ieee80211_channel *chan; chan = ic->ic_bss->ni_chan; for (;;) { if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX]) chan = &ic->ic_channels[0]; if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) { /* * Ignore channels marked passive-only * during an active scan. */ if ((ic->ic_flags & IEEE80211_F_ASCAN) == 0 || (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) break; } if (chan == ic->ic_bss->ni_chan) { ieee80211_end_scan(ifp); return; } } clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan)); DPRINTF(("chan %d->%d\n", ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan), ieee80211_chan2ieee(ic, chan))); ic->ic_bss->ni_chan = chan; ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); } #ifndef IEEE80211_STA_ONLY void ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan) { XYLog("%s\n", __FUNCTION__); struct ieee80211_node *ni; struct _ifnet *ifp = &ic->ic_if; ni = ic->ic_bss; if (ifp->if_flags & IFF_DEBUG) XYLog("%s: creating ibss\n", ifp->if_xname); ic->ic_flags |= IEEE80211_F_SIBSS; ni->ni_chan = chan; ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; ni->ni_txrate = 0; IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr); IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); if (ic->ic_opmode == IEEE80211_M_IBSS) { if ((ic->ic_flags & IEEE80211_F_DESBSSID) != 0) IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_des_bssid); else ni->ni_bssid[0] |= 0x02; /* local bit for IBSS */ } ni->ni_esslen = ic->ic_des_esslen; memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); ni->ni_rssi = 0; ni->ni_rstamp = 0; memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp)); ni->ni_intval = ic->ic_lintval; ni->ni_capinfo = IEEE80211_CAPINFO_IBSS; if (ic->ic_flags & IEEE80211_F_WEPON) ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; if (ic->ic_flags & IEEE80211_F_HTON) { const struct ieee80211_edca_ac_params *ac_qap; struct ieee80211_edca_ac_params *ac; int aci; /* * Configure HT protection. This will be updated later * based on the number of non-HT nodes in the node cache. */ ic->ic_protmode = IEEE80211_PROT_NONE; ni->ni_htop1 = IEEE80211_HTPROT_NONE; /* Disallow Greenfield mode. None of our drivers support it. */ ni->ni_htop1 |= IEEE80211_HTOP1_NONGF_STA; if (ic->ic_updateprot) ic->ic_updateprot(ic); /* Configure QoS EDCA parameters. */ for (aci = 0; aci < EDCA_NUM_AC; aci++) { ac = &ic->ic_edca_ac[aci]; ac_qap = &ieee80211_qap_edca_table[ic->ic_curmode][aci]; ac->ac_acm = ac_qap->ac_acm; ac->ac_aifsn = ac_qap->ac_aifsn; ac->ac_ecwmin = ac_qap->ac_ecwmin; ac->ac_ecwmax = ac_qap->ac_ecwmax; ac->ac_txoplimit = ac_qap->ac_txoplimit; } if (ic->ic_updateedca) (*ic->ic_updateedca)(ic); } if (ic->ic_flags & IEEE80211_F_RSNON) { struct ieee80211_key *k; /* initialize 256-bit global key counter to a random value */ arc4random_buf(ic->ic_globalcnt, EAPOL_KEY_NONCE_LEN); ni->ni_rsnprotos = ic->ic_rsnprotos; ni->ni_rsnakms = ic->ic_rsnakms; ni->ni_rsnciphers = ic->ic_rsnciphers; ni->ni_rsngroupcipher = ic->ic_rsngroupcipher; ni->ni_rsngroupmgmtcipher = ic->ic_rsngroupmgmtcipher; ni->ni_rsncaps = 0; if (ic->ic_caps & IEEE80211_C_MFP) { ni->ni_rsncaps |= IEEE80211_RSNCAP_MFPC; if (ic->ic_flags & IEEE80211_F_MFPR) ni->ni_rsncaps |= IEEE80211_RSNCAP_MFPR; } ic->ic_def_txkey = 1; ic->ic_flags &= ~IEEE80211_F_COUNTERM; k = &ic->ic_nw_keys[ic->ic_def_txkey]; memset(k, 0, sizeof(*k)); k->k_id = ic->ic_def_txkey; k->k_cipher = ni->ni_rsngroupcipher; k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX; k->k_len = ieee80211_cipher_keylen(k->k_cipher); arc4random_buf(k->k_key, k->k_len); (*ic->ic_set_key)(ic, ni, k); /* XXX */ if (ic->ic_caps & IEEE80211_C_MFP) { ic->ic_igtk_kid = 4; k = &ic->ic_nw_keys[ic->ic_igtk_kid]; memset(k, 0, sizeof(*k)); k->k_id = ic->ic_igtk_kid; k->k_cipher = ni->ni_rsngroupmgmtcipher; k->k_flags = IEEE80211_KEY_IGTK | IEEE80211_KEY_TX; k->k_len = 16; arc4random_buf(k->k_key, k->k_len); (*ic->ic_set_key)(ic, ni, k); /* XXX */ } /* * In HostAP mode, multicast traffic is sent using ic_bss * as the Tx node, so mark our node as valid so we can send * multicast frames using the group key we've just configured. */ ni->ni_port_valid = 1; ni->ni_flags |= IEEE80211_NODE_TXPROT; /* schedule a GTK/IGTK rekeying after 3600s */ timeout_add_sec(&ic->ic_rsn_timeout, 3600); } timeout_add_sec(&ic->ic_inact_timeout, IEEE80211_INACT_WAIT); timeout_add_sec(&ic->ic_node_cache_timeout, IEEE80211_CACHE_WAIT); ieee80211_new_state(ic, IEEE80211_S_RUN, -1); } #endif /* IEEE80211_STA_ONLY */ int ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni, int bgscan) { u_int8_t rate; int fail; fail = 0; if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0 && isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) fail |= IEEE80211_NODE_ASSOCFAIL_CHAN; if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && ni->ni_chan != ic->ic_des_chan) fail |= IEEE80211_NODE_ASSOCFAIL_CHAN; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) fail |= IEEE80211_NODE_ASSOCFAIL_IBSS; } else #endif { if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) fail |= IEEE80211_NODE_ASSOCFAIL_IBSS; } if (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON)) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY; } else { if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) fail |= IEEE80211_NODE_ASSOCFAIL_PRIVACY; } rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO); if (rate & IEEE80211_RATE_BASIC) fail |= IEEE80211_NODE_ASSOCFAIL_BASIC_RATE; if (ISSET(ic->ic_flags, IEEE80211_F_AUTO_JOIN) && ic->ic_des_esslen == 0) fail |= IEEE80211_NODE_ASSOCFAIL_ESSID; if (ic->ic_des_esslen != 0 && (ni->ni_esslen != ic->ic_des_esslen || memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) fail |= IEEE80211_NODE_ASSOCFAIL_ESSID; if ((ic->ic_flags & IEEE80211_F_DESBSSID) && !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) fail |= IEEE80211_NODE_ASSOCFAIL_BSSID; if (ic->ic_flags & IEEE80211_F_RSNON) { /* * If at least one RSN IE field from the AP's RSN IE fails * to overlap with any value the STA supports, the STA shall * decline to associate with that AP. */ if ((ni->ni_rsnprotos & ic->ic_rsnprotos) == 0) fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; if ((ni->ni_rsnakms & ic->ic_rsnakms) == 0) fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; if ((ni->ni_rsnakms & ic->ic_rsnakms & ~(IEEE80211_AKM_PSK | IEEE80211_AKM_SHA256_PSK)) == 0) { /* AP only supports PSK AKMPs */ if (!(ic->ic_flags & IEEE80211_F_PSK)) fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; } if (ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP40 && ni->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP && ni->ni_rsngroupcipher != IEEE80211_CIPHER_CCMP && ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP104) fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; if ((ni->ni_rsnciphers & ic->ic_rsnciphers) == 0) fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; /* we only support BIP as the IGTK cipher */ if ((ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC) && ni->ni_rsngroupmgmtcipher != IEEE80211_CIPHER_BIP) fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; /* we do not support MFP but AP requires it */ if (!(ic->ic_caps & IEEE80211_C_MFP) && (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPR)) fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; /* we require MFP but AP does not support it */ if ((ic->ic_caps & IEEE80211_C_MFP) && (ic->ic_flags & IEEE80211_F_MFPR) && !(ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC)) fail |= IEEE80211_NODE_ASSOCFAIL_WPA_PROTO; } if (ic->ic_if.if_flags & IFF_DEBUG && ieee80211_debug) { XYLog("%s: %c %s%c %3d%c %+4d %2dM%c %4s%c %7s%c %3s%c %.*s %s\n", ic->ic_if.if_xname, fail ? '-' : '+', ether_sprintf(ni->ni_bssid), fail & IEEE80211_NODE_ASSOCFAIL_BSSID ? '!' : ' ', ieee80211_chan2ieee(ic, ni->ni_chan), fail & IEEE80211_NODE_ASSOCFAIL_CHAN ? '!' : ' ', ni->ni_rssi, (rate & IEEE80211_RATE_VAL) / 2, fail & IEEE80211_NODE_ASSOCFAIL_BASIC_RATE ? '!' : ' ', (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : "????", fail & IEEE80211_NODE_ASSOCFAIL_IBSS ? '!' : ' ', (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "privacy" : "no", fail & IEEE80211_NODE_ASSOCFAIL_PRIVACY ? '!' : ' ', (ic->ic_flags & IEEE80211_F_RSNON) ? "rsn" : "no", fail & IEEE80211_NODE_ASSOCFAIL_WPA_PROTO ? '!' : ' ', ni->ni_esslen + 1, ni->ni_essid, fail & IEEE80211_NODE_ASSOCFAIL_ESSID ? "!" : ""); } /* We don't care about unrelated networks during background scans. */ if (bgscan) { if ((fail & IEEE80211_NODE_ASSOCFAIL_ESSID) == 0) ni->ni_assoc_fail = fail; } else ni->ni_assoc_fail = fail; if ((fail & IEEE80211_NODE_ASSOCFAIL_ESSID) == 0) ic->ic_bss->ni_assoc_fail = ni->ni_assoc_fail; return fail; } struct ieee80211_node_switch_bss_arg { u_int8_t cur_macaddr[IEEE80211_ADDR_LEN]; u_int8_t sel_macaddr[IEEE80211_ADDR_LEN]; }; /* Implements ni->ni_unref_cb(). */ void ieee80211_node_switch_bss(struct ieee80211com *ic, struct ieee80211_node *ni) { struct _ifnet *ifp = &ic->ic_if; struct ieee80211_node_switch_bss_arg *sba = (struct ieee80211_node_switch_bss_arg *)ni->ni_unref_arg; struct ieee80211_node *curbs, *selbs; splassert(IPL_NET); if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0) { free(sba); return; } ic->ic_xflags &= ~IEEE80211_F_TX_MGMT_ONLY; selbs = ieee80211_find_node(ic, sba->sel_macaddr); if (selbs == NULL) { free(sba); ic->ic_flags &= ~IEEE80211_F_BGSCAN; ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return; } curbs = ieee80211_find_node(ic, sba->cur_macaddr); if (curbs == NULL) { free(sba); ic->ic_flags &= ~IEEE80211_F_BGSCAN; ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return; } if (ifp->if_flags & IFF_DEBUG) { XYLog("%s: roaming from %s chan %d ", ifp->if_xname, ether_sprintf(curbs->ni_macaddr), ieee80211_chan2ieee(ic, curbs->ni_chan)); XYLog("to %s chan %d\n", ether_sprintf(selbs->ni_macaddr), ieee80211_chan2ieee(ic, selbs->ni_chan)); } ieee80211_node_newstate(curbs, IEEE80211_STA_CACHE); ieee80211_node_join_bss(ic, selbs); /* frees arg and ic->ic_bss */ } void ieee80211_node_join_bss(struct ieee80211com *ic, struct ieee80211_node *selbs, int force_reauth) { XYLog("%s selbs=%s mac=%s chan=%d rssi=%d protos=%d akms=%d ciphers=%d\n", __FUNCTION__, selbs->ni_essid, ether_sprintf(selbs->ni_bssid), ieee80211_chan2ieee(ic, selbs->ni_chan), selbs->ni_rssi, selbs->ni_rsnprotos, selbs->ni_rsnakms, selbs->ni_rsnciphers); enum ieee80211_phymode mode; struct ieee80211_node *ni; uint32_t assoc_fail = 0; /* Reinitialize media mode and channels if needed. */ mode = ieee80211_chan2mode(ic, selbs->ni_chan); if (mode != ic->ic_curmode) ieee80211_setmode(ic, mode); /* Keep recorded association failures for this BSS/ESS intact. */ if (IEEE80211_ADDR_EQ(ic->ic_bss->ni_macaddr, selbs->ni_macaddr) || (ic->ic_des_esslen > 0 && ic->ic_des_esslen == selbs->ni_esslen && memcmp(ic->ic_des_essid, selbs->ni_essid, selbs->ni_esslen) == 0)) assoc_fail = ic->ic_bss->ni_assoc_fail; (*ic->ic_node_copy)(ic, ic->ic_bss, selbs); ni = ic->ic_bss; ni->ni_assoc_fail |= assoc_fail; ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan); /* Make sure we send valid rates in an association request. */ if (ic->ic_opmode == IEEE80211_M_STA) ieee80211_fix_rate(ic, ni, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (ic->ic_flags & IEEE80211_F_RSNON) ieee80211_choose_rsnparams(ic); else if (ic->ic_flags & IEEE80211_F_WEPON) ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP; ieee80211_node_newstate(selbs, IEEE80211_STA_BSS); #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS) { ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (ni->ni_rates.rs_nrates == 0) { ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return; } ieee80211_new_state(ic, IEEE80211_S_RUN, -1); } else #endif { int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) && ic->ic_opmode == IEEE80211_M_STA && ic->ic_state == IEEE80211_S_RUN); int roamscan = bgscan && (ic->ic_flags & IEEE80211_F_DISABLE_BG_AUTO_CONNECT) == 0; int auth_next = (ic->ic_opmode == IEEE80211_M_STA && ic->ic_state == IEEE80211_S_AUTH); int mgt = -1; XYLog("%s ic_state=%d\n", __FUNCTION__, ic->ic_state); timeout_del(&ic->ic_bgscan_timeout); ic->ic_flags &= ~IEEE80211_F_BGSCAN; if (!force_reauth) { /* * After a background scan, we have now switched APs. * Pretend we were just de-authed, which makes * ieee80211_new_state() try to re-auth and thus send * an AUTH frame to our newly selected AP. */ if (roamscan) mgt = IEEE80211_FC0_SUBTYPE_DEAUTH; /* * If we are trying another AP after the previous one * failed (state transition AUTH->AUTH), ensure that * ieee80211_new_state() tries to send another auth frame. */ else if (auth_next) mgt = IEEE80211_FC0_SUBTYPE_AUTH; } else { mgt = IEEE80211_FC0_SUBTYPE_DEAUTH; } ieee80211_new_state(ic, IEEE80211_S_AUTH, mgt); } } struct ieee80211_node * ieee80211_node_choose_bss(struct ieee80211com *ic, int bgscan, struct ieee80211_node **curbs) { XYLog("%s\n", __FUNCTION__); struct ieee80211_node *ni, *nextbs, *selbs = NULL, *selbs2 = NULL, *selbs5 = NULL; uint8_t min_5ghz_rssi; ni = RB_MIN(ieee80211_tree, &ic->ic_tree); for (; ni != NULL; ni = nextbs) { nextbs = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); if (ni->ni_fails) { /* * The configuration of the access points may change * during my scan. So delete the entry for the AP * and retry to associate if there is another beacon. */ if (ni->ni_fails++ > 2) ieee80211_free_node(ic, ni); DPRINTF(("%s %s ni->ni_fails=%d\n", __FUNCTION__, ni->ni_essid, ni->ni_fails)); continue; } if (curbs && ieee80211_node_cmp(ic->ic_bss, ni) == 0) *curbs = ni; int fail = ieee80211_match_bss(ic, ni, bgscan); if (fail != 0) { DPRINTF(("%s ieee80211_match_bss==FALSE, ssid=%s, bssid=%s, %d\n", __FUNCTION__, ni->ni_essid, ether_sprintf(ni->ni_bssid), fail)); continue; } if (ic->ic_caps & IEEE80211_C_SCANALLBAND) { if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) && (selbs2 == NULL || ni->ni_rssi > selbs2->ni_rssi)) selbs2 = ni; else if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) && (selbs5 == NULL || ni->ni_rssi > selbs5->ni_rssi)) selbs5 = ni; } else if (selbs == NULL || ni->ni_rssi > selbs->ni_rssi) selbs = ni; } if (ic->ic_max_rssi) min_5ghz_rssi = IEEE80211_RSSI_THRES_RATIO_5GHZ; else min_5ghz_rssi = (uint8_t)IEEE80211_RSSI_THRES_5GHZ; /* * Prefer a 5Ghz AP even if its RSSI is weaker than the best 2Ghz AP * (as long as it meets the minimum RSSI threshold) since the 5Ghz band * is usually less saturated. */ if (selbs5 != NULL) { XYLog("%s 5ghz ssid=%s mac=%s rssi=%d\n", __FUNCTION__, selbs5->ni_essid, ether_sprintf(selbs5->ni_bssid), selbs5->ni_rssi); } if (selbs2 != NULL) { XYLog("%s 2ghz ssid=%s mac=%s rssi=%d\n", __FUNCTION__, selbs2->ni_essid, ether_sprintf(selbs2->ni_bssid), selbs2->ni_rssi); } if (selbs5 && (*ic->ic_node_checkrssi)(ic, selbs5)) selbs = selbs5; else if (selbs5 && selbs2) selbs = (selbs5->ni_rssi >= selbs2->ni_rssi ? selbs5 : selbs2); else if (selbs2) selbs = selbs2; else if (selbs5) selbs = selbs5; return selbs; } /* * Complete a scan of potential channels. */ void ieee80211_end_scan(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ieee80211_node *ni, *selbs = NULL, *curbs = NULL; int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) && ic->ic_opmode == IEEE80211_M_STA && ic->ic_state == IEEE80211_S_RUN); int roamscan = bgscan && (ic->ic_flags & IEEE80211_F_DISABLE_BG_AUTO_CONNECT) == 0; if (ic->ic_event_handler) (*ic->ic_event_handler)(ic, IEEE80211_EVT_SCAN_DONE, NULL); if (ifp->if_flags & IFF_DEBUG) XYLog("%s: end %s scan\n", ifp->if_xname, bgscan ? (roamscan ? "roam" : "background") : ((ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive")); if (ic->ic_scan_count) ic->ic_flags &= ~IEEE80211_F_ASCAN; if (ic->ic_opmode == IEEE80211_M_STA) ieee80211_clean_inactive_nodes(ic, IEEE80211_INACT_SCAN); ni = RB_MIN(ieee80211_tree, &ic->ic_tree); #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* XXX off stack? */ u_char occupied[howmany(IEEE80211_CHAN_MAX, NBBY)]; int i, fail; /* * The passive scan to look for existing AP's completed, * select a channel to camp on. Identify the channels * that already have one or more AP's and try to locate * an unoccupied one. If that fails, pick a random * channel from the active set. */ memset(occupied, 0, sizeof(occupied)); RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan)); for (i = 0; i < IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i) && isclr(occupied, i)) break; if (i == IEEE80211_CHAN_MAX) { fail = arc4random() & 3; /* random 0-3 */ for (i = 0; i < IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i) && fail-- == 0) break; } ieee80211_create_ibss(ic, &ic->ic_channels[i]); return; } #endif if (ni == NULL) { DPRINTF(("no scan candidate\n")); notfound: #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS && (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen != 0) { ieee80211_create_ibss(ic, ic->ic_ibss_chan); return; } #endif if (ic->ic_state != IEEE80211_S_RUN) { /* * Reset the list of channels to scan and scan the next mode * if nothing has been found. * If the device scans all bands in one fell swoop, return * current scan results to userspace regardless of mode. * This will loop forever until an access point is found. */ ieee80211_reset_scan(ifp); if (ieee80211_next_mode(ifp) == IEEE80211_MODE_AUTO || (ic->ic_caps & IEEE80211_C_SCANALLBAND)) ic->ic_scan_count++; ieee80211_next_scan(ifp); } return; } /* Possibly switch which ssid we are associated with */ if (!bgscan && ic->ic_opmode == IEEE80211_M_STA) ieee80211_switch_ess(ic); selbs = ieee80211_node_choose_bss(ic, bgscan, &curbs); if (bgscan) { struct ieee80211_node_switch_bss_arg *arg; ic->ic_flags &= ~IEEE80211_F_DISABLE_BG_AUTO_CONNECT; if (!roamscan) { ic->ic_flags &= ~IEEE80211_F_BGSCAN; return; } /* AP disappeared? Should not happen. */ if (selbs == NULL || curbs == NULL) { ic->ic_flags &= ~IEEE80211_F_BGSCAN; XYLog("%s %d AP disappeared? Should not happen.\n", __FUNCTION__, __LINE__); goto notfound; } /* * After a background scan we might end up choosing the * same AP again. Do not change ic->ic_bss in this case, * and make background scans less frequent. */ if (selbs == curbs) { if (ic->ic_bgscan_fail < IEEE80211_BGSCAN_FAIL_MAX) ic->ic_bgscan_fail++; ic->ic_flags &= ~IEEE80211_F_BGSCAN; /* * HT is negotiated during association so we must use * ic_bss to check HT. The nodes tree was re-populated * during background scan and therefore selbs and curbs * may not carry HT information. */ ni = ic->ic_bss; if (ni->ni_flags & IEEE80211_NODE_HE) ieee80211_setmode(ic, IEEE80211_MODE_11AX); else if (ni->ni_flags & IEEE80211_NODE_VHT) ieee80211_setmode(ic, IEEE80211_MODE_11AC); else if (ni->ni_flags & IEEE80211_NODE_HT) ieee80211_setmode(ic, IEEE80211_MODE_11N); else ieee80211_setmode(ic, ieee80211_chan2mode(ic, ni->ni_chan)); return; } arg = (struct ieee80211_node_switch_bss_arg *)malloc(sizeof(*arg), 0, 0); if (arg == NULL) { ic->ic_flags &= ~IEEE80211_F_BGSCAN; return; } ic->ic_bgscan_fail = 0; /* * We are going to switch APs. Stop A-MPDU Tx and * queue a de-auth frame addressed to our current AP. */ ieee80211_stop_ampdu_tx(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_DEAUTH); if (IEEE80211_SEND_MGMT(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE) != 0) { ic->ic_flags &= ~IEEE80211_F_BGSCAN; free(arg); return; } /* Prevent dispatch of additional data frames to hardware. */ ic->ic_xflags |= IEEE80211_F_TX_MGMT_ONLY; /* * Install a callback which will switch us to the new AP once * all dispatched frames have been processed by hardware. */ IEEE80211_ADDR_COPY(arg->cur_macaddr, curbs->ni_macaddr); IEEE80211_ADDR_COPY(arg->sel_macaddr, selbs->ni_macaddr); ic->ic_bss->ni_unref_arg = arg; ic->ic_bss->ni_unref_arg_size = sizeof(*arg); ic->ic_bss->ni_unref_cb = ieee80211_node_switch_bss; /* F_BGSCAN flag gets cleared in ieee80211_node_join_bss(). */ return; } else if (selbs == NULL) goto notfound; ieee80211_node_join_bss(ic, selbs); } /* * Autoselect the best RSN parameters (protocol, AKMP, pairwise cipher...) * that are supported by both peers (STA mode only). */ void ieee80211_choose_rsnparams(struct ieee80211com *ic) { struct ieee80211_node *ni = ic->ic_bss; struct ieee80211_pmk *pmk; /* filter out unsupported protocol versions */ ni->ni_rsnprotos &= ic->ic_rsnprotos; /* prefer RSN (aka WPA2) over WPA */ if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN) ni->ni_rsnprotos = IEEE80211_PROTO_RSN; else ni->ni_rsnprotos = IEEE80211_PROTO_WPA; /* filter out unsupported AKMPs */ ni->ni_rsnakms &= ic->ic_rsnakms; /* prefer SHA-256 based AKMPs */ if ((ic->ic_flags & IEEE80211_F_PSK) && (ni->ni_rsnakms & (IEEE80211_AKM_PSK | IEEE80211_AKM_SHA256_PSK))) { /* AP supports PSK AKMP and a PSK is configured */ if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_PSK) ni->ni_rsnakms = IEEE80211_AKM_SHA256_PSK; else ni->ni_rsnakms = IEEE80211_AKM_PSK; } else { if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_8021X) ni->ni_rsnakms = IEEE80211_AKM_SHA256_8021X; else ni->ni_rsnakms = IEEE80211_AKM_8021X; /* check if we have a cached PMK for this AP */ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN && (pmk = ieee80211_pmksa_find(ic, ni, NULL)) != NULL) { memcpy(ni->ni_pmkid, pmk->pmk_pmkid, IEEE80211_PMKID_LEN); ni->ni_flags |= IEEE80211_NODE_PMKID; } } /* filter out unsupported pairwise ciphers */ ni->ni_rsnciphers &= ic->ic_rsnciphers; /* prefer CCMP over TKIP */ if (ni->ni_rsnciphers & IEEE80211_CIPHER_CCMP) ni->ni_rsnciphers = IEEE80211_CIPHER_CCMP; else ni->ni_rsnciphers = IEEE80211_CIPHER_TKIP; ni->ni_rsncipher = (enum ieee80211_cipher)ni->ni_rsnciphers; /* use MFP if we both support it */ if ((ic->ic_caps & IEEE80211_C_MFP) && (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC)) ni->ni_flags |= IEEE80211_NODE_MFP; } int ieee80211_get_rate(struct ieee80211com *ic) { u_int8_t (*rates)[IEEE80211_RATE_MAXSIZE]; int rate; rates = &ic->ic_bss->ni_rates.rs_rates; if (ic->ic_fixed_rate != -1) rate = (*rates)[ic->ic_fixed_rate]; else if (ic->ic_state == IEEE80211_S_RUN) rate = (*rates)[ic->ic_bss->ni_txrate]; else rate = 0; return rate & IEEE80211_RATE_VAL; } struct ieee80211_node * ieee80211_node_alloc(struct ieee80211com *ic) { return (struct ieee80211_node *)malloc(sizeof(struct ieee80211_node), 0, 0); } void ieee80211_node_cleanup(struct ieee80211com *ic, struct ieee80211_node *ni) { if (ni == NULL) { return; } if (ni->ni_rsnie != NULL) { free(ni->ni_rsnie); ni->ni_rsnie = NULL; } if (ni->ni_rsnie_tlv != NULL && ni->ni_rsnie_tlv_len > 0) { free(ni->ni_rsnie_tlv); ni->ni_rsnie_tlv = NULL; ni->ni_rsnie_tlv_len = 0; } ieee80211_ba_del(ni); ieee80211_ba_free(ni); if (ni->ni_unref_arg != NULL) { free(ni->ni_unref_arg); ni->ni_unref_arg = NULL; ni->ni_unref_arg_size = 0; } #ifndef IEEE80211_STA_ONLY mq_purge(&ni->ni_savedq); #endif } void ieee80211_node_free(struct ieee80211com *ic, struct ieee80211_node *ni) { ieee80211_node_cleanup(ic, ni); free(ni); } void ieee80211_node_copy(struct ieee80211com *ic, struct ieee80211_node *dst, const struct ieee80211_node *src) { ieee80211_node_cleanup(ic, dst); *dst = *src; dst->ni_rsnie = NULL; if (src->ni_rsnie != NULL) ieee80211_save_ie(src->ni_rsnie, &dst->ni_rsnie); dst->ni_rsnie_tlv = NULL; dst->ni_rsnie_tlv_len = 0; if (src->ni_rsnie_tlv != NULL) { ieee80211_save_ie_tlv(src->ni_rsnie_tlv, &dst->ni_rsnie_tlv, &dst->ni_rsnie_tlv_len, src->ni_rsnie_tlv_len); } ieee80211_node_set_timeouts(dst); #ifndef IEEE80211_STA_ONLY mq_init(&dst->ni_savedq, IEEE80211_PS_MAX_QUEUE, IPL_NET); #endif } u_int8_t ieee80211_node_getrssi(struct ieee80211com *ic, const struct ieee80211_node *ni) { return ni->ni_rssi; } int ieee80211_node_checkrssi(struct ieee80211com *ic, const struct ieee80211_node *ni) { uint8_t thres; if (ni->ni_chan == IEEE80211_CHAN_ANYC) return 0; if (ic->ic_max_rssi) { thres = (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) ? IEEE80211_RSSI_THRES_RATIO_2GHZ : IEEE80211_RSSI_THRES_RATIO_5GHZ; return ((ni->ni_rssi * 100) / ic->ic_max_rssi >= thres); } thres = (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) ? IEEE80211_RSSI_THRES_2GHZ : IEEE80211_RSSI_THRES_5GHZ; return (ni->ni_rssi >= (u_int8_t)thres); } void ieee80211_node_set_timeouts(struct ieee80211_node *ni) { int i; memset(ni->ni_addba_req_to, 0, sizeof(ni->ni_addba_req_to) * nitems(ni->ni_addba_req_to)); #ifndef IEEE80211_STA_ONLY timeout_set(&ni->ni_eapol_to, ieee80211_eapol_timeout, ni); timeout_set(&ni->ni_sa_query_to, ieee80211_sa_query_timeout, ni); #endif timeout_set(&ni->ni_addba_req_to[EDCA_AC_BE], ieee80211_node_addba_request_ac_be_to, ni); timeout_set(&ni->ni_addba_req_to[EDCA_AC_BK], ieee80211_node_addba_request_ac_bk_to, ni); timeout_set(&ni->ni_addba_req_to[EDCA_AC_VI], ieee80211_node_addba_request_ac_vi_to, ni); timeout_set(&ni->ni_addba_req_to[EDCA_AC_VO], ieee80211_node_addba_request_ac_vo_to, ni); for (i = 0; i < nitems(ni->ni_addba_req_intval); i++) ni->ni_addba_req_intval[i] = 1; } void ieee80211_setup_node(struct ieee80211com *ic, struct ieee80211_node *ni, const u_int8_t *macaddr) { int i, s; DPRINTF(("%s %s\n", __FUNCTION__, ether_sprintf((u_int8_t *)macaddr))); IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); ieee80211_node_newstate(ni, IEEE80211_STA_CACHE); ni->ni_ic = ic; /* back-pointer */ /* Initialize cached last sequence numbers with invalid values. */ ni->ni_rxseq = 0xffffU; for (i=0; i < IEEE80211_NUM_TID; ++i) ni->ni_qos_rxseqs[i] = 0xffffU; #ifndef IEEE80211_STA_ONLY mq_init(&ni->ni_savedq, IEEE80211_PS_MAX_QUEUE, IPL_NET); #endif ieee80211_node_set_timeouts(ni); s = splnet(); RB_INSERT(ieee80211_tree, &ic->ic_tree, ni); ic->ic_nnodes++; splx(s); } struct ieee80211_node * ieee80211_alloc_node(struct ieee80211com *ic, const u_int8_t *macaddr) { struct ieee80211_node *ni = ieee80211_alloc_node_helper(ic); if (ni != NULL) ieee80211_setup_node(ic, ni, macaddr); else ic->ic_stats.is_rx_nodealloc++; return ni; } struct ieee80211_node * ieee80211_dup_bss(struct ieee80211com *ic, const u_int8_t *macaddr) { XYLog("%s %d\n", __FUNCTION__, __LINE__); struct ieee80211_node *ni = ieee80211_alloc_node_helper(ic); if (ni != NULL) { ieee80211_setup_node(ic, ni, macaddr); /* * Inherit from ic_bss. */ IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); ni->ni_chan = ic->ic_bss->ni_chan; } else ic->ic_stats.is_rx_nodealloc++; return ni; } struct ieee80211_node * ieee80211_find_node(struct ieee80211com *ic, const u_int8_t *macaddr) { struct ieee80211_node *ni; int cmp; /* similar to RBT_FIND except we compare keys, not nodes */ ni = RB_ROOT(&ic->ic_tree); while (ni != NULL) { cmp = memcmp(macaddr, ni->ni_macaddr, IEEE80211_ADDR_LEN); if (cmp < 0) ni = RB_LEFT(ni, ni_node); else if (cmp > 0) ni = RB_RIGHT(ni, ni_node); else break; } return ni; } /* * Return a reference to the appropriate node for sending * a data frame. This handles node discovery in adhoc networks. * * Drivers will call this, so increase the reference count before * returning the node. */ struct ieee80211_node * ieee80211_find_txnode(struct ieee80211com *ic, const u_int8_t *macaddr) { #ifndef IEEE80211_STA_ONLY struct ieee80211_node *ni; int s; #endif /* * The destination address should be in the node table * unless we are operating in station mode or this is a * multicast/broadcast frame. */ if (ic->ic_opmode == IEEE80211_M_STA || IEEE80211_IS_MULTICAST(macaddr)) return ieee80211_ref_node(ic->ic_bss); #ifndef IEEE80211_STA_ONLY s = splnet(); ni = ieee80211_find_node(ic, macaddr); splx(s); if (ni == NULL) { if (ic->ic_opmode != IEEE80211_M_IBSS && ic->ic_opmode != IEEE80211_M_AHDEMO) return NULL; /* * Fake up a node; this handles node discovery in * adhoc mode. Note that for the driver's benefit * we we treat this like an association so the driver * has an opportunity to setup its private state. * * XXX need better way to handle this; issue probe * request so we can deduce rate set, etc. */ if ((ni = ieee80211_dup_bss(ic, macaddr)) == NULL) return NULL; /* XXX no rate negotiation; just dup */ ni->ni_rates = ic->ic_bss->ni_rates; ni->ni_txrate = 0; if (ic->ic_newassoc) (*ic->ic_newassoc)(ic, ni, 1); } return ieee80211_ref_node(ni); #else return NULL; /* can't get there */ #endif /* IEEE80211_STA_ONLY */ } /* * It is usually desirable to process a Rx packet using its sender's * node-record instead of the BSS record. * * - AP mode: keep a node-record for every authenticated/associated * station *in the BSS*. For future use, we also track neighboring * APs, since they might belong to the same ESS. APs in the same * ESS may bridge packets to each other, forming a Wireless * Distribution System (WDS). * * - IBSS mode: keep a node-record for every station *in the BSS*. * Also track neighboring stations by their beacons/probe responses. * * - monitor mode: keep a node-record for every sender, regardless * of BSS. * * - STA mode: the only available node-record is the BSS record, * ic->ic_bss. * * Of all the 802.11 Control packets, only the node-records for * RTS packets node-record can be looked up. * * Return non-zero if the packet's node-record is kept, zero * otherwise. */ static __inline int ieee80211_needs_rxnode(struct ieee80211com *ic, const struct ieee80211_frame *wh, const u_int8_t **bssid) { int monitor, rc = 0; monitor = (ic->ic_opmode == IEEE80211_M_MONITOR); *bssid = NULL; switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { case IEEE80211_FC0_TYPE_CTL: if (!monitor) break; return (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_RTS; case IEEE80211_FC0_TYPE_MGT: *bssid = wh->i_addr3; switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { case IEEE80211_FC0_SUBTYPE_BEACON: case IEEE80211_FC0_SUBTYPE_PROBE_RESP: break; default: #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_STA) break; rc = IEEE80211_ADDR_EQ(*bssid, ic->ic_bss->ni_bssid) || IEEE80211_ADDR_EQ(*bssid, etherbroadcastaddr); #endif break; } break; case IEEE80211_FC0_TYPE_DATA: switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: *bssid = wh->i_addr3; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS || ic->ic_opmode == IEEE80211_M_AHDEMO) rc = IEEE80211_ADDR_EQ(*bssid, ic->ic_bss->ni_bssid); #endif break; case IEEE80211_FC1_DIR_TODS: *bssid = wh->i_addr1; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) rc = IEEE80211_ADDR_EQ(*bssid, ic->ic_bss->ni_bssid); #endif break; case IEEE80211_FC1_DIR_FROMDS: case IEEE80211_FC1_DIR_DSTODS: *bssid = wh->i_addr2; #ifndef IEEE80211_STA_ONLY rc = (ic->ic_opmode == IEEE80211_M_HOSTAP); #endif break; } break; } return monitor || rc; } /* * Drivers call this, so increase the reference count before returning * the node. */ struct ieee80211_node * ieee80211_find_rxnode(struct ieee80211com *ic, const struct ieee80211_frame *wh) { static const u_int8_t zero[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct ieee80211_node *ni; const u_int8_t *bssid; int s; if (!ieee80211_needs_rxnode(ic, wh, &bssid)) return ieee80211_ref_node(ic->ic_bss); s = splnet(); ni = ieee80211_find_node(ic, wh->i_addr2); splx(s); if (ni != NULL) return ieee80211_ref_node(ni); #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) return ieee80211_ref_node(ic->ic_bss); #endif /* XXX see remarks in ieee80211_find_txnode */ /* XXX no rate negotiation; just dup */ if ((ni = ieee80211_dup_bss(ic, wh->i_addr2)) == NULL) return ieee80211_ref_node(ic->ic_bss); IEEE80211_ADDR_COPY(ni->ni_bssid, (bssid != NULL) ? bssid : zero); ni->ni_rates = ic->ic_bss->ni_rates; ni->ni_txrate = 0; if (ic->ic_newassoc) (*ic->ic_newassoc)(ic, ni, 1); DPRINTF(("faked-up node %p for %s\n", ni, ether_sprintf((u_int8_t *)wh->i_addr2))); return ieee80211_ref_node(ni); } void ieee80211_ba_del(struct ieee80211_node *ni) { int tid; for (tid = 0; tid < nitems(ni->ni_rx_ba); tid++) { struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; if (ba->ba_state != IEEE80211_BA_INIT) { if (timeout_pending(&ba->ba_to)) timeout_del(&ba->ba_to); if (timeout_pending(&ba->ba_gap_to)) timeout_del(&ba->ba_gap_to); ba->ba_state = IEEE80211_BA_INIT; } } for (tid = 0; tid < nitems(ni->ni_tx_ba); tid++) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; if (ba->ba_state != IEEE80211_BA_INIT) { if (timeout_pending(&ba->ba_to)) timeout_del(&ba->ba_to); ba->ba_state = IEEE80211_BA_INIT; } } timeout_del(&ni->ni_addba_req_to[EDCA_AC_BE]); timeout_del(&ni->ni_addba_req_to[EDCA_AC_BK]); timeout_del(&ni->ni_addba_req_to[EDCA_AC_VI]); timeout_del(&ni->ni_addba_req_to[EDCA_AC_VO]); } void ieee80211_ba_free(struct ieee80211_node *ni) { int tid; for (tid = 0; tid < nitems(ni->ni_rx_ba); tid++) { struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; timeout_free(&ba->ba_to); timeout_free(&ba->ba_gap_to); } for (tid = 0; tid < nitems(ni->ni_tx_ba); tid++) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; timeout_free(&ba->ba_to); } timeout_free(&ni->ni_addba_req_to[EDCA_AC_BE]); timeout_free(&ni->ni_addba_req_to[EDCA_AC_BK]); timeout_free(&ni->ni_addba_req_to[EDCA_AC_VI]); timeout_free(&ni->ni_addba_req_to[EDCA_AC_VO]); } void ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni) { DPRINTF(("%s %s %s\n", __FUNCTION__, ni->ni_essid, ether_sprintf(ni->ni_bssid))); if (ni == ic->ic_bss) panic("freeing bss node"); splassert(IPL_NET); DPRINTF(("%s, %s\n", __FUNCTION__, ether_sprintf(ni->ni_macaddr))); #ifndef IEEE80211_STA_ONLY timeout_del(&ni->ni_eapol_to); timeout_free(&ni->ni_eapol_to); timeout_del(&ni->ni_sa_query_to); timeout_free(&ni->ni_sa_query_to); IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); #endif ieee80211_ba_del(ni); ieee80211_ba_free(ni); RB_REMOVE(ieee80211_tree, &ic->ic_tree, ni); ic->ic_nnodes--; #ifndef IEEE80211_STA_ONLY if (mq_purge(&ni->ni_savedq) > 0) { if (ic->ic_set_tim != NULL) (*ic->ic_set_tim)(ic, ni->ni_associd, 0); } #endif (*ic->ic_node_free)(ic, ni); /* TBD indicate to drivers that a new node can be allocated */ } void ieee80211_release_node(struct ieee80211com *ic, struct ieee80211_node *ni) { int s; DPRINTF(("%s refcnt %u\n", ether_sprintf(ni->ni_macaddr), ni->ni_refcnt)); s = splnet(); if (ieee80211_node_decref(ni) == 0) { if (ni->ni_unref_cb) { (*ni->ni_unref_cb)(ic, ni); ni->ni_unref_cb = NULL; /* Freed by callback if necessary: */ ni->ni_unref_arg = NULL; ni->ni_unref_arg_size = 0; } if (ni->ni_state == IEEE80211_STA_COLLECT) ieee80211_free_node(ic, ni); } splx(s); } void ieee80211_free_allnodes(struct ieee80211com *ic, int clear_ic_bss) { struct ieee80211_node *ni, *next_ni; int s; DPRINTF(("freeing all nodes\n")); s = splnet(); for (ni = RB_MIN(ieee80211_tree, &ic->ic_tree); ni != NULL; ni = next_ni) { next_ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); if (!clear_ic_bss && ic->ic_bss != NULL) { if (memcmp(ic->ic_bss->ni_bssid, ni->ni_bssid, IEEE80211_ADDR_LEN) == 0 && strncmp((const char *)ic->ic_bss->ni_essid, (const char *)ni->ni_essid, IEEE80211_NWID_LEN) == 0) { continue; } } ieee80211_free_node(ic, ni); } splx(s); if (clear_ic_bss && ic->ic_bss != NULL) ieee80211_node_cleanup(ic, ic->ic_bss); } void ieee80211_clean_cached(struct ieee80211com *ic) { struct ieee80211_node *ni, *next_ni; int s; s = splnet(); for (ni = RB_MIN(ieee80211_tree, &ic->ic_tree); ni != NULL; ni = next_ni) { next_ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); if (ni->ni_state == IEEE80211_STA_CACHE) ieee80211_free_node(ic, ni); } splx(s); } void ieee80211_clean_sta_bss_node(struct ieee80211com *ic) { struct ieee80211_node *ni, *next_ni; int s; s = splnet(); if (ic->ic_bss == NULL) return; for (ni = RB_MIN(ieee80211_tree, &ic->ic_tree); ni != NULL; ni = next_ni) { next_ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); if (ni->ni_state == IEEE80211_STA_BSS) { if (memcmp(ic->ic_bss->ni_bssid, ni->ni_bssid, IEEE80211_ADDR_LEN) != 0) ieee80211_node_newstate(ni, IEEE80211_STA_CACHE); } } splx(s); } /* * Timeout inactive nodes. * * If called because of a cache timeout, which happens only in hostap and ibss * modes, clean all inactive cached or authenticated nodes but don't de-auth * any associated nodes. Also update HT protection settings. * * Else, this function is called because a new node must be allocated but the * node cache is full. In this case, return as soon as a free slot was made * available. If acting as hostap, clean cached nodes regardless of their * recent activity and also allow de-authing of authenticated nodes older * than one cache wait interval, and de-authing of inactive associated nodes. */ void ieee80211_clean_nodes(struct ieee80211com *ic, int cache_timeout) { struct ieee80211_node *ni, *next_ni; u_int gen = ic->ic_scangen++; /* NB: ok 'cuz single-threaded*/ int s; #ifndef IEEE80211_STA_ONLY int nnodes = 0, nonht = 0, nonhtassoc = 0; struct _ifnet *ifp = &ic->ic_if; enum ieee80211_htprot htprot = IEEE80211_HTPROT_NONE; enum ieee80211_protmode protmode = IEEE80211_PROT_NONE; #endif s = splnet(); for (ni = RB_MIN(ieee80211_tree, &ic->ic_tree); ni != NULL; ni = next_ni) { next_ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); if (!cache_timeout && ic->ic_nnodes < ic->ic_max_nnodes) break; if (ni->ni_scangen == gen) /* previously handled */ continue; #ifndef IEEE80211_STA_ONLY nnodes++; if ((ic->ic_flags & IEEE80211_F_HTON) && cache_timeout) { /* * Check if node supports 802.11n. * Only require HT capabilities IE for this check. * Nodes might never reveal their supported MCS to us * unless they go through a full association sequence. * ieee80211_node_supports_ht() could misclassify them. */ if ((ni->ni_flags & IEEE80211_NODE_HTCAP) == 0) { nonht++; if (ni->ni_state == IEEE80211_STA_ASSOC) nonhtassoc++; } } #endif ni->ni_scangen = gen; if (ni->ni_refcnt > 0) continue; #ifndef IEEE80211_STA_ONLY if ((ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_IBSS) && ic->ic_state == IEEE80211_S_RUN) { if (cache_timeout) { if (ni->ni_state != IEEE80211_STA_COLLECT && (ni->ni_state == IEEE80211_STA_ASSOC || ni->ni_inact < IEEE80211_INACT_MAX)) continue; } else { if (ic->ic_opmode == IEEE80211_M_HOSTAP && ((ni->ni_state == IEEE80211_STA_ASSOC && ni->ni_inact < IEEE80211_INACT_MAX) || (ni->ni_state == IEEE80211_STA_AUTH && ni->ni_inact == 0))) continue; if (ic->ic_opmode == IEEE80211_M_IBSS && ni->ni_state != IEEE80211_STA_COLLECT && ni->ni_state != IEEE80211_STA_CACHE && ni->ni_inact < IEEE80211_INACT_MAX) continue; } } if (ifp->if_flags & IFF_DEBUG) XYLog("%s, %s: station %s purged from node cache\n", __FUNCTION__, ifp->if_xname, ether_sprintf(ni->ni_macaddr)); #endif /* * If we're hostap and the node is authenticated, send * a deauthentication frame. The node will be freed when * the driver calls ieee80211_release_node(). */ #ifndef IEEE80211_STA_ONLY nnodes--; if ((ic->ic_flags & IEEE80211_F_HTON) && cache_timeout) { if ((ni->ni_flags & IEEE80211_NODE_HTCAP) == 0) { nonht--; if (ni->ni_state == IEEE80211_STA_ASSOC) nonhtassoc--; } } if (ic->ic_opmode == IEEE80211_M_HOSTAP && ni->ni_state >= IEEE80211_STA_AUTH && ni->ni_state != IEEE80211_STA_COLLECT) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_EXPIRE); ieee80211_node_leave(ic, ni); } else #endif ieee80211_free_node(ic, ni); ic->ic_stats.is_node_timeout++; } #ifndef IEEE80211_STA_ONLY if ((ic->ic_flags & IEEE80211_F_HTON) && cache_timeout) { uint16_t htop1 = ic->ic_bss->ni_htop1; /* Update HT protection settings. */ if (nonht) { protmode = IEEE80211_PROT_CTSONLY; if (nonhtassoc) htprot = IEEE80211_HTPROT_NONHT_MIXED; else htprot = IEEE80211_HTPROT_NONMEMBER; } if ((htop1 & IEEE80211_HTOP1_PROT_MASK) != htprot) { htop1 &= ~IEEE80211_HTOP1_PROT_MASK; htop1 |= htprot; ic->ic_bss->ni_htop1 = htop1; ic->ic_protmode = protmode; if (ic->ic_updateprot) ic->ic_updateprot(ic); } } /* * During a cache timeout we iterate over all nodes. * Check for node leaks by comparing the actual number of cached * nodes with the ic_nnodes count, which is maintained while adding * and removing nodes from the cache. */ if ((ifp->if_flags & IFF_DEBUG) && cache_timeout && nnodes != ic->ic_nnodes) XYLog("%s: number of cached nodes is %d, expected %d," "possible nodes leak\n", ifp->if_xname, nnodes, ic->ic_nnodes); #endif splx(s); } void ieee80211_clean_inactive_nodes(struct ieee80211com *ic, int inact_max) { DPRINTF(("%s\n", __FUNCTION__)); struct ieee80211_node *ni, *next_ni; u_int gen = ic->ic_scangen++; /* NB: ok 'cuz single-threaded*/ int s; s = splnet(); for (ni = RB_MIN(ieee80211_tree, &ic->ic_tree); ni != NULL; ni = next_ni) { next_ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); if (ni->ni_scangen == gen) /* previously handled */ continue; ni->ni_scangen = gen; if (ni->ni_refcnt > 0 || ni->ni_inact < inact_max) continue; ieee80211_free_node(ic, ni); ic->ic_stats.is_node_timeout++; } splx(s); } void ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f, void *arg) { struct ieee80211_node *ni; int s; s = splnet(); RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) (*f)(arg, ni); splx(s); } /* * Install received HT caps information in the node's state block. */ void ieee80211_setup_htcaps(struct ieee80211_node *ni, const uint8_t *data, uint8_t len) { uint16_t rxrate; if (len != 26) return; ni->ni_htcaps = (data[0] | (data[1] << 8)); ni->ni_htcaps &= le16toh(ni->ni_ic->ic_htcaps | ~(IEEE80211_HTCAP_CBW20_40 | IEEE80211_HTCAP_SGI40 | IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_GF | IEEE80211_HTCAP_LDPC | IEEE80211_HTCAP_DSSSCCK40)); if (!(ni->ni_ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC)) ni->ni_htcaps &= ~IEEE80211_HTCAP_RXSTBC_MASK; if (!(ni->ni_ic->ic_htcaps & IEEE80211_HTCAP_RXSTBC_MASK)) ni->ni_htcaps &= ~IEEE80211_HTCAP_TXSTBC; ni->ni_ampdu_param = data[2]; memcpy(ni->ni_rxmcs, &data[3], sizeof(ni->ni_rxmcs)); /* clear reserved bits */ clrbit(ni->ni_rxmcs, 77); clrbit(ni->ni_rxmcs, 78); clrbit(ni->ni_rxmcs, 79); /* Max MCS Rx rate in 1Mb/s units (0 means "not specified"). */ rxrate = ((data[13] | (data[14]) << 8) & IEEE80211_MCS_RX_RATE_HIGH); if (rxrate < 1024) ni->ni_max_rxrate = rxrate; ni->ni_tx_mcs_set = data[15]; ni->ni_htxcaps = (data[19] | (data[20] << 8)); ni->ni_txbfcaps = (data[21] | (data[22] << 8) | (data[23] << 16) | (data[24] << 24)); ni->ni_aselcaps = data[25]; ni->ni_flags |= IEEE80211_NODE_HTCAP; } #ifndef IEEE80211_STA_ONLY /* * Handle nodes switching from 11n into legacy modes. */ void ieee80211_clear_htcaps(struct ieee80211_node *ni) { ni->ni_htcaps = 0; ni->ni_ampdu_param = 0; memset(ni->ni_rxmcs, 0, sizeof(ni->ni_rxmcs)); ni->ni_max_rxrate = 0; ni->ni_tx_mcs_set = 0; ni->ni_htxcaps = 0; ni->ni_txbfcaps = 0; ni->ni_aselcaps = 0; ni->ni_flags &= ~(IEEE80211_NODE_HT | IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40 | IEEE80211_NODE_HTCAP); } #endif /* * Install received HT op information in the node's state block. */ int ieee80211_setup_htop(struct ieee80211_node *ni, const uint8_t *data, uint8_t len, int isprobe) { if (len != 22) return 0; ni->ni_primary_chan = data[0]; /* XXX corresponds to ni_chan */ ni->ni_htop0 = data[1]; ni->ni_htop1 = (data[2] | (data[3] << 8)); ni->ni_htop2 = (data[3] | (data[4] << 8)); /* * According to 802.11-2012 Table 8-130 the Basic MCS set is * only "present in Beacon, Probe Response, Mesh Peering Open * and Mesh Peering Confirm frames. Otherwise reserved." */ if (isprobe) memcpy(ni->ni_basic_mcs, &data[6], sizeof(ni->ni_basic_mcs)); return 1; } /* * Parse an 802.11ac VHT operation IE. */ void ieee80211_setup_vhtopmode(struct ieee80211_node *ni, const uint8_t *ie) { /* vht operation */ struct ieee80211_ie_vht_operation *op = (struct ieee80211_ie_vht_operation *)ie; ni->ni_vht_chanwidth = op->chan_width; ni->ni_vht_chan1 = op->center_freq_seg1_idx; ni->ni_vht_chan2 = op->center_freq_seg2_idx; ni->ni_vht_basicmcs = op->basic_mcs_set; DPRINTF(("%s: chan1=%d, chan2=%d, chanwidth=%d, basicmcs=0x%04x\n", __func__, ni->ni_vht_chan1, ni->ni_vht_chan2, ni->ni_vht_chanwidth, ni->ni_vht_basicmcs)); } /* * Parse an 802.11ac VHT capability IE. */ void ieee80211_setup_vhtcaps(struct ieee80211com *ic, struct ieee80211_node *ni, const uint8_t *ie) { uint32_t val, val1, val2; int i; uint16_t rx_mcs_map; uint16_t rx_highest; uint16_t tx_mcs_map; uint16_t tx_highest; uint32_t own_vhtcap = ic->ic_vhtcaps; uint32_t new_vhtcap = 0, peer_vhtcap; /* vht capability */ peer_vhtcap = le32dec(ie + 2); /* suppmcs */ rx_mcs_map = le16dec(ie + 6); rx_highest = le16dec(ie + 8); tx_mcs_map = le16dec(ie + 10); tx_highest = le16dec(ie + 12); #define MS(_v, _f) (((_v) & _f) >> _f##_S) #define SM(_v, _f) (((_v) << _f##_S) & _f) val1 = MS(own_vhtcap, IEEE80211_VHTCAP_MAX_MPDU_MASK); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_MAX_MPDU_MASK); val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_MAX_MPDU_MASK); /* Supported Channel Width */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK); if ((val2 == 2) && ((own_vhtcap & IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160_80P80MHZ) == 0)) val2 = 1; if ((val2 == 1) && ((own_vhtcap & IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ) == 0)) val2 = 0; val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK); /* RX LDPC */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_RXLDPC); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_RXLDPC); val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_RXLDPC); /* Short-GI 80 */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_SHORT_GI_80); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_SHORT_GI_80); val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_SHORT_GI_80); /* Short-GI 160 */ val2 = val1 = MS(own_vhtcap, IEEE80211_VHTCAP_SHORT_GI_160); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_SHORT_GI_160); val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_SHORT_GI_160); /* * STBC is slightly more complicated. * * In non-STA mode, we just announce our capabilities and that * is that. * * In STA mode, we should calculate our capabilities based on * local capabilities /and/ what the remote says. So: * * + Only TX STBC if we support it and the remote supports RX STBC; * + Only announce RX STBC if we support it and the remote supports * TX STBC; * + RX STBC should be the minimum of local and remote RX STBC; */ /* TX STBC */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_TXSTBC); /* STA mode - enable it only if node RXSTBC is non-zero */ val2 = !! MS(peer_vhtcap, IEEE80211_VHTCAP_RXSTBC_MASK); val = MIN(val1, val2); /* XXX For now, use the 11n config flag */ if ((ic->ic_htcaps & IEEE80211_HTCAP_TXSTBC) == 0) val = 0; new_vhtcap |= SM(val, IEEE80211_VHTCAP_TXSTBC); /* RX STBC1..4 */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_RXSTBC_MASK); /* STA mode - enable it only if node TXSTBC is non-zero */ val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_TXSTBC); val = MIN(val1, val2); /* XXX For now, use the 11n config flag */ if ((ic->ic_htcaps & IEEE80211_HTCAP_RXSTBC_MASK) == 0) val = 0; new_vhtcap |= SM(val, IEEE80211_VHTCAP_RXSTBC_MASK); /* * Finally - if RXSTBC is 0, then don't enable TXSTBC. * Strictly speaking a device can TXSTBC and not RXSTBC, but * it would be silly. */ if (val == 0) new_vhtcap &= ~IEEE80211_VHTCAP_TXSTBC; /* * Some of these fields require other fields to exist. * So before using it, the parent field needs to be checked * otherwise the overridden value may be wrong. * * For example, if SU beamformee is set to 0, then BF STS * needs to be 0. */ /* SU Beamformer capable */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE); val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE); /* SU Beamformee capable */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE); val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE); /* Beamformee STS capability - only if SU beamformee capable */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK); val = MIN(val1, val2); if ((new_vhtcap & IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE) == 0) val = 0; new_vhtcap |= SM(val, IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK); /* Sounding dimensions - only if SU beamformer capable */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_MASK); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_MASK); val = MIN(val1, val2); if ((new_vhtcap & IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE) == 0) val = 0; new_vhtcap |= SM(val, IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_MASK); /* * MU Beamformer capable - only if SU BFF capable, MU BFF capable * and STA (not AP) */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_MU_BEAMFORMER_CAPABLE); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_MU_BEAMFORMER_CAPABLE); val = MIN(val1, val2); if ((new_vhtcap & IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE) == 0) val = 0; /* Only enable for STA mode */ new_vhtcap |= SM(val, IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE); /* * MU Beamformee capable - only if SU BFE capable, MU BFE capable * and AP (not STA) */ /* Only enable for AP mode */ val = 0; new_vhtcap |= SM(val, IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE); /* VHT TXOP PS */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_VHT_TXOP_PS); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_VHT_TXOP_PS); val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_VHT_TXOP_PS); /* HTC_VHT */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_HTC_VHT); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_HTC_VHT); val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_HTC_VHT); /* A-MPDU length max */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); val = MIN(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); /* * Link adaptation is only valid if HTC-VHT capable is 1. * Otherwise, always set it to 0. */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MASK); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MASK); val = MIN(val1, val2); if ((new_vhtcap & IEEE80211_VHTCAP_HTC_VHT) == 0) val = 0; new_vhtcap |= SM(val, IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MASK); /* * The following two options are 0 if the pattern may change, 1 if it * does not change. So, downgrade to the higher value. */ /* RX antenna pattern */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_RX_ANTENNA_PATTERN); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_RX_ANTENNA_PATTERN); val = MAX(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_RX_ANTENNA_PATTERN); /* TX antenna pattern */ val1 = MS(own_vhtcap, IEEE80211_VHTCAP_TX_ANTENNA_PATTERN); val2 = MS(peer_vhtcap, IEEE80211_VHTCAP_TX_ANTENNA_PATTERN); val = MAX(val1, val2); new_vhtcap |= SM(val, IEEE80211_VHTCAP_TX_ANTENNA_PATTERN); /* copy EXT_NSS_BW Support value or remove the capability */ if (ic->ic_caps & IEEE80211_C_SUPPORTS_VHT_EXT_NSS_BW) { new_vhtcap |= IEEE80211_VHTCAP_EXT_NSS_BW_MASK; } else { tx_highest &= ~htole16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); } #undef SM #undef MS ni->ni_vhtcaps = new_vhtcap; /* * MCS set - again, we announce what we want to use * based on configuration, device capabilities and * already-learnt vhtcap/vhtinfo IE information. */ /* MCS set - start with whatever the device supports */ for (i = 0; i < 8; i++) { uint16_t own_rx, own_tx, peer_rx, peer_tx; own_rx = le16toh(ic->ic_vht_rx_mcs_map); own_rx = (own_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; own_tx = le16toh(ic->ic_vht_tx_mcs_map); own_tx = (own_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; peer_rx = le16toh(rx_mcs_map); peer_rx = (peer_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; peer_tx = le16toh(tx_mcs_map); peer_tx = (peer_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; if (peer_tx != IEEE80211_VHT_MCS_NOT_SUPPORTED) { if (own_rx == IEEE80211_VHT_MCS_NOT_SUPPORTED) peer_tx = IEEE80211_VHT_MCS_NOT_SUPPORTED; else if (own_rx < peer_tx) peer_tx = own_rx; } if (peer_rx != IEEE80211_VHT_MCS_NOT_SUPPORTED) { if (own_tx == IEEE80211_VHT_MCS_NOT_SUPPORTED) peer_rx = IEEE80211_VHT_MCS_NOT_SUPPORTED; else if (own_tx < peer_rx) peer_rx = own_tx; } rx_mcs_map &= ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2); rx_mcs_map |= cpu_to_le16(peer_rx << i * 2); tx_mcs_map &= ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2); tx_mcs_map |= cpu_to_le16(peer_tx << i * 2); } ni->ni_vht_mcsinfo.rx_mcs_map = rx_mcs_map; ni->ni_vht_mcsinfo.tx_mcs_map = tx_mcs_map; ni->ni_vht_mcsinfo.tx_highest = tx_highest; ni->ni_vht_mcsinfo.rx_highest = rx_highest; ni->ni_flags |= IEEE80211_NODE_VHTCAP; } #ifndef IEEE80211_STA_ONLY /* * Handle nodes switching from 11ac into legacy modes. */ void ieee80211_clear_vhtcaps(struct ieee80211_node *ni) { ni->ni_vhtcaps = 0; memset(&ni->ni_vht_mcsinfo, 0, sizeof(ni->ni_vht_mcsinfo)); ni->ni_flags &= ~(IEEE80211_NODE_VHT | IEEE80211_NODE_VHT_SGI80 | IEEE80211_NODE_VHT_SGI160 | IEEE80211_NODE_VHTCAP); } #endif void ieee80211_setup_hecaps(struct ieee80211_node *ni, const uint8_t *data, uint8_t len) { struct ieee80211_he_cap_elem *he_cap_ie_elem = (struct ieee80211_he_cap_elem *)data; uint8_t mcs_nss_size, he_ppe_size, he_total_size; mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap_ie_elem); he_ppe_size = ieee80211_he_ppe_size(data[sizeof(ni->ni_he_cap_elem) + mcs_nss_size], he_cap_ie_elem->phy_cap_info); he_total_size = sizeof(ni->ni_he_cap_elem) + mcs_nss_size + he_ppe_size; if (len < he_total_size) return; memcpy(&ni->ni_he_cap_elem, data, sizeof(ni->ni_he_cap_elem)); /* HE Tx/Rx HE MCS NSS Support Field */ memcpy(&ni->ni_he_mcs_nss_supp, &data[sizeof(ni->ni_he_cap_elem)], mcs_nss_size); /* Check if there are (optional) PPE Thresholds */ if (ni->ni_he_cap_elem.phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) memcpy(ni->ni_ppe_thres, &data[sizeof(ni->ni_he_cap_elem) + mcs_nss_size], he_ppe_size); } int ieee80211_setup_heop(struct ieee80211_node *ni, const uint8_t *data, uint8_t len) { struct ieee80211_he_operation *he_op_ie = (struct ieee80211_he_operation *)data; ni->ni_he_oper_params = le32toh(he_op_ie->he_oper_params); ni->ni_he_oper_nss_set = le16toh(he_op_ie->he_mcs_nss_set); bzero(&ni->ni_he_optional, sizeof(ni->ni_he_optional)); if (len > __offsetof(struct ieee80211_he_operation, optional)) { memcpy(ni->ni_he_optional, he_op_ie->optional, min(sizeof(ni->ni_he_optional), len - __offsetof(struct ieee80211_he_operation, optional))); } return 1; } /* * Install received rate set information in the node's state block. */ int ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni, const u_int8_t *rates, const u_int8_t *xrates, int flags) { struct ieee80211_rateset *rs = &ni->ni_rates; memset(rs, 0, sizeof(*rs)); rs->rs_nrates = rates[1]; memcpy(rs->rs_rates, rates + 2, rs->rs_nrates); if (xrates != NULL) { u_int8_t nxrates; /* * Tack on 11g extended supported rate element. */ nxrates = xrates[1]; if (rs->rs_nrates + nxrates > IEEE80211_RATE_MAXSIZE) { nxrates = IEEE80211_RATE_MAXSIZE - rs->rs_nrates; DPRINTF(("extended rate set too large; " "only using %u of %u rates\n", nxrates, xrates[1])); ic->ic_stats.is_rx_rstoobig++; } memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates); rs->rs_nrates += nxrates; } return ieee80211_fix_rate(ic, ni, flags); } void ieee80211_node_trigger_addba_req(struct ieee80211_node *ni, int tid) { if (ni->ni_tx_ba[tid].ba_state == IEEE80211_BA_INIT && !timeout_pending(&ni->ni_addba_req_to[tid])) { timeout_add_sec(&ni->ni_addba_req_to[tid], ni->ni_addba_req_intval[tid]); } } void ieee80211_node_addba_request(struct ieee80211_node *ni, int tid) { struct ieee80211com *ic = ni->ni_ic; uint16_t ssn = ni->ni_qos_txseqs[tid]; ieee80211_addba_request(ic, ni, ssn, tid); } void ieee80211_node_addba_request_ac_be_to(void *arg) { struct ieee80211_node *ni = (struct ieee80211_node *)arg; ieee80211_node_addba_request(ni, EDCA_AC_BE); } void ieee80211_node_addba_request_ac_bk_to(void *arg) { struct ieee80211_node *ni = (struct ieee80211_node *)arg; ieee80211_node_addba_request(ni, EDCA_AC_BK); } void ieee80211_node_addba_request_ac_vi_to(void *arg) { struct ieee80211_node *ni = (struct ieee80211_node *)arg; ieee80211_node_addba_request(ni, EDCA_AC_VI); } void ieee80211_node_addba_request_ac_vo_to(void *arg) { struct ieee80211_node *ni = (struct ieee80211_node *)arg; ieee80211_node_addba_request(ni, EDCA_AC_VO); } #ifndef IEEE80211_STA_ONLY /* * Check if the specified node supports ERP. */ int ieee80211_iserp_sta(const struct ieee80211_node *ni) { static const u_int8_t rates[] = { 2, 4, 11, 22, 12, 24, 48 }; const struct ieee80211_rateset *rs = &ni->ni_rates; int i, j; /* * A STA supports ERP operation if it includes all the Clause 19 * mandatory rates in its supported rate set. */ for (i = 0; i < nitems(rates); i++) { for (j = 0; j < rs->rs_nrates; j++) { if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == rates[i]) break; } if (j == rs->rs_nrates) return 0; } return 1; } /* * This function is called to notify the 802.1X PACP machine that a new * 802.1X port is enabled and must be authenticated. For 802.11, a port * becomes enabled whenever a STA successfully completes Open System * authentication with an AP. */ void ieee80211_needs_auth(struct ieee80211com *ic, struct ieee80211_node *ni) { /* * XXX this could be done via the route socket of via a dedicated * EAP socket or another kernel->userland notification mechanism. * The notification should include the MAC address (ni_macaddr). */ } /* * Handle an HT STA joining an HT network. */ void ieee80211_node_join_ht(struct ieee80211com *ic, struct ieee80211_node *ni) { /* Update HT protection setting. */ if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) { uint16_t htop1 = ic->ic_bss->ni_htop1; htop1 &= ~IEEE80211_HTOP1_PROT_MASK; htop1 |= IEEE80211_HTPROT_NONHT_MIXED; ic->ic_bss->ni_htop1 = htop1; if (ic->ic_updateprot) ic->ic_updateprot(ic); } } /* * Handle a station joining an RSN network. */ void ieee80211_node_join_rsn(struct ieee80211com *ic, struct ieee80211_node *ni) { DPRINTF(("station %s associated using proto %d akm 0x%x " "cipher 0x%x groupcipher 0x%x\n", ether_sprintf(ni->ni_macaddr), ni->ni_rsnprotos, ni->ni_rsnakms, ni->ni_rsnciphers, ni->ni_rsngroupcipher)); ni->ni_rsn_state = RSNA_AUTHENTICATION; ni->ni_key_count = 0; ni->ni_port_valid = 0; ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT; ni->ni_flags &= ~IEEE80211_NODE_RSN_NEW_PTK; ni->ni_replaycnt = -1; /* XXX */ ni->ni_rsn_retries = 0; ni->ni_rsncipher = (enum ieee80211_cipher)ni->ni_rsnciphers; ni->ni_rsn_state = RSNA_AUTHENTICATION_2; /* generate a new authenticator nonce (ANonce) */ arc4random_buf(ni->ni_nonce, EAPOL_KEY_NONCE_LEN); if (!ieee80211_is_8021x_akm((enum ieee80211_akm)ni->ni_rsnakms)) { memcpy(ni->ni_pmk, ic->ic_psk, IEEE80211_PMK_LEN); ni->ni_flags |= IEEE80211_NODE_PMK; (void)ieee80211_send_4way_msg1(ic, ni); } else if (ni->ni_flags & IEEE80211_NODE_PMK) { /* skip 802.1X auth if a cached PMK was found */ (void)ieee80211_send_4way_msg1(ic, ni); } else { /* no cached PMK found, needs full 802.1X auth */ ieee80211_needs_auth(ic, ni); } } void ieee80211_count_longslotsta(void *arg, struct ieee80211_node *ni) { int *longslotsta = (int *)arg; if (ni->ni_associd == 0 || ni->ni_state == IEEE80211_STA_COLLECT) return; if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)) (*longslotsta)++; } void ieee80211_count_nonerpsta(void *arg, struct ieee80211_node *ni) { int *nonerpsta = (int *)arg; if (ni->ni_associd == 0 || ni->ni_state == IEEE80211_STA_COLLECT) return; if (!ieee80211_iserp_sta(ni)) (*nonerpsta)++; } void ieee80211_count_pssta(void *arg, struct ieee80211_node *ni) { int *pssta = (int *)arg; if (ni->ni_associd == 0 || ni->ni_state == IEEE80211_STA_COLLECT) return; if (ni->ni_pwrsave == IEEE80211_PS_DOZE) (*pssta)++; } void ieee80211_count_rekeysta(void *arg, struct ieee80211_node *ni) { int *rekeysta = (int *)arg; if (ni->ni_associd == 0 || ni->ni_state == IEEE80211_STA_COLLECT) return; if (ni->ni_flags & IEEE80211_NODE_REKEY) (*rekeysta)++; } /* * Handle a station joining an 11g network. */ void ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni) { int longslotsta = 0, nonerpsta = 0; if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)) { /* * Joining STA doesn't support short slot time. We must * disable the use of short slot time for all other associated * STAs and give the driver a chance to reconfigure the * hardware. */ ieee80211_iterate_nodes(ic, ieee80211_count_longslotsta, &longslotsta); if (longslotsta == 1) { if (ic->ic_caps & IEEE80211_C_SHSLOT) ieee80211_set_shortslottime(ic, 0); } DPRINTF(("[%s] station needs long slot time, count %d\n", ether_sprintf(ni->ni_macaddr), longslotsta)); } if (!ieee80211_iserp_sta(ni)) { /* * Joining STA is non-ERP. */ ieee80211_iterate_nodes(ic, ieee80211_count_nonerpsta, &nonerpsta); DPRINTF(("[%s] station is non-ERP, %d non-ERP " "stations associated\n", ether_sprintf(ni->ni_macaddr), nonerpsta)); /* must enable the use of protection */ if (ic->ic_protmode != IEEE80211_PROT_NONE) { DPRINTF(("enable use of protection\n")); ic->ic_flags |= IEEE80211_F_USEPROT; } if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; } else ni->ni_flags |= IEEE80211_NODE_ERP; } void ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp) { int newassoc = (ni->ni_state != IEEE80211_STA_ASSOC); if (ni->ni_associd == 0) { u_int16_t aid; /* * It would be clever to search the bitmap * more efficiently, but this will do for now. */ for (aid = 1; aid < ic->ic_max_aid; aid++) { if (!IEEE80211_AID_ISSET(aid, ic->ic_aid_bitmap)) break; } if (aid >= ic->ic_max_aid) { IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_REASON_ASSOC_TOOMANY); ieee80211_node_leave(ic, ni); return; } ni->ni_associd = aid | 0xc000; IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap); if (ic->ic_curmode == IEEE80211_MODE_11G || (ic->ic_curmode == IEEE80211_MODE_11N && IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan))) ieee80211_node_join_11g(ic, ni); } DPRINTF(("station %s %s associated at aid %d\n", ether_sprintf(ni->ni_macaddr), newassoc ? "newly" : "already", ni->ni_associd & ~0xc000)); ieee80211_ht_negotiate(ic, ni); if (ic->ic_flags & IEEE80211_F_HTON) ieee80211_node_join_ht(ic, ni); /* give driver a chance to setup state like ni_txrate */ if (ic->ic_newassoc) (*ic->ic_newassoc)(ic, ni, newassoc); IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS); ieee80211_node_newstate(ni, IEEE80211_STA_ASSOC); if (!(ic->ic_flags & IEEE80211_F_RSNON)) { ni->ni_port_valid = 1; ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP; } else ieee80211_node_join_rsn(ic, ni); #if NBRIDGE > 0 /* * If the parent interface is a bridge port, learn * the node's address dynamically on this interface. */ if (ic->ic_if.if_bridgeidx != 0) bridge_update(&ic->ic_if, (struct ether_addr *)ni->ni_macaddr, 0); #endif } /* * Handle a VHT STA leaving a VHT network. */ void ieee80211_node_leave_vht(struct ieee80211com *ic, struct ieee80211_node *ni) { ieee80211_clear_vhtcaps(ni); } /* * Handle an HT STA leaving an HT network. */ void ieee80211_node_leave_ht(struct ieee80211com *ic, struct ieee80211_node *ni) { struct ieee80211_rx_ba *ba; u_int8_t tid; int i; /* free all Block Ack records */ ieee80211_ba_del(ni); ieee80211_ba_free(ni); for (tid = 0; tid < IEEE80211_NUM_TID; tid++) { ba = &ni->ni_rx_ba[tid]; if (ba->ba_buf != NULL) { for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++) mbuf_freem(ba->ba_buf[i].m); free(ba->ba_buf); ba->ba_buf = NULL; } } ieee80211_clear_htcaps(ni); } /* * Handle a station leaving an RSN network. */ void ieee80211_node_leave_rsn(struct ieee80211com *ic, struct ieee80211_node *ni) { int rekeysta = 0; ni->ni_rsn_state = RSNA_DISCONNECTED; ni->ni_rsn_state = RSNA_INITIALIZE; if (ni->ni_flags & IEEE80211_NODE_REKEY) { ni->ni_flags &= ~IEEE80211_NODE_REKEY; ieee80211_iterate_nodes(ic, ieee80211_count_rekeysta, &rekeysta); if (rekeysta == 0) ieee80211_setkeysdone(ic); } ni->ni_flags &= ~IEEE80211_NODE_PMK; ni->ni_rsn_gstate = RSNA_IDLE; timeout_del(&ni->ni_eapol_to); timeout_del(&ni->ni_sa_query_to); ni->ni_rsn_retries = 0; ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT; ni->ni_port_valid = 0; (*ic->ic_delete_key)(ic, ni, &ni->ni_pairwise_key); } /* * Handle a station leaving an 11g network. */ void ieee80211_node_leave_11g(struct ieee80211com *ic, struct ieee80211_node *ni) { int longslotsta = 0, nonerpsta = 0; if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)) { /* leaving STA did not support short slot time */ ieee80211_iterate_nodes(ic, ieee80211_count_longslotsta, &longslotsta); if (longslotsta == 1) { /* * All associated STAs now support short slot time, so * enable this feature and give the driver a chance to * reconfigure the hardware. Notice that IBSS always * use a long slot time. */ if ((ic->ic_caps & IEEE80211_C_SHSLOT) && ic->ic_opmode != IEEE80211_M_IBSS) ieee80211_set_shortslottime(ic, 1); } DPRINTF(("[%s] long slot time station leaves, count %d\n", ether_sprintf(ni->ni_macaddr), longslotsta)); } if (!(ni->ni_flags & IEEE80211_NODE_ERP)) { /* leaving STA was non-ERP */ ieee80211_iterate_nodes(ic, ieee80211_count_nonerpsta, &nonerpsta); if (nonerpsta == 1) { /* * All associated STAs are now ERP capable, disable use * of protection and re-enable short preamble support. */ ic->ic_flags &= ~IEEE80211_F_USEPROT; if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) ic->ic_flags |= IEEE80211_F_SHPREAMBLE; } DPRINTF(("[%s] non-ERP station leaves, count %d\n", ether_sprintf(ni->ni_macaddr), nonerpsta)); } } /* * Handle bookkeeping for station deauthentication/disassociation * when operating as an ap. */ void ieee80211_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) { if (ic->ic_opmode != IEEE80211_M_HOSTAP) panic("not in ap mode, mode %u", ic->ic_opmode); if (ni->ni_state == IEEE80211_STA_COLLECT) return; /* * If node wasn't previously associated all we need to do is * reclaim the reference. */ if (ni->ni_associd == 0) { ieee80211_node_newstate(ni, IEEE80211_STA_COLLECT); return; } if (ni->ni_pwrsave == IEEE80211_PS_DOZE) ni->ni_pwrsave = IEEE80211_PS_AWAKE; if (mq_purge(&ni->ni_savedq) > 0) { if (ic->ic_set_tim != NULL) (*ic->ic_set_tim)(ic, ni->ni_associd, 0); } if (ic->ic_flags & IEEE80211_F_RSNON) ieee80211_node_leave_rsn(ic, ni); if (ic->ic_curmode == IEEE80211_MODE_11G || (ic->ic_curmode == IEEE80211_MODE_11N && IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan))) ieee80211_node_leave_11g(ic, ni); if (ni->ni_flags & IEEE80211_NODE_HT) ieee80211_node_leave_ht(ic, ni); if (ni->ni_flags & IEEE80211_NODE_VHT) ieee80211_node_leave_vht(ic, ni); if (ic->ic_node_leave != NULL) (*ic->ic_node_leave)(ic, ni); ieee80211_node_newstate(ni, IEEE80211_STA_COLLECT); #if NBRIDGE > 0 /* * If the parent interface is a bridge port, delete * any dynamically learned address for this node. */ if (ic->ic_if.if_bridgeidx != 0) bridge_update(&ic->ic_if, (struct ether_addr *)ni->ni_macaddr, 1); #endif } static int ieee80211_do_slow_print(struct ieee80211com *ic, int *did_print) { static const struct timeval merge_print_intvl = { .tv_sec = 1, .tv_usec = 0 }; if ((ic->ic_if.if_flags & IFF_LINK0) == 0) return 0; if (!*did_print && (ic->ic_if.if_flags & IFF_DEBUG) == 0 && !ratecheck(&ic->ic_last_merge_print, &merge_print_intvl)) return 0; *did_print = 1; return 1; } /* ieee80211_ibss_merge helps merge 802.11 ad hoc networks. The * convention, set by the Wireless Ethernet Compatibility Alliance * (WECA), is that an 802.11 station will change its BSSID to match * the "oldest" 802.11 ad hoc network, on the same channel, that * has the station's desired SSID. The "oldest" 802.11 network * sends beacons with the greatest TSF timestamp. * * Return ENETRESET if the BSSID changed, 0 otherwise. * * XXX Perhaps we should compensate for the time that elapses * between the MAC receiving the beacon and the host processing it * in ieee80211_ibss_merge. */ int ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni, u_int64_t local_tsft) { u_int64_t beacon_tsft; int did_print = 0, sign; union { u_int64_t word; u_int8_t tstamp[8]; } u; /* ensure alignment */ (void)memcpy(&u, &ni->ni_tstamp[0], sizeof(u)); beacon_tsft = letoh64(u.word); /* we are faster, let the other guy catch up */ if (beacon_tsft < local_tsft) sign = -1; else sign = 1; if (IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) { if (!ieee80211_do_slow_print(ic, &did_print)) return 0; XYLog("%s: tsft offset %s%llu\n", ic->ic_if.if_xname, (sign < 0) ? "-" : "", (sign < 0) ? (local_tsft - beacon_tsft) : (beacon_tsft - local_tsft)); return 0; } if (sign < 0) return 0; if (ieee80211_match_bss(ic, ni, 0) != 0) return 0; if (ieee80211_do_slow_print(ic, &did_print)) { XYLog("%s: ieee80211_ibss_merge: bssid mismatch %s\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid)); XYLog("%s: my tsft %llu beacon tsft %llu\n", ic->ic_if.if_xname, local_tsft, beacon_tsft); XYLog("%s: sync TSF with %s\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr)); } ic->ic_flags &= ~IEEE80211_F_SIBSS; /* negotiate rates with new IBSS */ ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (ni->ni_rates.rs_nrates == 0) { if (ieee80211_do_slow_print(ic, &did_print)) { XYLog("%s: rates mismatch, BSSID %s\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid)); } return 0; } if (ieee80211_do_slow_print(ic, &did_print)) { XYLog("%s: sync BSSID %s -> ", ic->ic_if.if_xname, ether_sprintf(ic->ic_bss->ni_bssid)); XYLog("%s ", ether_sprintf(ni->ni_bssid)); XYLog("(from %s)\n", ether_sprintf(ni->ni_macaddr)); } ieee80211_node_newstate(ni, IEEE80211_STA_BSS); (*ic->ic_node_copy)(ic, ic->ic_bss, ni); return ENETRESET; } void ieee80211_set_tim(struct ieee80211com *ic, int aid, int set) { if (set) setbit(ic->ic_tim_bitmap, aid & ~0xc000); else clrbit(ic->ic_tim_bitmap, aid & ~0xc000); } /* * This function shall be called by drivers immediately after every DTIM. * Transmit all group addressed MSDUs buffered at the AP. */ void ieee80211_notify_dtim(struct ieee80211com *ic) { /* NB: group addressed MSDUs are buffered in ic_bss */ struct ieee80211_node *ni = ic->ic_bss; struct _ifnet *ifp = &ic->ic_if; struct ieee80211_frame *wh; mbuf_t m; _KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP); while ((m = mq_dequeue(&ni->ni_savedq)) != NULL) { if (!mq_empty(&ni->ni_savedq)) { /* more queued frames, set the more data bit */ wh = mtod(m, struct ieee80211_frame *); wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; } mq_enqueue(&ic->ic_pwrsaveq, m); (*ifp->if_start)(ifp); } /* XXX assumes everything has been sent */ ic->ic_tim_mcast_pending = 0; } #endif /* IEEE80211_STA_ONLY */ /* * Compare nodes in the tree by lladdr */ int ieee80211_node_cmp(const struct ieee80211_node *b1, const struct ieee80211_node *b2) { return (memcmp(b1->ni_macaddr, b2->ni_macaddr, IEEE80211_ADDR_LEN)); } /* * Compare nodes in the tree by essid */ int ieee80211_ess_cmp(const struct ieee80211_ess_rbt *b1, const struct ieee80211_ess_rbt *b2) { return (memcmp(b1->essid, b2->essid, IEEE80211_NWID_LEN)); } /* * Generate red-black tree function logic */ RB_GENERATE(ieee80211_tree, ieee80211_node, ni_node, ieee80211_node_cmp); RB_GENERATE(ieee80211_ess_tree, ieee80211_ess_rbt, ess_rbt, ieee80211_ess_cmp); ================================================ FILE: itl80211/openbsd/net80211/ieee80211_node.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_node.h,v 1.87 2020/07/21 08:38:59 stsp Exp $ */ /* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_node.h,v 1.10 2004/04/05 22:10:26 sam Exp $ */ #ifndef _NET80211_IEEE80211_NODE_H_ #define _NET80211_IEEE80211_NODE_H_ #include #include #include #define IEEE80211_PSCAN_WAIT 5 /* passive scan wait */ #define IEEE80211_TRANS_WAIT 5 /* transition wait */ #define IEEE80211_INACT_WAIT 5 /* inactivity timer interval */ #define IEEE80211_INACT_MAX (300/IEEE80211_INACT_WAIT) #define IEEE80211_CACHE_SIZE 200 #define IEEE80211_CACHE_WAIT 30 #define IEEE80211_INACT_SCAN 10 /* for station mode */ struct ieee80211_rateset { u_int8_t rs_nrates; u_int8_t rs_rates[IEEE80211_RATE_MAXSIZE]; }; extern const struct ieee80211_rateset ieee80211_std_rateset_11a; extern const struct ieee80211_rateset ieee80211_std_rateset_11b; extern const struct ieee80211_rateset ieee80211_std_rateset_11g; /* Index into ieee80211_std_rateset_11n[] array. */ #define IEEE80211_HT_RATESET_SISO 0 #define IEEE80211_HT_RATESET_SISO_SGI 1 #define IEEE80211_HT_RATESET_MIMO2 2 #define IEEE80211_HT_RATESET_MIMO2_SGI 3 #define IEEE80211_HT_RATESET_MIMO3 4 #define IEEE80211_HT_RATESET_MIMO3_SGI 5 #define IEEE80211_HT_RATESET_MIMO4 6 #define IEEE80211_HT_RATESET_MIMO4_SGI 7 #define IEEE80211_HT_RATESET_CBW40_SISO 8 #define IEEE80211_HT_RATESET_CBW40_SISO_SGI 9 #define IEEE80211_HT_RATESET_CBW40_MIMO2 10 #define IEEE80211_HT_RATESET_CBW40_MIMO2_SGI 11 #define IEEE80211_HT_RATESET_CBW40_MIMO3 12 #define IEEE80211_HT_RATESET_CBW40_MIMO3_SGI 13 #define IEEE80211_HT_RATESET_CBW40_MIMO4 14 #define IEEE80211_HT_RATESET_CBW40_MIMO4_SGI 15 #define IEEE80211_HT_NUM_RATESETS 16 /* Maximum number of rates in a HT rateset. */ #define IEEE80211_HT_RATESET_MAX_NRATES 8 /* Number of MCS indices represented by struct ieee80211_ht_rateset. */ #define IEEE80211_HT_RATESET_NUM_MCS 32 struct ieee80211_ht_rateset { uint32_t nrates; uint32_t rates[IEEE80211_HT_RATESET_MAX_NRATES]; /* 500 kbit/s units */ /* * This bitmask can only express MCS 0 - MCS 31. * IEEE 802.11 defined 77 HT MCS in total but common hardware * implementations tend to support MCS index 0 through 31 only. */ uint32_t mcs_mask; /* Range of MCS indices represented in this rateset. */ int min_mcs; int max_mcs; int sgi; }; extern const struct ieee80211_ht_rateset ieee80211_std_ratesets_11n[]; /* Index into ieee80211_std_rateset_11ac[] array. */ #define IEEE80211_VHT_RATESET_SISO 0 #define IEEE80211_VHT_RATESET_SISO_SGI 1 #define IEEE80211_VHT_RATESET_MIMO2 2 #define IEEE80211_VHT_RATESET_MIMO2_SGI 3 #define IEEE80211_VHT_RATESET_SISO_40 4 #define IEEE80211_VHT_RATESET_SISO_40_SGI 5 #define IEEE80211_VHT_RATESET_MIMO2_40 6 #define IEEE80211_VHT_RATESET_MIMO2_40_SGI 7 #define IEEE80211_VHT_RATESET_SISO_80 8 #define IEEE80211_VHT_RATESET_SISO_80_SGI 9 #define IEEE80211_VHT_RATESET_MIMO2_80 10 #define IEEE80211_VHT_RATESET_MIMO2_80_SGI 11 #define IEEE80211_VHT_RATESET_SISO_160 12 #define IEEE80211_VHT_RATESET_SISO_160_SGI 13 #define IEEE80211_VHT_RATESET_MIMO2_160 14 #define IEEE80211_VHT_RATESET_MIMO2_160_SGI 15 #define IEEE80211_VHT_NUM_RATESETS 16 /* Maximum number of rates in a VHT rateset. */ #define IEEE80211_VHT_RATESET_MAX_NRATES 10 /* Number of MCS indices represented by struct ieee80211_vht_rateset. */ #define IEEE80211_VHT_RATESET_NUM_MCS IEEE80211_VHT_RATESET_MAX_NRATES struct ieee80211_vht_rateset { uint32_t nrates; uint32_t rates[IEEE80211_VHT_RATESET_MAX_NRATES]; /* 500 kbit/s units */ /* Number of spatial streams used by rates in this rateset. */ int num_ss; int sgi; }; extern const struct ieee80211_vht_rateset ieee80211_std_ratesets_11ac[]; #define IEEE80211_HE_RATESET_SISO 0 #define IEEE80211_HE_RATESET_MIMO2 1 #define IEEE80211_HE_RATESET_SISO_40 2 #define IEEE80211_HE_RATESET_MIMO2_40 3 #define IEEE80211_HE_RATESET_SISO_80 4 #define IEEE80211_HE_RATESET_MIMO2_80 5 #define IEEE80211_HE_RATESET_SISO_160 6 #define IEEE80211_HE_RATESET_MIMO2_160 7 #define IEEE80211_HE_NUM_RATESETS 8 /* Maximum number of rates in a HT rateset. */ #define IEEE80211_HE_RATESET_MAX_NRATES 12 /* Number of MCS indices represented by struct ieee80211_he_rateset. */ #define IEEE80211_HE_RATESET_NUM_MCS IEEE80211_HE_RATESET_MAX_NRATES struct ieee80211_he_rateset { uint32_t nrates; uint32_t rates[IEEE80211_HE_RATESET_MAX_NRATES]; /* 500 kbit/s units */ /* Number of spatial streams used by rates in this rateset. */ int num_ss; }; extern const struct ieee80211_he_rateset ieee80211_std_ratesets_11ax[]; enum ieee80211_node_state { IEEE80211_STA_CACHE, /* cached node */ IEEE80211_STA_BSS, /* ic->ic_bss, the network we joined */ IEEE80211_STA_AUTH, /* successfully authenticated */ IEEE80211_STA_ASSOC, /* successfully associated */ IEEE80211_STA_COLLECT /* This node remains in the cache while * the driver sends a de-auth message; * afterward it should be freed to make room * for a new node. */ }; #define ieee80211_node_newstate(__ni, __state) \ do { \ (__ni)->ni_state = (__state); \ } while (0) enum ieee80211_node_psstate { IEEE80211_PS_AWAKE, IEEE80211_PS_DOZE }; #define IEEE80211_PS_MAX_QUEUE 50 /* maximum saved packets */ /* Authenticator state machine: 4-Way Handshake (see 8.5.6.1.1) */ enum { RSNA_INITIALIZE, RSNA_AUTHENTICATION, RSNA_AUTHENTICATION_2, RSNA_INITPMK, RSNA_INITPSK, RSNA_PTKSTART, RSNA_PTKCALCNEGOTIATING, RSNA_PTKCALCNEGOTIATING_2, RSNA_PTKINITNEGOTIATING, RSNA_PTKINITDONE, RSNA_DISCONNECT, RSNA_DISCONNECTED }; /* Authenticator state machine: Group Key Handshake (see 8.5.6.1.2) */ enum { RSNA_IDLE, RSNA_REKEYNEGOTIATING, RSNA_REKEYESTABLISHED, RSNA_KEYERROR }; /* Supplicant state machine: 4-Way Handshake (not documented in standard) */ enum { RSNA_SUPP_INITIALIZE, /* not expecting any messages */ RSNA_SUPP_PTKSTART, /* awaiting handshake message 1 */ RSNA_SUPP_PTKNEGOTIATING, /* got message 1 and derived PTK */ RNSA_SUPP_PTKDONE /* got message 3 and authenticated AP */ }; struct ieee80211_rxinfo { u_int32_t rxi_flags; u_int32_t rxi_tstamp; int rxi_rssi; uint8_t rxi_chan; }; #define IEEE80211_RXI_HWDEC 0x00000001 #define IEEE80211_RXI_AMPDU_DONE 0x00000002 #define IEEE80211_RXI_HWDEC_SAME_PN 0x00000004 #define IEEE80211_RXI_SAME_SEQ 0x00000008 /* Block Acknowledgement Record */ struct ieee80211_tx_ba { struct ieee80211_node *ba_ni; /* backpointer for callbacks */ CTimeout* ba_to; int ba_timeout_val; int ba_state; #define IEEE80211_BA_INIT 0 #define IEEE80211_BA_REQUESTED 1 #define IEEE80211_BA_AGREED 2 /* ADDBA parameter set field for this BA agreement. */ u_int16_t ba_params; /* These values are IEEE802.11 frame sequence numbers (0x0-0xfff) */ u_int16_t ba_winstart; u_int16_t ba_winend; /* Number of A-MPDU subframes in reorder buffer. */ u_int16_t ba_winsize; #define IEEE80211_BA_MAX_WINSZ 64 /* corresponds to maximum ADDBA BUFSZ */ u_int8_t ba_token; /* Bitmap for ACK'd frames in the current BA window. */ uint64_t ba_bitmap; }; struct ieee80211_ba_buf { mbuf_t m; struct ieee80211_rxinfo rxi; }; struct ieee80211_rx_ba { struct ieee80211_node *ba_ni; /* backpointer for callbacks */ struct ieee80211_ba_buf *ba_buf; CTimeout* ba_to; int ba_timeout_val; int ba_state; u_int16_t ba_params; u_int16_t ba_winstart; u_int16_t ba_winend; u_int16_t ba_winsize; u_int16_t ba_head; CTimeout* ba_gap_to; #define IEEE80211_BA_GAP_TIMEOUT 300 /* msec */ /* * Counter for frames forced to wait in the reordering buffer * due to a leading gap caused by one or more missing frames. */ int ba_gapwait; /* Counter for consecutive frames which missed the BA window. */ int ba_winmiss; /* Sequence number of previous frame which missed the BA window. */ uint16_t ba_missedsn; /* Window moves forward after this many frames have missed it. */ #define IEEE80211_BA_MAX_WINMISS 8 uint8_t ba_token; }; /* * Node specific information. Note that drivers are expected * to derive from this structure to add device-specific per-node * state. This is done by overriding the ic_node_* methods in * the ieee80211com structure. */ struct ieee80211_node { RB_ENTRY(ieee80211_node) ni_node; struct ieee80211com *ni_ic; /* back-pointer */ u_int ni_refcnt; u_int ni_scangen; /* gen# for timeout scan */ /* hardware */ u_int32_t ni_rstamp; /* recv timestamp */ u_int8_t ni_rssi; /* recv ssi */ /* header */ u_int8_t ni_macaddr[IEEE80211_ADDR_LEN]; u_int8_t ni_bssid[IEEE80211_ADDR_LEN]; /* beacon, probe response */ u_int8_t ni_tstamp[8]; /* from last rcv'd beacon */ u_int16_t ni_intval; /* beacon interval */ u_int16_t ni_capinfo; /* capabilities */ u_int8_t ni_esslen; u_int8_t ni_essid[IEEE80211_NWID_LEN]; struct ieee80211_rateset ni_rates; /* negotiated rate set */ u_int8_t *ni_country; /* country information XXX */ struct ieee80211_channel *ni_chan; u_int8_t ni_erp; /* 11g only */ #ifdef AIRPORT u_int64_t ni_age_ts; #endif /* DTIM and contention free period (CFP) */ u_int8_t ni_dtimcount; u_int8_t ni_dtimperiod; #ifdef notyet u_int8_t ni_cfpperiod; /* # of DTIMs between CFPs */ u_int16_t ni_cfpduremain; /* remaining cfp duration */ u_int16_t ni_cfpmaxduration;/* max CFP duration in TU */ u_int16_t ni_nextdtim; /* time to next DTIM */ u_int16_t ni_timoffset; #endif /* power saving mode */ u_int8_t ni_pwrsave; struct mbuf_queue ni_savedq; /* packets queued for pspoll */ /* RSN */ CTimeout* ni_eapol_to; u_int ni_rsn_state; u_int ni_rsn_supp_state; u_int ni_rsn_gstate; u_int ni_rsn_retries; u_int ni_supported_rsnprotos; u_int ni_rsnprotos; u_int ni_supported_rsnakms; u_int ni_rsnakms; u_int ni_rsnciphers; enum ieee80211_cipher ni_rsngroupcipher; enum ieee80211_cipher ni_rsngroupmgmtcipher; u_int16_t ni_rsncaps; enum ieee80211_cipher ni_rsncipher; u_int8_t ni_nonce[EAPOL_KEY_NONCE_LEN]; u_int8_t ni_pmk[IEEE80211_PMK_LEN]; u_int8_t ni_pmkid[IEEE80211_PMKID_LEN]; u_int64_t ni_replaycnt; u_int8_t ni_replaycnt_ok; u_int64_t ni_reqreplaycnt; u_int8_t ni_reqreplaycnt_ok; u_int8_t *ni_rsnie; u_int8_t *ni_rsnie_tlv; uint32_t ni_rsnie_tlv_len; struct ieee80211_key ni_pairwise_key; struct ieee80211_ptk ni_ptk; u_int8_t ni_key_count; int ni_port_valid; /* SA Query */ u_int16_t ni_sa_query_trid; CTimeout* ni_sa_query_to; int ni_sa_query_count; /* HT capabilities */ uint16_t ni_htcaps; uint8_t ni_ampdu_param; uint8_t ni_rxmcs[howmany(80,NBBY)]; uint16_t ni_max_rxrate; /* in Mb/s, 0 <= rate <= 1023 */ uint8_t ni_tx_mcs_set; uint16_t ni_htxcaps;// extended_ht_cap_info uint32_t ni_txbfcaps; uint8_t ni_aselcaps;// antenna_selection_info /* HT operation */ uint8_t ni_primary_chan; /* XXX corresponds to ni_chan */ uint8_t ni_htop0;// ht_param uint16_t ni_htop1;// operation_mode uint16_t ni_htop2;// stbc_param uint8_t ni_basic_mcs[howmany(128,NBBY)]; uint8_t ni_ht2ndchan; /* HT 2nd channel */ uint8_t ni_chw; /* negotiated channel width */ /* VHT state */ uint32_t ni_vhtcaps; uint16_t ni_vht_basicmcs; uint16_t ni_vht_pad2; struct ieee80211_vht_mcs_info ni_vht_mcsinfo; uint8_t ni_vht_chan1; /* 20/40/80/160 - VHT chan1 */ uint8_t ni_vht_chan2; /* 80+80 - VHT chan2 */ uint8_t ni_vht_chanwidth; /* IEEE80211_VHT_CHANWIDTH_ */ uint8_t ni_vht_pad1; uint32_t ni_vht_spare[8]; /* HE state */ struct ieee80211_he_cap_elem ni_he_cap_elem; /* Fixed portion of the HE capabilities element. */ struct ieee80211_he_mcs_nss_supp ni_he_mcs_nss_supp; /* The supported NSS/MCS combinations. */ uint8_t ni_ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN]; /* Holds the PPE Thresholds data. */ uint32_t ni_he_oper_params; uint16_t ni_he_oper_nss_set; uint8_t ni_he_optional[8]; /* Timeout handlers which trigger Tx Block Ack negotiation. */ CTimeout* ni_addba_req_to[IEEE80211_NUM_TID]; int ni_addba_req_intval[IEEE80211_NUM_TID]; #define IEEE80211_ADDBA_REQ_INTVAL_MAX 30 /* in seconds */ /* Block Ack records */ struct ieee80211_tx_ba ni_tx_ba[IEEE80211_NUM_TID]; struct ieee80211_rx_ba ni_rx_ba[IEEE80211_NUM_TID]; int ni_txmcs; /* current MCS used for TX */ int ni_vht_ss; /* VHT # spatial streams */ uint8_t ni_rx_nss; /* others */ u_int16_t ni_associd; /* assoc response */ u_int16_t ni_txseq; /* seq to be transmitted */ u_int16_t ni_rxseq; /* seq previous received */ u_int16_t ni_qos_txseqs[IEEE80211_NUM_TID]; u_int16_t ni_qos_rxseqs[IEEE80211_NUM_TID]; int ni_fails; /* failure count to associate */ uint32_t ni_assoc_fail; /* assoc failure reasons */ #define IEEE80211_NODE_ASSOCFAIL_CHAN 0x01 #define IEEE80211_NODE_ASSOCFAIL_IBSS 0x02 #define IEEE80211_NODE_ASSOCFAIL_PRIVACY 0x04 #define IEEE80211_NODE_ASSOCFAIL_BASIC_RATE 0x08 #define IEEE80211_NODE_ASSOCFAIL_ESSID 0x10 #define IEEE80211_NODE_ASSOCFAIL_BSSID 0x20 #define IEEE80211_NODE_ASSOCFAIL_WPA_PROTO 0x40 #define IEEE80211_NODE_ASSOCFAIL_WPA_KEY 0x80 int ni_inact; /* inactivity mark count */ int ni_txrate; /* index to ni_rates[] */ int ni_state; u_int32_t ni_flags; /* special-purpose state */ #define IEEE80211_NODE_ERP 0x0001 #define IEEE80211_NODE_QOS 0x0002 #define IEEE80211_NODE_REKEY 0x0004 /* GTK rekeying in progress */ #define IEEE80211_NODE_RXPROT 0x0008 /* RX protection ON */ #define IEEE80211_NODE_TXPROT 0x0010 /* TX protection ON */ #define IEEE80211_NODE_TXRXPROT \ (IEEE80211_NODE_TXPROT | IEEE80211_NODE_RXPROT) #define IEEE80211_NODE_RXMGMTPROT 0x0020 /* RX MMPDU protection ON */ #define IEEE80211_NODE_TXMGMTPROT 0x0040 /* TX MMPDU protection ON */ #define IEEE80211_NODE_MFP 0x0080 /* MFP negotiated */ #define IEEE80211_NODE_PMK 0x0100 /* ni_pmk set */ #define IEEE80211_NODE_PMKID 0x0200 /* ni_pmkid set */ #define IEEE80211_NODE_HT 0x0400 /* HT negotiated */ #define IEEE80211_NODE_SA_QUERY 0x0800 /* SA Query in progress */ #define IEEE80211_NODE_SA_QUERY_FAILED 0x1000 /* last SA Query failed */ #define IEEE80211_NODE_RSN_NEW_PTK 0x2000 /* expecting a new PTK */ #define IEEE80211_NODE_HT_SGI20 0x4000 /* SGI on 20 MHz negotiated */ #define IEEE80211_NODE_HT_SGI40 0x8000 /* SGI on 40 MHz negotiated */ #define IEEE80211_NODE_VHT 0x10000 /* VHT negotiated */ #define IEEE80211_NODE_HTCAP 0x20000 /* claims to support HT */ #define IEEE80211_NODE_VHTCAP 0x40000 /* claims to support VHT */ #define IEEE80211_NODE_VHT_SGI80 0x80000 /* SGI on 80 MHz negotiated */ #define IEEE80211_NODE_VHT_SGI160 0x100000 /* SGI on 160 MHz negotiated */ #define IEEE80211_NODE_HE 0x200000 /* HE negotiated */ /* If not NULL, this function gets called when ni_refcnt hits zero. */ void (*ni_unref_cb)(struct ieee80211com *, struct ieee80211_node *); void * ni_unref_arg; size_t ni_unref_arg_size; #ifdef AIRPORT uint8_t verb[0x1024];//冗余信息 zxy #endif }; RB_HEAD(ieee80211_tree, ieee80211_node); struct ieee80211_ess_rbt { RB_ENTRY(ieee80211_ess_rbt) ess_rbt; u_int8_t esslen; u_int8_t essid[IEEE80211_NWID_LEN]; struct ieee80211_node *ni2; struct ieee80211_node *ni5; struct ieee80211_node *ni; }; RB_HEAD(ieee80211_ess_tree, ieee80211_ess_rbt); static inline void ieee80211_node_incref(struct ieee80211_node *ni) { int s; s = splnet(); ni->ni_refcnt++; splx(s); } static inline u_int ieee80211_node_decref(struct ieee80211_node *ni) { u_int refcnt; int s; s = splnet(); refcnt = --ni->ni_refcnt; splx(s); return refcnt; } static inline struct ieee80211_node * ieee80211_ref_node(struct ieee80211_node *ni) { ieee80211_node_incref(ni); return ni; } static inline void ieee80211_unref_node(struct ieee80211_node **ni) { ieee80211_node_decref(*ni); *ni = NULL; /* guard against use */ } /* * Check if the peer supports HT. * Require a HT capabilities IE and at least one of the mandatory MCS. * MCS 0-7 are mandatory but some APs have particular MCS disabled. */ static inline int ieee80211_node_supports_ht(struct ieee80211_node *ni) { return ((ni->ni_flags & IEEE80211_NODE_HTCAP) && ni->ni_rxmcs[0] & 0xff); } static inline int ieee80211_node_supports_vht(struct ieee80211_node *ni) { return ((ni->ni_flags & IEEE80211_NODE_VHTCAP)); } /* Check if the peer supports HT short guard interval (SGI) on 20 MHz. */ static inline int ieee80211_node_supports_ht_sgi20(struct ieee80211_node *ni) { return ieee80211_node_supports_ht(ni) && (ni->ni_htcaps & IEEE80211_HTCAP_SGI20); } /* Check if the peer supports HT short guard interval (SGI) on 40 MHz. */ static inline int ieee80211_node_supports_ht_sgi40(struct ieee80211_node *ni) { return ieee80211_node_supports_ht(ni) && (ni->ni_htcaps & IEEE80211_HTCAP_SGI40); } /* Check if the peer can receive frames sent on a 40 MHz channel. */ static inline int ieee80211_node_supports_ht_chan40(struct ieee80211_node *ni) { return (ieee80211_node_supports_ht(ni) && (ni->ni_htcaps & IEEE80211_HTCAP_CBW20_40) && (ni->ni_htop0 & IEEE80211_HTOP0_CHW)); } static inline int ieee80211_node_supports_vht_sgi80(struct ieee80211_node *ni) { return ieee80211_node_supports_vht(ni) && (ni->ni_vhtcaps & IEEE80211_VHTCAP_SHORT_GI_80); } static inline int ieee80211_node_supports_vht_sgi160(struct ieee80211_node *ni) { return ieee80211_node_supports_vht(ni) && (ni->ni_vhtcaps & IEEE80211_VHTCAP_SHORT_GI_160); } static inline int ieee80211_node_supports_sgi(struct ieee80211_node *ni) { if (ni->ni_flags & IEEE80211_NODE_HE) return 0; if (ni->ni_flags & IEEE80211_NODE_VHT) { switch (ni->ni_chw) { case IEEE80211_CHAN_WIDTH_20: return ieee80211_node_supports_ht_sgi20(ni); case IEEE80211_CHAN_WIDTH_40: return ieee80211_node_supports_ht_sgi40(ni); case IEEE80211_CHAN_WIDTH_80: return ieee80211_node_supports_vht_sgi80(ni); case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: return ieee80211_node_supports_vht_sgi160(ni); default: return false; } } if (ni->ni_flags & IEEE80211_NODE_HT) { switch (ni->ni_chw) { case IEEE80211_CHAN_WIDTH_20: return ieee80211_node_supports_ht_sgi20(ni); case IEEE80211_CHAN_WIDTH_40: return ieee80211_node_supports_ht_sgi40(ni); default: return false; } } return 0; } struct ieee80211com; typedef void ieee80211_iter_func(void *, struct ieee80211_node *); void ieee80211_node_attach(struct _ifnet *); void ieee80211_node_lateattach(struct _ifnet *); void ieee80211_node_detach(struct _ifnet *); void ieee80211_begin_scan(struct _ifnet *); void ieee80211_next_scan(struct _ifnet *); void ieee80211_end_scan(struct _ifnet *); void ieee80211_reset_scan(struct _ifnet *); struct ieee80211_node *ieee80211_alloc_node(struct ieee80211com *, const u_int8_t *); struct ieee80211_node *ieee80211_dup_bss(struct ieee80211com *, const u_int8_t *); struct ieee80211_node *ieee80211_find_node(struct ieee80211com *, const u_int8_t *); void ieee80211_ba_del(struct ieee80211_node *); void ieee80211_ba_free(struct ieee80211_node *ni); struct ieee80211_node *ieee80211_find_rxnode(struct ieee80211com *, const struct ieee80211_frame *); struct ieee80211_node *ieee80211_find_txnode(struct ieee80211com *, const u_int8_t *); void ieee80211_release_node(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node *); void ieee80211_free_allnodes(struct ieee80211com *, int); void ieee80211_iterate_nodes(struct ieee80211com *, ieee80211_iter_func *, void *); void ieee80211_clean_cached(struct ieee80211com *); void ieee80211_clean_sta_bss_node(struct ieee80211com *); void ieee80211_clean_nodes(struct ieee80211com *, int); void ieee80211_setup_htcaps(struct ieee80211_node *, const uint8_t *, uint8_t); void ieee80211_clear_htcaps(struct ieee80211_node *); int ieee80211_setup_htop(struct ieee80211_node *, const uint8_t *, uint8_t, int); void ieee80211_setup_vhtcaps(struct ieee80211com *, struct ieee80211_node *, const uint8_t *); void ieee80211_setup_vhtopmode(struct ieee80211_node *, const uint8_t *); void ieee80211_clear_vhtcaps(struct ieee80211_node *); void ieee80211_setup_hecaps(struct ieee80211_node *, const uint8_t *, uint8_t); int ieee80211_setup_heop(struct ieee80211_node *, const uint8_t *, uint8_t); int ieee80211_setup_rates(struct ieee80211com *, struct ieee80211_node *, const u_int8_t *, const u_int8_t *, int); void ieee80211_node_trigger_addba_req(struct ieee80211_node *, int); int ieee80211_iserp_sta(const struct ieee80211_node *); void ieee80211_count_longslotsta(void *, struct ieee80211_node *); void ieee80211_count_nonerpsta(void *, struct ieee80211_node *); void ieee80211_count_pssta(void *, struct ieee80211_node *); void ieee80211_count_rekeysta(void *, struct ieee80211_node *); void ieee80211_node_join(struct ieee80211com *, struct ieee80211_node *, int); void ieee80211_node_leave(struct ieee80211com *, struct ieee80211_node *); int ieee80211_match_bss(struct ieee80211com *, struct ieee80211_node *, int); struct ieee80211_node *ieee80211_node_choose_bss(struct ieee80211com *, int, struct ieee80211_node **); void ieee80211_node_join_bss(struct ieee80211com *, struct ieee80211_node *, int force_reauth = 0); void ieee80211_create_ibss(struct ieee80211com* , struct ieee80211_channel *); void ieee80211_notify_dtim(struct ieee80211com *); void ieee80211_set_tim(struct ieee80211com *, int, int); void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *); int ieee80211_node_cmp(const struct ieee80211_node *, const struct ieee80211_node *); int ieee80211_ess_cmp(const struct ieee80211_ess_rbt *, const struct ieee80211_ess_rbt *); RB_PROTOTYPE(ieee80211_tree, ieee80211_node, ni_node, ieee80211_node_cmp); RB_PROTOTYPE(ieee80211_ess_tree, ieee80211_ess_rbt, ess_rbt, ieee80211_ess_cmp); #endif /* _NET80211_IEEE80211_NODE_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_output.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. */ /* $OpenBSD: ieee80211_output.c,v 1.132 2020/12/08 15:52:04 stsp Exp $ */ /* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * Copyright (c) 2007-2009 Damien Bergamini * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET6 #include #endif #if NVLAN > 0 #include #endif #include #include int ieee80211_mgmt_output(struct _ifnet *, struct ieee80211_node *, mbuf_t, int); int ieee80211_can_use_ampdu(struct ieee80211com *, struct ieee80211_node *); u_int8_t *ieee80211_add_rsn_body(u_int8_t *, struct ieee80211com *, const struct ieee80211_node *, int); mbuf_t ieee80211_getmgmt(int, int, u_int); mbuf_t ieee80211_get_probe_req(struct ieee80211com *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY mbuf_t ieee80211_get_probe_resp(struct ieee80211com *, struct ieee80211_node *); #endif mbuf_t ieee80211_get_auth(struct ieee80211com *, struct ieee80211_node *, u_int16_t, u_int16_t); mbuf_t ieee80211_get_deauth(struct ieee80211com *, struct ieee80211_node *, u_int16_t); mbuf_t ieee80211_get_assoc_req(struct ieee80211com *, struct ieee80211_node *, int); #ifndef IEEE80211_STA_ONLY mbuf_t ieee80211_get_assoc_resp(struct ieee80211com *, struct ieee80211_node *, u_int16_t); #endif mbuf_t ieee80211_get_disassoc(struct ieee80211com *, struct ieee80211_node *, u_int16_t); mbuf_t ieee80211_get_addba_req(struct ieee80211com *, struct ieee80211_node *, u_int8_t); mbuf_t ieee80211_get_addba_resp(struct ieee80211com *, struct ieee80211_node *, u_int8_t, u_int8_t, u_int16_t); mbuf_t ieee80211_get_delba(struct ieee80211com *, struct ieee80211_node *, u_int8_t, u_int8_t, u_int16_t); uint8_t *ieee80211_add_wme_info(uint8_t *, struct ieee80211com *); #ifndef IEEE80211_STA_ONLY uint8_t *ieee80211_add_wme_param(uint8_t *, struct ieee80211com *); #endif mbuf_t ieee80211_get_sa_query(struct ieee80211com *, struct ieee80211_node *, u_int8_t); mbuf_t ieee80211_get_action(struct ieee80211com *, struct ieee80211_node *, u_int8_t, u_int8_t, int); /* * IEEE 802.11 output routine. Normally this will directly call the * Ethernet output routine because 802.11 encapsulation is called * later by the driver. This function can be used to send raw frames * if the mbuf has been tagged with a 802.11 data link type. */ int ieee80211_output(struct _ifnet *ifp, mbuf_t m, struct sockaddr *dst, struct rtentry *rt) { XYLog("%s 啊啊啊啊\n", __FUNCTION__); struct ieee80211_frame *wh; struct m_tag *mtag; int error = 0; //TODO // // /* Interface has to be up and running */ // if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != // (IFF_UP | IFF_RUNNING)) { // error = ENETDOWN; // goto bad; // } // // /* Try to get the DLT from a mbuf tag */ // if ((mtag = m_tag_find(m, PACKET_TAG_DLT, NULL)) != NULL) { // struct ieee80211com *ic = (struct ieee80211com *)ifp; // u_int dlt = *(u_int *)(mtag + 1); // // /* Fallback to ethernet for non-802.11 linktypes */ // if (!(dlt == DLT_IEEE802_11 || dlt == DLT_IEEE802_11_RADIO)) // goto fallback; // // if (mbuf_pkthdr_len(m) < sizeof(struct ieee80211_frame_min)) // return (EINVAL); // wh = mtod(m, struct ieee80211_frame *); // if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != // IEEE80211_FC0_VERSION_0) // return (EINVAL); // if (!(ic->ic_caps & IEEE80211_C_RAWCTL) && // (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == // IEEE80211_FC0_TYPE_CTL) // return (EINVAL); // // return (if_enqueue(ifp, m)); // } fallback: return (if_enqueue(ifp, m)); bad: mbuf_freem(m); return (error); } const char * ieee80211_action_name(struct ieee80211_frame *wh) { const u_int8_t *frm = (const uint8_t *)&wh[1]; const char *categ_ba_name[3] = { "addba_req", "addba_resp", "delba" }; if (frm[0] == IEEE80211_CATEG_BA && frm[1] < nitems(categ_ba_name)) return categ_ba_name[frm[1]]; return "action"; } /* * Send a management frame to the specified node. The node pointer * must have a reference as the pointer will be passed to the driver * and potentially held for a long time. If the frame is successfully * dispatched to the driver, then it is responsible for freeing the * reference (and potentially free'ing up any associated storage). */ int ieee80211_mgmt_output(struct _ifnet *ifp, struct ieee80211_node *ni, mbuf_t m, int type) { struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ieee80211_frame *wh; if (ni == NULL) panic("null node"); ni->ni_inact = 0; /* * We want to pass the node down to the driver's start * routine. We could stick this in an m_tag and tack that * on to the mbuf. However that's rather expensive to do * for every frame so instead we stuff it in a special pkthdr * field. */ mbuf_prepend(&m, sizeof(struct ieee80211_frame), MBUF_DONTWAIT); if (m == NULL) return ENOMEM; mbuf_pkthdr_setrcvif(m, (ifnet_t)ni); wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)&wh->i_dur[0] = 0; *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseq = (ni->ni_txseq + 1) & 0xfff; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); /* check if protection is required for this mgmt frame */ if ((ic->ic_caps & IEEE80211_C_MFP) && (type == IEEE80211_FC0_SUBTYPE_DISASSOC || type == IEEE80211_FC0_SUBTYPE_DEAUTH || type == IEEE80211_FC0_SUBTYPE_ACTION)) { /* * Hack: we should not set the Protected bit in outgoing * group management frames, however it is used as an * indication to the drivers that they must encrypt the * frame. Drivers should clear this bit from group * management frames (software crypto code will do it). * XXX could use an mbuf flag.. */ if (IEEE80211_IS_MULTICAST(wh->i_addr1) || (ni->ni_flags & IEEE80211_NODE_TXMGMTPROT)) wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; } if (ifp->if_flags & IFF_DEBUG) { /* avoid to print too many frames */ if ( #ifndef IEEE80211_STA_ONLY ic->ic_opmode == IEEE80211_M_IBSS || #endif #ifdef IEEE80211_DEBUG ieee80211_debug > 1 || #endif (type & IEEE80211_FC0_SUBTYPE_MASK) != IEEE80211_FC0_SUBTYPE_PROBE_RESP) { const char *subtype_name; if ((type & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_ACTION) subtype_name = ieee80211_action_name(wh); else subtype_name = ieee80211_mgt_subtype_name[ (type & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT]; XYLog("%s: sending %s to %s on channel %u mode %s\n", ifp->if_xname, subtype_name, ether_sprintf(ni->ni_macaddr), ieee80211_chan2ieee(ic, ni->ni_chan), ieee80211_phymode_name[ic->ic_curmode]); } } #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP && ieee80211_pwrsave(ic, m, ni) != 0) return 0; #endif mq_enqueue(&ic->ic_mgtq, m); ifp->if_timer = 1; ifp->if_start(ifp); return 0; } /*- * EDCA tables are computed using the following formulas: * * 1) EDCATable (non-AP QSTA) * * AC CWmin CWmax AIFSN TXOP limit(ms) * ------------------------------------------------------------- * AC_BK aCWmin aCWmax 7 0 * AC_BE aCWmin aCWmax 3 0 * AC_VI (aCWmin+1)/2-1 aCWmin 2 agn=3.008 b=6.016 others=0 * AC_VO (aCWmin+1)/4-1 (aCWmin+1)/2-1 2 agn=1.504 b=3.264 others=0 * * 2) QAPEDCATable (QAP) * * AC CWmin CWmax AIFSN TXOP limit(ms) * ------------------------------------------------------------- * AC_BK aCWmin aCWmax 7 0 * AC_BE aCWmin 4*(aCWmin+1)-1 3 0 * AC_VI (aCWmin+1)/2-1 aCWmin 1 agn=3.008 b=6.016 others=0 * AC_VO (aCWmin+1)/4-1 (aCWmin+1)/2-1 1 agn=1.504 b=3.264 others=0 * * and the following aCWmin/aCWmax values: * * PHY aCWmin aCWmax * --------------------------- * 11A 15 1023 * 11B 31 1023 * 11G 15* 1023 (*) aCWmin(1) * 11N 15 1023 */ const struct ieee80211_edca_ac_params ieee80211_edca_table[IEEE80211_MODE_MAX][EDCA_NUM_AC] = { [IEEE80211_MODE_11B] = { [EDCA_AC_BK] = { 5, 10, 7, 0 }, [EDCA_AC_BE] = { 5, 10, 3, 0 }, [EDCA_AC_VI] = { 4, 5, 2, 188 }, [EDCA_AC_VO] = { 3, 4, 2, 102 } }, [IEEE80211_MODE_11A] = { [EDCA_AC_BK] = { 4, 10, 7, 0 }, [EDCA_AC_BE] = { 4, 10, 3, 0 }, [EDCA_AC_VI] = { 3, 4, 2, 94 }, [EDCA_AC_VO] = { 2, 3, 2, 47 } }, [IEEE80211_MODE_11G] = { [EDCA_AC_BK] = { 4, 10, 7, 0 }, [EDCA_AC_BE] = { 4, 10, 3, 0 }, [EDCA_AC_VI] = { 3, 4, 2, 94 }, [EDCA_AC_VO] = { 2, 3, 2, 47 } }, [IEEE80211_MODE_11N] = { [EDCA_AC_BK] = { 4, 10, 7, 0 }, [EDCA_AC_BE] = { 4, 10, 3, 0 }, [EDCA_AC_VI] = { 3, 4, 2, 94 }, [EDCA_AC_VO] = { 2, 3, 2, 47 } }, [IEEE80211_MODE_11AC] = { [EDCA_AC_BK] = { 4, 10, 7, 0 }, [EDCA_AC_BE] = { 4, 10, 3, 0 }, [EDCA_AC_VI] = { 3, 4, 2, 94 }, [EDCA_AC_VO] = { 2, 3, 2, 47 } }, }; #ifndef IEEE80211_STA_ONLY const struct ieee80211_edca_ac_params ieee80211_qap_edca_table[IEEE80211_MODE_MAX][EDCA_NUM_AC] = { [IEEE80211_MODE_11B] = { [EDCA_AC_BK] = { 5, 10, 7, 0 }, [EDCA_AC_BE] = { 5, 7, 3, 0 }, [EDCA_AC_VI] = { 4, 5, 1, 188 }, [EDCA_AC_VO] = { 3, 4, 1, 102 } }, [IEEE80211_MODE_11A] = { [EDCA_AC_BK] = { 4, 10, 7, 0 }, [EDCA_AC_BE] = { 4, 6, 3, 0 }, [EDCA_AC_VI] = { 3, 4, 1, 94 }, [EDCA_AC_VO] = { 2, 3, 1, 47 } }, [IEEE80211_MODE_11G] = { [EDCA_AC_BK] = { 4, 10, 7, 0 }, [EDCA_AC_BE] = { 4, 6, 3, 0 }, [EDCA_AC_VI] = { 3, 4, 1, 94 }, [EDCA_AC_VO] = { 2, 3, 1, 47 } }, [IEEE80211_MODE_11N] = { [EDCA_AC_BK] = { 4, 10, 7, 0 }, [EDCA_AC_BE] = { 4, 6, 3, 0 }, [EDCA_AC_VI] = { 3, 4, 1, 94 }, [EDCA_AC_VO] = { 2, 3, 1, 47 } }, [IEEE80211_MODE_11AC] = { [EDCA_AC_BK] = { 4, 10, 7, 0 }, [EDCA_AC_BE] = { 4, 6, 3, 0 }, [EDCA_AC_VI] = { 3, 4, 1, 94 }, [EDCA_AC_VO] = { 2, 3, 1, 47 } }, }; #endif /* IEEE80211_STA_ONLY */ /* * Return the EDCA Access Category to be used for transmitting a frame with * user-priority `up'. */ enum ieee80211_edca_ac ieee80211_up_to_ac(struct ieee80211com *ic, int up) { /* see Table 9-1 */ static const enum ieee80211_edca_ac up_to_ac[] = { EDCA_AC_BE, /* BE */ EDCA_AC_BK, /* BK */ EDCA_AC_BK, /* -- */ EDCA_AC_BE, /* EE */ EDCA_AC_VI, /* CL */ EDCA_AC_VI, /* VI */ EDCA_AC_VO, /* VO */ EDCA_AC_VO /* NC */ }; enum ieee80211_edca_ac ac; ac = (up <= 7) ? up_to_ac[up] : EDCA_AC_BE; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) return ac; #endif /* * We do not support the admission control procedure defined in * IEEE Std 802.11-2012 section 9.19.4.2.3. The spec says that * non-AP QSTAs that don't support this procedure shall use EDCA * parameters of a lower priority AC that does not require * admission control. */ while (ac != EDCA_AC_BK && ic->ic_edca_ac[ac].ac_acm) { switch (ac) { case EDCA_AC_BK: /* can't get there */ break; case EDCA_AC_BE: /* BE shouldn't require admission control */ ac = EDCA_AC_BK; break; case EDCA_AC_VI: ac = EDCA_AC_BE; break; case EDCA_AC_VO: ac = EDCA_AC_VI; break; } } return ac; } /* * Get mbuf's user-priority: if mbuf is not VLAN tagged, select user-priority * based on the DSCP (Differentiated Services Codepoint) field. */ int ieee80211_classify(struct ieee80211com *ic, mbuf_t m) { struct ether_header eh; u_int8_t ds_field; #if NVLAN > 0 if (m->m_flags & M_VLANTAG) /* use VLAN 802.1D user-priority */ return EVL_PRIOFTAG(m->m_pkthdr.ether_vtag); #endif mbuf_copydata(m, 0, sizeof(eh), (caddr_t)&eh); if (eh.ether_type == htons(ETHERTYPE_IP)) { struct ip ip; mbuf_copydata(m, sizeof(eh), sizeof(ip), (caddr_t)&ip); if (ip.ip_v != 4) return 0; ds_field = ip.ip_tos; } #ifdef INET6 else if (eh.ether_type == htons(ETHERTYPE_IPV6)) { struct ip6_hdr ip6; u_int32_t flowlabel; mbuf_copydata(m, sizeof(eh), sizeof(ip6), (caddr_t)&ip6); flowlabel = ntohl(ip6.ip6_flow); if ((flowlabel >> 28) != 6) return 0; ds_field = (flowlabel >> 20) & 0xff; } #endif /* INET6 */ else /* neither IPv4 nor IPv6 */ return 0; /* * Map Differentiated Services Codepoint field (see RFC2474). * Preserves backward compatibility with IP Precedence field. */ switch (ds_field & 0xfc) { case IPTOS_PREC_PRIORITY: return EDCA_AC_VI; case IPTOS_PREC_IMMEDIATE: return EDCA_AC_BK; case IPTOS_PREC_FLASH: case IPTOS_PREC_FLASHOVERRIDE: case IPTOS_PREC_CRITIC_ECP: case IPTOS_PREC_INTERNETCONTROL: case IPTOS_PREC_NETCONTROL: return EDCA_AC_VO; default: return EDCA_AC_BE; } } int ieee80211_can_use_ampdu(struct ieee80211com *ic, struct ieee80211_node *ni) { return (ni->ni_flags & IEEE80211_NODE_HT) && (ic->ic_caps & IEEE80211_C_TX_AMPDU) && !(ic->ic_opmode == IEEE80211_M_STA && ni != ic->ic_bss) && /* * Don't use A-MPDU on non-encrypted networks. There are devices * with buggy firmware which allow an attacker to inject 802.11 * frames into a wifi network by embedding rouge A-MPDU subframes * in an arbitrary data payload (e.g. PNG images) which may end * up appearing as actual frames after de-aggregation by a buggy * device; see https://github.com/rpp0/aggr-inject for details. * WPA2 prevents this injection attack since the attacker would * need to inject frames which get decrypted correctly. */ ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)); } void ieee80211_tx_compressed_bar(struct ieee80211com *ic, struct ieee80211_node *ni, int tid, uint16_t ssn) { struct _ifnet *ifp = &ic->ic_if; mbuf_t m; m = ieee80211_get_compressed_bar(ic, ni, tid, ssn); if (m == NULL) return; ieee80211_ref_node(ni); if (mq_enqueue(&ic->ic_mgtq, m) == 0) ifp->if_start(ifp); else ieee80211_release_node(ic, ni); } /* * Encapsulate an outbound data frame. The mbuf chain is updated and * a reference to the destination node is returned. If an error is * encountered NULL is returned and the node reference will also be NULL. * * NB: The caller is responsible for free'ing a returned node reference. * The convention is ic_bss is not reference counted; the caller must * maintain that. */ mbuf_t ieee80211_encap(struct _ifnet *ifp, mbuf_t m, struct ieee80211_node **pni) { struct ieee80211com *ic = (struct ieee80211com *)ifp; struct ether_header eh; struct ieee80211_frame *wh; struct ieee80211_node *ni = NULL; struct llc *llc; mbuf_tag_id_t mtag; u_int8_t *addr; u_int dlt, hdrlen; int addqos, tid = 0; /* Handle raw frames if mbuf is tagged as 802.11 */ if (0) { // if (mbuf_tag_find(m, mtag, (mbuf_tag_type_t)PACKET_TAG_DLT, &tag_len, (void**)&tag_data) == 0) { // if ((mtag = m_tag_find(m, PACKET_TAG_DLT, NULL)) != NULL) { dlt = *(u_int *)(mtag + 1); if (!(dlt == DLT_IEEE802_11 || dlt == DLT_IEEE802_11_RADIO)) goto fallback; wh = mtod(m, struct ieee80211_frame *); switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: case IEEE80211_FC1_DIR_FROMDS: addr = wh->i_addr1; break; case IEEE80211_FC1_DIR_DSTODS: case IEEE80211_FC1_DIR_TODS: addr = wh->i_addr3; break; default: goto bad; } ni = ieee80211_find_txnode(ic, addr); if (ni == NULL) ni = ieee80211_ref_node(ic->ic_bss); if (ni == NULL) { XYLog("%s: no node for dst %s, " "discard raw tx frame\n", ifp->if_xname, ether_sprintf(addr)); ic->ic_stats.is_tx_nonode++; goto bad; } ni->ni_inact = 0; *pni = ni; return (m); } fallback: if (mbuf_len(m) < sizeof(struct ether_header)) { mbuf_pullup(&m, sizeof(struct ether_header)); if (m == NULL) { ic->ic_stats.is_tx_nombuf++; goto bad; } } memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header)); ni = ieee80211_find_txnode(ic, eh.ether_dhost); if (ni == NULL) { DPRINTF(("no node for dst %s, discard frame\n", ether_sprintf(eh.ether_dhost))); ic->ic_stats.is_tx_nonode++; goto bad; } #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP && ni != ic->ic_bss && ni->ni_state != IEEE80211_STA_ASSOC) { ic->ic_stats.is_tx_nonode++; goto bad; } #endif if ((ic->ic_flags & IEEE80211_F_RSNON) && !ni->ni_port_valid && eh.ether_type != htons(ETHERTYPE_PAE)) { DPRINTF(("port not valid: %s\n", ether_sprintf(eh.ether_dhost))); ic->ic_stats.is_tx_noauth++; goto bad; } if ((ic->ic_flags & IEEE80211_F_COUNTERM) && ni->ni_rsncipher == IEEE80211_CIPHER_TKIP) /* XXX TKIP countermeasures! */; ni->ni_inact = 0; if ((ic->ic_flags & IEEE80211_F_QOS) && (ni->ni_flags & IEEE80211_NODE_QOS) && /* do not QoS-encapsulate EAPOL frames */ eh.ether_type != htons(ETHERTYPE_PAE)) { struct ieee80211_tx_ba *ba; tid = ieee80211_classify(ic, m); ba = &ni->ni_tx_ba[tid]; /* We use QoS data frames for aggregation only. */ if (ba->ba_state != IEEE80211_BA_AGREED) { hdrlen = sizeof(struct ieee80211_frame); addqos = 0; if ((ic->ic_caps & IEEE80211_C_TX_AMPDU_SETUP_IN_RS) == 0 && ieee80211_can_use_ampdu(ic, ni)) ieee80211_node_trigger_addba_req(ni, tid); } else { hdrlen = sizeof(struct ieee80211_qosframe); addqos = 1; } } else { hdrlen = sizeof(struct ieee80211_frame); addqos = 0; } mbuf_adj(m, sizeof(struct ether_header) - LLC_SNAPFRAMELEN); llc = mtod(m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; llc->llc_snap.org_code[0] = 0; llc->llc_snap.org_code[1] = 0; llc->llc_snap.org_code[2] = 0; llc->llc_snap.ether_type = eh.ether_type; mbuf_prepend(&m, hdrlen, MBUF_DONTWAIT); if (m == NULL) { ic->ic_stats.is_tx_nombuf++; goto bad; } wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; *(u_int16_t *)&wh->i_dur[0] = 0; if (addqos) { struct ieee80211_qosframe *qwh = (struct ieee80211_qosframe *)wh; u_int16_t qos = tid; if (ic->ic_tid_noack & (1 << tid)) qos |= IEEE80211_QOS_ACK_POLICY_NOACK; else { /* Use HT immediate block-ack. */ qos |= IEEE80211_QOS_ACK_POLICY_NORMAL; } qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; *(u_int16_t *)qwh->i_qos = htole16(qos); *(u_int16_t *)qwh->i_seq = htole16(ni->ni_qos_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_qos_txseqs[tid] = (ni->ni_qos_txseqs[tid] + 1) & 0xfff; } else { *(u_int16_t *)&wh->i_seq[0] = htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseq = (ni->ni_txseq + 1) & 0xfff; } switch (ic->ic_opmode) { case IEEE80211_M_STA: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); break; case IEEE80211_M_HOSTAP: wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); break; #endif default: /* should not get there */ goto bad; } if ((ic->ic_flags & IEEE80211_F_WEPON) || ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_flags & IEEE80211_NODE_TXPROT))) wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP && ieee80211_pwrsave(ic, m, ni) != 0) { *pni = NULL; return NULL; } #endif *pni = ni; return m; bad: mbuf_freem(m); if (ni != NULL) ieee80211_release_node(ic, ni); *pni = NULL; return NULL; } /* * Add a Capability Information field to a frame (see 7.3.1.4). */ u_int8_t * ieee80211_add_capinfo(u_int8_t *frm, struct ieee80211com *ic, const struct ieee80211_node *ni) { u_int16_t capinfo; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else if (ic->ic_opmode == IEEE80211_M_HOSTAP) capinfo = IEEE80211_CAPINFO_ESS; else #endif capinfo = 0; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP && (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON))) capinfo |= IEEE80211_CAPINFO_PRIVACY; #endif /* NB: some 11a AP's reject the request when short preamble is set */ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; LE_WRITE_2(frm, capinfo); return frm + 2; } /* * Add an SSID element to a frame (see 7.3.2.1). */ u_int8_t * ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len) { *frm++ = IEEE80211_ELEMID_SSID; *frm++ = len; memcpy(frm, ssid, len); return frm + len; } /* * Add a supported rates element to a frame (see 7.3.2.2). */ u_int8_t * ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs) { int nrates; *frm++ = IEEE80211_ELEMID_RATES; nrates = min(rs->rs_nrates, IEEE80211_RATE_SIZE); *frm++ = nrates; memcpy(frm, rs->rs_rates, nrates); return frm + nrates; } #ifndef IEEE80211_STA_ONLY /* * Add a DS Parameter Set element to a frame (see 7.3.2.4). */ u_int8_t * ieee80211_add_ds_params(u_int8_t *frm, struct ieee80211com *ic, const struct ieee80211_node *ni) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); return frm; } /* * Add a TIM element to a frame (see 7.3.2.6 and Annex L). */ u_int8_t * ieee80211_add_tim(u_int8_t *frm, struct ieee80211com *ic) { u_int i, offset = 0, len; /* find first non-zero octet in the virtual bit map */ for (i = 0; i < ic->ic_tim_len && ic->ic_tim_bitmap[i] == 0; i++); /* clear the lsb as it is reserved for the broadcast indication bit */ if (i < ic->ic_tim_len) offset = i & ~1; /* find last non-zero octet in the virtual bit map */ for (i = ic->ic_tim_len - 1; i > 0 && ic->ic_tim_bitmap[i] == 0; i--); len = i - offset + 1; *frm++ = IEEE80211_ELEMID_TIM; *frm++ = len + 3; /* length */ *frm++ = ic->ic_dtim_count; /* DTIM count */ *frm++ = ic->ic_dtim_period; /* DTIM period */ /* Bitmap Control */ *frm = offset; /* set broadcast/multicast indication bit if necessary */ if (ic->ic_dtim_count == 0 && ic->ic_tim_mcast_pending) *frm |= 0x01; frm++; /* Partial Virtual Bitmap */ memcpy(frm, &ic->ic_tim_bitmap[offset], len); return frm + len; } /* * Add an IBSS Parameter Set element to a frame (see 7.3.2.7). */ u_int8_t * ieee80211_add_ibss_params(u_int8_t *frm, const struct ieee80211_node *ni) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; LE_WRITE_2(frm, 0); /* TODO: ATIM window */ return frm + 2; } /* * Add an EDCA Parameter Set element to a frame (see 7.3.2.29). */ u_int8_t * ieee80211_add_edca_params(u_int8_t *frm, struct ieee80211com *ic) { const struct ieee80211_edca_ac_params *edca; int aci; *frm++ = IEEE80211_ELEMID_EDCAPARMS; *frm++ = 18; /* length */ *frm++ = 0; /* QoS Info */ *frm++ = 0; /* reserved */ /* setup AC Parameter Records */ edca = ieee80211_edca_table[ic->ic_curmode]; for (aci = 0; aci < EDCA_NUM_AC; aci++) { const struct ieee80211_edca_ac_params *ac = &edca[aci]; *frm++ = (aci << 5) | ((ac->ac_acm & 0x1) << 4) | (ac->ac_aifsn & 0xf); *frm++ = (ac->ac_ecwmax << 4) | (ac->ac_ecwmin & 0xf); LE_WRITE_2(frm, ac->ac_txoplimit); frm += 2; } return frm; } /* * Add an ERP element to a frame (see 7.3.2.13). */ u_int8_t * ieee80211_add_erp(u_int8_t *frm, struct ieee80211com *ic) { u_int8_t erp; int nonerpsta = 0; *frm++ = IEEE80211_ELEMID_ERP; *frm++ = 1; erp = 0; /* * The NonERP_Present bit shall be set to 1 when a NonERP STA * is associated with the BSS. */ ieee80211_iterate_nodes(ic, ieee80211_count_nonerpsta, &nonerpsta); if (nonerpsta != 0) erp |= IEEE80211_ERP_NON_ERP_PRESENT; /* * If one or more NonERP STAs are associated in the BSS, the * Use_Protection bit shall be set to 1 in transmitted ERP * Information Elements. */ if (ic->ic_flags & IEEE80211_F_USEPROT) erp |= IEEE80211_ERP_USE_PROTECTION; /* * The Barker_Preamble_Mode bit shall be set to 1 by the ERP * Information Element sender if one or more associated NonERP * STAs are not short preamble capable. */ if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE)) erp |= IEEE80211_ERP_BARKER_MODE; *frm++ = erp; return frm; } #endif /* IEEE80211_STA_ONLY */ /* * Add a QoS Capability element to a frame (see 7.3.2.35). */ u_int8_t * ieee80211_add_qos_capability(u_int8_t *frm, struct ieee80211com *ic) { *frm++ = IEEE80211_ELEMID_QOS_CAP; *frm++ = 1; *frm++ = 0; /* QoS Info */ return frm; } #define WME_OUI_BYTES 0x00, 0x50, 0xf2 /* * Add a Wifi-Alliance WME (aka WMM) info element to a frame. * WME is a requirement for Wifi-Alliance compliance and some * 11n APs will not negotiate HT if this element is missing. */ uint8_t * ieee80211_add_wme_info(uint8_t *frm, struct ieee80211com *ic) { static const struct ieee80211_wme_info info = { .wme_id = IEEE80211_ELEMID_VENDOR, .wme_len = sizeof(struct ieee80211_wme_info) - 2, .wme_oui = { WME_OUI_BYTES }, .wme_type = WME_OUI_TYPE, .wme_subtype = WME_INFO_OUI_SUBTYPE, .wme_version = WME_VERSION, .wme_info = 0, }; memcpy(frm, &info, sizeof(info)); return frm + sizeof(info); } #ifndef IEEE80211_STA_ONLY /* * Add a Wifi-Alliance WMM (aka WME) parameter element to a frame. */ uint8_t * ieee80211_add_wme_param(uint8_t *frm, struct ieee80211com *ic) { const struct ieee80211_edca_ac_params *edca; int aci; *frm++ = IEEE80211_ELEMID_VENDOR; *frm++ = 24; memcpy(frm, MICROSOFT_OUI, 3); frm += 3; *frm++ = 2; /* OUI type */ *frm++ = 1; /* OUI subtype */ *frm++ = 1; /* version */ *frm++ = 0; /* info */ *frm++ = 0; /* reserved */ /* setup AC Parameter Records */ edca = ieee80211_edca_table[ic->ic_curmode]; for (aci = 0; aci < EDCA_NUM_AC; aci++) { const struct ieee80211_edca_ac_params *ac = &edca[aci]; *frm++ = (aci << 5) | ((ac->ac_acm & 0x1) << 4) | (ac->ac_aifsn & 0xf); *frm++ = (ac->ac_ecwmax << 4) | (ac->ac_ecwmin & 0xf); LE_WRITE_2(frm, ac->ac_txoplimit); frm += 2; } return frm; } #endif /* * Add an RSN element to a frame (see 802.11-2012 8.4.2.27) */ u_int8_t * ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic, const struct ieee80211_node *ni, int wpa) { const u_int8_t *oui = wpa ? MICROSOFT_OUI : IEEE80211_OUI; u_int8_t *pcount; u_int16_t count, rsncaps; /* write Version field */ LE_WRITE_2(frm, 1); frm += 2; /* write Group Data Cipher Suite field (see 802.11-2012 Table 8-99) */ memcpy(frm, oui, 3); frm += 3; switch (ni->ni_rsngroupcipher) { case IEEE80211_CIPHER_WEP40: *frm++ = 1; break; case IEEE80211_CIPHER_TKIP: *frm++ = 2; break; case IEEE80211_CIPHER_CCMP: *frm++ = 4; break; case IEEE80211_CIPHER_WEP104: *frm++ = 5; break; default: /* can't get there */ panic("invalid group data cipher!"); } pcount = frm; frm += 2; count = 0; /* write Pairwise Cipher Suite List */ if (ni->ni_rsnciphers & IEEE80211_CIPHER_USEGROUP) { memcpy(frm, oui, 3); frm += 3; *frm++ = 0; count++; } if (ni->ni_rsnciphers & IEEE80211_CIPHER_TKIP) { memcpy(frm, oui, 3); frm += 3; *frm++ = 2; count++; } if (ni->ni_rsnciphers & IEEE80211_CIPHER_CCMP) { memcpy(frm, oui, 3); frm += 3; *frm++ = 4; count++; } /* write Pairwise Cipher Suite Count field */ LE_WRITE_2(pcount, count); pcount = frm; frm += 2; count = 0; /* write AKM Suite List (see Table 20dc) */ if (ni->ni_rsnakms & IEEE80211_AKM_8021X) { memcpy(frm, oui, 3); frm += 3; *frm++ = 1; count++; } if (ni->ni_rsnakms & IEEE80211_AKM_PSK) { memcpy(frm, oui, 3); frm += 3; *frm++ = 2; count++; } if (!wpa && (ni->ni_rsnakms & IEEE80211_AKM_SHA256_8021X)) { memcpy(frm, oui, 3); frm += 3; *frm++ = 5; count++; } if (!wpa && (ni->ni_rsnakms & IEEE80211_AKM_SHA256_PSK)) { memcpy(frm, oui, 3); frm += 3; *frm++ = 6; count++; } /* write AKM Suite List Count field */ LE_WRITE_2(pcount, count); if (wpa) return frm; /* write RSN Capabilities field */ rsncaps = (ni->ni_rsncaps & (IEEE80211_RSNCAP_PTKSA_RCNT_MASK | IEEE80211_RSNCAP_GTKSA_RCNT_MASK)); if (ic->ic_caps & IEEE80211_C_MFP) { rsncaps |= IEEE80211_RSNCAP_MFPC; if (ic->ic_flags & IEEE80211_F_MFPR) rsncaps |= IEEE80211_RSNCAP_MFPR; } if (ic->ic_flags & IEEE80211_F_PBAR) rsncaps |= IEEE80211_RSNCAP_PBAC; LE_WRITE_2(frm, rsncaps); frm += 2; if (ni->ni_flags & IEEE80211_NODE_PMKID) { /* write PMKID Count field */ LE_WRITE_2(frm, 1); frm += 2; /* write PMKID List (only 1) */ memcpy(frm, ni->ni_pmkid, IEEE80211_PMKID_LEN); frm += IEEE80211_PMKID_LEN; } if (!(ic->ic_caps & IEEE80211_C_MFP)) return frm; if ((ni->ni_flags & IEEE80211_NODE_PMKID) == 0) { /* no PMKID (PMKID Count=0) */ LE_WRITE_2(frm, 0); frm += 2; } /* write Group Integrity Cipher Suite field */ memcpy(frm, oui, 3); frm += 3; switch (ic->ic_rsngroupmgmtcipher) { case IEEE80211_CIPHER_BIP: *frm++ = 6; break; default: /* can't get there */ panic("invalid integrity group cipher!"); } return frm; } u_int8_t * ieee80211_add_rsn(u_int8_t *frm, struct ieee80211com *ic, const struct ieee80211_node *ni) { u_int8_t *plen; *frm++ = IEEE80211_ELEMID_RSN; plen = frm++; /* length filled in later */ frm = ieee80211_add_rsn_body(frm, ic, ni, 0); /* write length field */ *plen = frm - plen - 1; return frm; } /* * Add a vendor-specific WPA element to a frame. * This is required for compatibility with Wi-Fi Alliance WPA. */ u_int8_t * ieee80211_add_wpa(u_int8_t *frm, struct ieee80211com *ic, const struct ieee80211_node *ni) { u_int8_t *plen; *frm++ = IEEE80211_ELEMID_VENDOR; plen = frm++; /* length filled in later */ memcpy(frm, MICROSOFT_OUI, 3); frm += 3; *frm++ = 1; /* WPA */ frm = ieee80211_add_rsn_body(frm, ic, ni, 1); /* write length field */ *plen = frm - plen - 1; return frm; } /* * Add an extended supported rates element to a frame (see 7.3.2.14). */ u_int8_t * ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs) { int nrates; _KASSERT(rs->rs_nrates > IEEE80211_RATE_SIZE); *frm++ = IEEE80211_ELEMID_XRATES; nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; *frm++ = nrates; memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); return frm + nrates; } uint8_t * ieee80211_add_ht_ie(uint8_t *frm, struct ieee80211com *ic, struct ieee80211_node *ni) { *frm++ = IEEE80211_ELEMID_HTCAPS; *frm++ = 26; uint16_t cap = ni->ni_htcaps;; cap |= ic->ic_htcaps; switch (ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK) { XYLog("%s line=%d\n", __FUNCTION__, __LINE__); case IEEE80211_HTOP0_SCO_SCA: XYLog("%s line=%d\n", __FUNCTION__, __LINE__); if (ni->ni_chan != NULL) { XYLog("%s line=%d\n", __FUNCTION__, __LINE__); if ((ni->ni_chan->ic_flags & IEEE80211_CHAN_HT40U) == 0) { XYLog("%s line=%d\n", __FUNCTION__, __LINE__); cap &= ~IEEE80211_HTCAP_CBW20_40; cap &= ~IEEE80211_HTCAP_SGI40; } } break; case IEEE80211_HTOP0_SCO_SCB: XYLog("%s line=%d\n", __FUNCTION__, __LINE__); if (ni->ni_chan != NULL) { XYLog("%s line=%d\n", __FUNCTION__, __LINE__); if ((ni->ni_chan->ic_flags & IEEE80211_CHAN_HT40D) == 0) { XYLog("%s line=%d\n", __FUNCTION__, __LINE__); cap &= ~IEEE80211_HTCAP_CBW20_40; cap &= ~IEEE80211_HTCAP_SGI40; } } break; default: break; } LE_WRITE_2(frm, cap); frm += 2; *frm++ = ic->ic_ampdu_params; memcpy(frm, ic->ic_sup_mcs, 10); frm += 10;// rx_mask LE_WRITE_2(frm, (ic->ic_max_rxrate & IEEE80211_MCS_RX_RATE_HIGH)); frm += 2;// rx_highest *frm++ = ic->ic_tx_mcs_set;// tx_params *frm++ = 0; /* reserved */ *frm++ = 0; /* reserved */ *frm++ = 0; /* reserved */ LE_WRITE_2(frm, ic->ic_htxcaps); frm += 2; LE_WRITE_4(frm, ic->ic_txbfcaps); frm += 4; *frm++ = ic->ic_aselcaps; return frm; } /* * Add an HT Capabilities element to a frame (see 7.3.2.57). */ uint8_t * ieee80211_add_htcaps(uint8_t *frm, struct ieee80211com *ic) { *frm++ = IEEE80211_ELEMID_HTCAPS; *frm++ = sizeof(struct ieee80211_ie_htcap) - 2; LE_WRITE_2(frm, ic->ic_htcaps); frm += 2; *frm++ = ic->ic_ampdu_params; memcpy(frm, ic->ic_sup_mcs, 10); frm += 10; LE_WRITE_2(frm, (ic->ic_max_rxrate & IEEE80211_MCS_RX_RATE_HIGH)); frm += 2; *frm++ = ic->ic_tx_mcs_set; *frm++ = 0; /* reserved */ *frm++ = 0; /* reserved */ *frm++ = 0; /* reserved */ LE_WRITE_2(frm, ic->ic_htxcaps); frm += 2; LE_WRITE_4(frm, ic->ic_txbfcaps); frm += 4; *frm++ = ic->ic_aselcaps; return frm; } uint8_t * ieee80211_add_vhtcaps(uint8_t *frm, struct ieee80211com *ic) { *frm++ = IEEE80211_ELEMID_VHT_CAP; *frm++ = sizeof(struct ieee80211_ie_vhtcap) - 2; /* 32-bit VHT capability */ LE_WRITE_4(frm, ic->ic_vhtcaps); frm += 4; /* suppmcs */ LE_WRITE_2(frm, ic->ic_vht_rx_mcs_map); frm += 2; LE_WRITE_2(frm, ic->ic_vht_rx_highest); frm += 2; LE_WRITE_2(frm, ic->ic_vht_tx_mcs_map); frm += 2; LE_WRITE_2(frm, ic->ic_vht_tx_highest); frm += 2; return frm; } uint8_t * ieee80211_add_hecaps(uint8_t *frm, struct ieee80211com *ic) { uint8_t nss_size, ie_len; uint8_t *orig_pos = frm; nss_size = ieee80211_he_mcs_nss_size(&ic->ic_he_cap_elem); ie_len = 2 + 1 + sizeof(ic->ic_he_cap_elem) + nss_size + ieee80211_he_ppe_size(ic->ic_ppe_thres[0], ic->ic_he_cap_elem.phy_cap_info); *frm++ = IEEE80211_ELEMID_EXTENSION; frm++; /* We'll set the size later below */ *frm++ = IEEE80211_ELEMID_EXT_HE_CAPABILITY; /* Fixed data */ memcpy(frm, &ic->ic_he_cap_elem, sizeof(ic->ic_he_cap_elem)); frm += sizeof(ic->ic_he_cap_elem); memcpy(frm, &ic->ic_he_mcs_nss_supp, nss_size); frm += nss_size; /* Check if PPE Threshold should be present */ if ((ic->ic_he_cap_elem.phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0) return frm; /* * Calculate how many PPET16/PPET8 pairs are to come. Algorithm: * (NSS_M1 + 1) x (num of 1 bits in RU_INDEX_BITMASK) */ nss_size = hweight8(ic->ic_ppe_thres[0] & IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK); nss_size *= (1 + ((ic->ic_ppe_thres[0] & IEEE80211_PPE_THRES_NSS_MASK) >> IEEE80211_PPE_THRES_NSS_POS)); /* * Each pair is 6 bits, and we need to add the 7 "header" bits to the * total size. */ nss_size = (nss_size * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7; nss_size = DIV_ROUND_UP(nss_size, 8); /* Copy PPE Thresholds */ memcpy(frm, &ic->ic_ppe_thres, nss_size); frm += nss_size; orig_pos[1] = (frm - orig_pos) - 2; return frm; } #ifndef IEEE80211_STA_ONLY /* * Add an HT Operation element to a frame (see 7.3.2.58). */ u_int8_t * ieee80211_add_htop(u_int8_t *frm, struct ieee80211com *ic) { *frm++ = IEEE80211_ELEMID_HTOP; *frm++ = 22; *frm++ = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); *frm++ = ic->ic_bss->ni_htop0; LE_WRITE_2(frm, ic->ic_bss->ni_htop1); frm += 2; LE_WRITE_2(frm, ic->ic_bss->ni_htop2); frm += 2; memset(frm, 0, 16); frm += 16; return frm; } #endif /* !IEEE80211_STA_ONLY */ #ifndef IEEE80211_STA_ONLY /* * Add a Timeout Interval element to a frame (see 7.3.2.49). */ u_int8_t * ieee80211_add_tie(u_int8_t *frm, u_int8_t type, u_int32_t value) { *frm++ = IEEE80211_ELEMID_TIE; *frm++ = 5; /* length */ *frm++ = type; /* Timeout Interval type */ LE_WRITE_4(frm, value); return frm + 4; } #endif mbuf_t ieee80211_getmgmt(int flags, int type, u_int pktlen) { mbuf_t m; /* reserve space for 802.11 header */ pktlen += sizeof(struct ieee80211_frame); if (pktlen > MCLBYTES) panic("management frame too large: %u", pktlen); mbuf_gethdr(flags, type, &m); if (m == NULL) return NULL; if (pktlen > mbuf_get_mhlen()) { mbuf_mclget(flags, type, &m); if (!(mbuf_flags(m) & MBUF_EXT)) return mbuf_free(m); } mbuf_setdata(m, (u_int8_t*) mbuf_data(m) + sizeof(struct ieee80211_frame), mbuf_len(m) - sizeof(struct ieee80211_frame)); return m; } /*- * Probe request frame format: * [tlv] SSID * [tlv] Supported rates * [tlv] Extended Supported Rates (802.11g) * [tlv] HT Capabilities (802.11n) */ mbuf_t ieee80211_get_probe_req(struct ieee80211com *ic, struct ieee80211_node *ni) { const struct ieee80211_rateset *rs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; mbuf_t m; u_int8_t *frm; m = ieee80211_getmgmt(MBUF_DONTWAIT, MT_DATA, 2 + ic->ic_des_esslen + 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) + ((rs->rs_nrates > IEEE80211_RATE_SIZE) ? 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) + ((ic->ic_flags & IEEE80211_F_HTON) ? sizeof(struct ieee80211_ie_htcap) + sizeof(struct ieee80211_wme_info) : 0) + ((ic->ic_flags & IEEE80211_F_VHTON) ? sizeof(struct ieee80211_ie_vhtcap) : 0)); if (m == NULL) return NULL; frm = mtod(m, u_int8_t *); frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen); frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); if (ic->ic_flags & IEEE80211_F_HTON) { frm = ieee80211_add_htcaps(frm, ic); frm = ieee80211_add_wme_info(frm, ic); } if (ic->ic_flags & IEEE80211_F_VHTON) frm = ieee80211_add_vhtcaps(frm, ic); size_t l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); return m; } #ifndef IEEE80211_STA_ONLY /*- * Probe response frame format: * [8] Timestamp * [2] Beacon interval * [2] Capability * [tlv] Service Set Identifier (SSID) * [tlv] Supported rates * [tlv] DS Parameter Set (802.11g) * [tlv] ERP Information (802.11g) * [tlv] Extended Supported Rates (802.11g) * [tlv] RSN (802.11i) * [tlv] EDCA Parameter Set (802.11e) * [tlv] HT Capabilities (802.11n) * [tlv] HT Operation (802.11n) */ mbuf_t ieee80211_get_probe_resp(struct ieee80211com *ic, struct ieee80211_node *ni) { const struct ieee80211_rateset *rs = &ic->ic_bss->ni_rates; mbuf_t m; u_int8_t *frm; m = ieee80211_getmgmt(MBUF_DONTWAIT, MT_DATA, 8 + 2 + 2 + 2 + ni->ni_esslen + 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) + 2 + 1 + ((ic->ic_opmode == IEEE80211_M_IBSS) ? 2 + 2 : 0) + ((ic->ic_curmode == IEEE80211_MODE_11G) ? 2 + 1 : 0) + ((rs->rs_nrates > IEEE80211_RATE_SIZE) ? 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) + (((ic->ic_flags & IEEE80211_F_RSNON) && (ic->ic_bss->ni_rsnprotos & IEEE80211_PROTO_RSN)) ? 2 + IEEE80211_RSNIE_MAXLEN : 0) + ((ic->ic_flags & IEEE80211_F_QOS) ? 2 + 18 : 0) + (((ic->ic_flags & IEEE80211_F_RSNON) && (ic->ic_bss->ni_rsnprotos & IEEE80211_PROTO_WPA)) ? 2 + IEEE80211_WPAIE_MAXLEN : 0) + ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 24 + 26 : 0)); if (m == NULL) return NULL; frm = mtod(m, u_int8_t *); memset(frm, 0, 8); frm += 8; /* timestamp is set by hardware */ LE_WRITE_2(frm, ic->ic_bss->ni_intval); frm += 2; frm = ieee80211_add_capinfo(frm, ic, ni); frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen); frm = ieee80211_add_rates(frm, rs); frm = ieee80211_add_ds_params(frm, ic, ni); if (ic->ic_opmode == IEEE80211_M_IBSS) frm = ieee80211_add_ibss_params(frm, ni); if (ic->ic_curmode == IEEE80211_MODE_11G) frm = ieee80211_add_erp(frm, ic); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); if ((ic->ic_flags & IEEE80211_F_RSNON) && (ic->ic_bss->ni_rsnprotos & IEEE80211_PROTO_RSN)) frm = ieee80211_add_rsn(frm, ic, ic->ic_bss); if (ic->ic_flags & IEEE80211_F_QOS) frm = ieee80211_add_edca_params(frm, ic); if ((ic->ic_flags & IEEE80211_F_RSNON) && (ic->ic_bss->ni_rsnprotos & IEEE80211_PROTO_WPA)) frm = ieee80211_add_wpa(frm, ic, ic->ic_bss); if (ic->ic_flags & IEEE80211_F_HTON) { frm = ieee80211_add_htcaps(frm, ic); frm = ieee80211_add_htop(frm, ic); frm = ieee80211_add_wme_param(frm, ic); } size_t l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); return m; } #endif /* IEEE80211_STA_ONLY */ /*- * Authentication frame format: * [2] Authentication algorithm number * [2] Authentication transaction sequence number * [2] Status code */ mbuf_t ieee80211_get_auth(struct ieee80211com *ic, struct ieee80211_node *ni, u_int16_t status, u_int16_t seq) { mbuf_t m; u_int8_t *frm; mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &m); if (m == NULL) return NULL; mbuf_align_32(m, 2 * 3); mbuf_pkthdr_setlen(m, 2 * 3); mbuf_setlen(m, 2 * 3); frm = mtod(m, u_int8_t *); LE_WRITE_2(frm, IEEE80211_AUTH_ALG_OPEN); frm += 2; LE_WRITE_2(frm, seq); frm += 2; LE_WRITE_2(frm, status); return m; } /*- * Deauthentication frame format: * [2] Reason code */ mbuf_t ieee80211_get_deauth(struct ieee80211com *ic, struct ieee80211_node *ni, u_int16_t reason) { mbuf_t m; mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &m); if (m == NULL) return NULL; mbuf_align_32(m, 2); mbuf_pkthdr_setlen(m, 2); mbuf_setlen(m, 2); *mtod(m, u_int16_t *) = htole16(reason); return m; } /*- * (Re)Association request frame format: * [2] Capability information * [2] Listen interval * [6*] Current AP address (Reassociation only) * [tlv] SSID * [tlv] Supported rates * [tlv] Extended Supported Rates (802.11g) * [tlv] RSN (802.11i) * [tlv] QoS Capability (802.11e) * [tlv] HT Capabilities (802.11n) */ mbuf_t ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni, int type) { const struct ieee80211_rateset *rs = &ni->ni_rates; mbuf_t m; u_int8_t *frm; u_int16_t capinfo; m = ieee80211_getmgmt(MBUF_DONTWAIT, MT_DATA, 2 + 2 + ((type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) ? IEEE80211_ADDR_LEN : 0) + 2 + ni->ni_esslen + 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) + ((rs->rs_nrates > IEEE80211_RATE_SIZE) ? 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) + (((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)) ? 2 + IEEE80211_RSNIE_MAXLEN : 0) + ((ni->ni_flags & IEEE80211_NODE_QOS) ? 2 + 1 : 0) + (((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)) ? 2 + IEEE80211_WPAIE_MAXLEN : 0) + ((ic->ic_flags & IEEE80211_F_HTON) ? sizeof(struct ieee80211_ie_htcap) + sizeof(struct ieee80211_wme_info) : 0) + ((ic->ic_flags & IEEE80211_F_VHTON) ? sizeof(struct ieee80211_ie_vhtcap) + 2 : 0) + ((ic->ic_flags & IEEE80211_F_HEON) ? (sizeof(struct ieee80211_he_cap_elem) + 2 + 1 + sizeof(struct ieee80211_he_mcs_nss_supp) + IEEE80211_HE_PPE_THRES_MAX_LEN) : 0)); if (m == NULL) return NULL; frm = mtod(m, u_int8_t *); capinfo = IEEE80211_CAPINFO_ESS; if (ic->ic_flags & IEEE80211_F_WEPON) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_caps & IEEE80211_C_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; LE_WRITE_2(frm, capinfo); frm += 2; LE_WRITE_2(frm, ic->ic_lintval); frm += 2; if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid); frm += IEEE80211_ADDR_LEN; } frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); if ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)) { #ifdef USE_APPLE_SUPPLICANT if (ic->ic_rsn_ie_override[1] > 0) { memcpy(frm, ic->ic_rsn_ie_override, 2 + ic->ic_rsn_ie_override[1]); frm += 2 + ic->ic_rsn_ie_override[1]; } else #endif frm = ieee80211_add_rsn(frm, ic, ni); } if (ni->ni_flags & IEEE80211_NODE_QOS) frm = ieee80211_add_qos_capability(frm, ic); if ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)) { #ifdef USE_APPLE_SUPPLICANT if (ic->ic_rsn_ie_override[1] > 0) { memcpy(frm, ic->ic_rsn_ie_override, 2 + ic->ic_rsn_ie_override[1]); frm += 2 + ic->ic_rsn_ie_override[1]; } else #endif frm = ieee80211_add_wpa(frm, ic, ni); } if (ic->ic_flags & IEEE80211_F_HTON) { frm = ieee80211_add_htcaps(frm, ic); frm = ieee80211_add_wme_info(frm, ic); } if (ic->ic_flags & IEEE80211_F_VHTON) frm = ieee80211_add_vhtcaps(frm, ic); if (ic->ic_flags & IEEE80211_F_HEON) frm = ieee80211_add_hecaps(frm, ic); size_t l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); return m; } #ifndef IEEE80211_STA_ONLY /*- * (Re)Association response frame format: * [2] Capability information * [2] Status code * [2] Association ID (AID) * [tlv] Supported rates * [tlv] Extended Supported Rates (802.11g) * [tlv] EDCA Parameter Set (802.11e) * [tlv] Timeout Interval (802.11w) * [tlv] HT Capabilities (802.11n) * [tlv] HT Operation (802.11n) */ mbuf_t ieee80211_get_assoc_resp(struct ieee80211com *ic, struct ieee80211_node *ni, u_int16_t status) { const struct ieee80211_rateset *rs = &ni->ni_rates; mbuf_t m; u_int8_t *frm; m = ieee80211_getmgmt(MBUF_DONTWAIT, MT_DATA, 2 + 2 + 2 + 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) + ((rs->rs_nrates > IEEE80211_RATE_SIZE) ? 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) + ((ni->ni_flags & IEEE80211_NODE_QOS) ? 2 + 18 : 0) + ((status == IEEE80211_STATUS_TRY_AGAIN_LATER) ? 2 + 7 : 0) + ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 24 + 26 : 0)); if (m == NULL) return NULL; frm = mtod(m, u_int8_t *); frm = ieee80211_add_capinfo(frm, ic, ni); LE_WRITE_2(frm, status); frm += 2; if (status == IEEE80211_STATUS_SUCCESS) LE_WRITE_2(frm, ni->ni_associd); else LE_WRITE_2(frm, 0); frm += 2; frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); if (ni->ni_flags & IEEE80211_NODE_QOS) frm = ieee80211_add_edca_params(frm, ic); if ((ni->ni_flags & IEEE80211_NODE_MFP) && status == IEEE80211_STATUS_TRY_AGAIN_LATER) { /* Association Comeback Time */ frm = ieee80211_add_tie(frm, 3, 1000 /* XXX */); } if (ic->ic_flags & IEEE80211_F_HTON) { frm = ieee80211_add_htcaps(frm, ic); frm = ieee80211_add_htop(frm, ic); frm = ieee80211_add_wme_param(frm, ic); } size_t l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); return m; } #endif /* IEEE80211_STA_ONLY */ /*- * Disassociation frame format: * [2] Reason code */ mbuf_t ieee80211_get_disassoc(struct ieee80211com *ic, struct ieee80211_node *ni, u_int16_t reason) { mbuf_t m; mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &m); if (m == NULL) return NULL; mbuf_align_32(m, 2); mbuf_pkthdr_setlen(m, 2); mbuf_setlen(m, 2); *mtod(m, u_int16_t *) = htole16(reason); return m; } /*- * ADDBA Request frame format: * [1] Category * [1] Action * [1] Dialog Token * [2] Block Ack Parameter Set * [2] Block Ack Timeout Value * [2] Block Ack Starting Sequence Control */ mbuf_t ieee80211_get_addba_req(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t tid) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; mbuf_t m; u_int8_t *frm; m = ieee80211_getmgmt(MBUF_DONTWAIT, MT_DATA, 9); if (m == NULL) return m; frm = mtod(m, u_int8_t *); *frm++ = IEEE80211_CATEG_BA; *frm++ = IEEE80211_ACTION_ADDBA_REQ; *frm++ = ba->ba_token; LE_WRITE_2(frm, ba->ba_params); frm += 2; LE_WRITE_2(frm, ba->ba_timeout_val / IEEE80211_DUR_TU); frm += 2; LE_WRITE_2(frm, ba->ba_winstart << IEEE80211_SEQ_SEQ_SHIFT); frm += 2; size_t l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); return m; } /* Move Tx BA window forward to the specified SSN. */ void ieee80211_output_ba_move_window(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid, uint16_t ssn) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; uint16_t s = ba->ba_winstart; while (SEQ_LT(s, ssn) && ba->ba_bitmap) { s = (s + 1) % 0xfff; ba->ba_bitmap >>= 1; } ba->ba_winstart = (ssn & 0xfff); ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; } /* * Move Tx BA window forward up to the first hole in the bitmap * or up to the specified SSN, whichever comes first. * After calling this function, frames before the start of the * potentially changed BA window should be discarded. */ void ieee80211_output_ba_move_window_to_first_unacked(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid, uint16_t ssn) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; uint16_t s = ba->ba_winstart; uint64_t bitmap = ba->ba_bitmap; int can_move_window = 0; while (bitmap && SEQ_LT(s, ssn)) { if ((bitmap & 1) == 0) break; s = (s + 1) % 0xfff; bitmap >>= 1; can_move_window = 1; } if (can_move_window) ieee80211_output_ba_move_window(ic, ni, tid, s); } /* Record an ACK for a frame with a given SSN within the Tx BA window. */ void ieee80211_output_ba_record_ack(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid, uint16_t ssn) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; int i = 0; uint16_t s = ba->ba_winstart; _KASSERT(!SEQ_LT(ssn, ba->ba_winstart)); _KASSERT(!SEQ_LT(ba->ba_winend, ssn)); while (SEQ_LT(s, ssn)) { s = (s + 1) % 0xfff; i++; } if (i < ba->ba_winsize) ba->ba_bitmap |= (1 << i); } /*- * ADDBA Response frame format: * [1] Category * [1] Action * [1] Dialog Token * [2] Status Code * [2] Block Ack Parameter Set * [2] Block Ack Timeout Value */ mbuf_t ieee80211_get_addba_resp(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t tid, u_int8_t token, u_int16_t status) { struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; mbuf_t m; u_int8_t *frm; u_int16_t params; m = ieee80211_getmgmt(MBUF_DONTWAIT, MT_DATA, 9); if (m == NULL) return m; frm = mtod(m, u_int8_t *); *frm++ = IEEE80211_CATEG_BA; *frm++ = IEEE80211_ACTION_ADDBA_RESP; *frm++ = token; LE_WRITE_2(frm, status); frm += 2; if (status == 0) params = ba->ba_params; else params = tid << IEEE80211_ADDBA_TID_SHIFT; LE_WRITE_2(frm, params); frm += 2; if (status == 0) LE_WRITE_2(frm, ba->ba_timeout_val / IEEE80211_DUR_TU); else LE_WRITE_2(frm, 0); frm += 2; size_t l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); return m; } /*- * DELBA frame format: * [1] Category * [1] Action * [2] DELBA Parameter Set * [2] Reason Code */ mbuf_t ieee80211_get_delba(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t tid, u_int8_t dir, u_int16_t reason) { mbuf_t m; u_int8_t *frm; u_int16_t params; m = ieee80211_getmgmt(MBUF_DONTWAIT, MT_DATA, 6); if (m == NULL) return m; frm = mtod(m, u_int8_t *); *frm++ = IEEE80211_CATEG_BA; *frm++ = IEEE80211_ACTION_DELBA; params = tid << 12; if (dir) params |= IEEE80211_DELBA_INITIATOR; LE_WRITE_2(frm, params); frm += 2; LE_WRITE_2(frm, reason); frm += 2; size_t l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); return m; } /*- * SA Query Request/Reponse frame format: * [1] Category * [1] Action * [16] Transaction Identifier */ mbuf_t ieee80211_get_sa_query(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t action) { mbuf_t m; u_int8_t *frm; m = ieee80211_getmgmt(MBUF_DONTWAIT, MT_DATA, 4); if (m == NULL) return NULL; frm = mtod(m, u_int8_t *); *frm++ = IEEE80211_CATEG_SA_QUERY; *frm++ = action; /* ACTION_SA_QUERY_REQ/RESP */ LE_WRITE_2(frm, ni->ni_sa_query_trid); frm += 2; size_t l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); return m; } mbuf_t ieee80211_get_action(struct ieee80211com *ic, struct ieee80211_node *ni, u_int8_t categ, u_int8_t action, int arg) { mbuf_t m = NULL; switch (categ) { case IEEE80211_CATEG_BA: switch (action) { case IEEE80211_ACTION_ADDBA_REQ: m = ieee80211_get_addba_req(ic, ni, arg & 0xffff); break; case IEEE80211_ACTION_ADDBA_RESP: m = ieee80211_get_addba_resp(ic, ni, arg & 0xff, arg >> 8, arg >> 16); break; case IEEE80211_ACTION_DELBA: m = ieee80211_get_delba(ic, ni, arg & 0xff, arg >> 8, arg >> 16); break; } break; case IEEE80211_CATEG_SA_QUERY: switch (action) { #ifndef IEEE80211_STA_ONLY case IEEE80211_ACTION_SA_QUERY_REQ: #endif case IEEE80211_ACTION_SA_QUERY_RESP: m = ieee80211_get_sa_query(ic, ni, action); break; } break; } return m; } /* * Send a management frame. The node is for the destination (or ic_bss * when in station mode). Nodes other than ic_bss have their reference * count bumped to reflect our use for an indeterminant time. */ int ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, int type, int arg1, int arg2) { #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0) struct _ifnet *ifp = &ic->ic_if; mbuf_t m; int ret, timer; if (ni == NULL) panic("null node"); /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ ieee80211_ref_node(ni); timer = 0; switch (type) { case IEEE80211_FC0_SUBTYPE_PROBE_REQ: if ((m = ieee80211_get_probe_req(ic, ni)) == NULL) senderr(ENOMEM, is_tx_nombuf); timer = IEEE80211_TRANS_WAIT; break; #ifndef IEEE80211_STA_ONLY case IEEE80211_FC0_SUBTYPE_PROBE_RESP: if ((m = ieee80211_get_probe_resp(ic, ni)) == NULL) senderr(ENOMEM, is_tx_nombuf); break; #endif case IEEE80211_FC0_SUBTYPE_AUTH: m = ieee80211_get_auth(ic, ni, arg1 >> 16, arg1 & 0xffff); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); if (ic->ic_opmode == IEEE80211_M_STA) timer = IEEE80211_TRANS_WAIT; break; case IEEE80211_FC0_SUBTYPE_DEAUTH: if ((m = ieee80211_get_deauth(ic, ni, arg1)) == NULL) senderr(ENOMEM, is_tx_nombuf); #ifndef IEEE80211_STA_ONLY if ((ifp->if_flags & IFF_DEBUG) && (ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_IBSS)) XYLog("%s: station %s deauthenticate (reason %d)\n", ifp->if_xname, ether_sprintf(ni->ni_macaddr), arg1); #endif break; case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: if ((m = ieee80211_get_assoc_req(ic, ni, type)) == NULL) senderr(ENOMEM, is_tx_nombuf); timer = IEEE80211_TRANS_WAIT; break; #ifndef IEEE80211_STA_ONLY case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: if ((m = ieee80211_get_assoc_resp(ic, ni, arg1)) == NULL) senderr(ENOMEM, is_tx_nombuf); break; #endif case IEEE80211_FC0_SUBTYPE_DISASSOC: if ((m = ieee80211_get_disassoc(ic, ni, arg1)) == NULL) senderr(ENOMEM, is_tx_nombuf); #ifndef IEEE80211_STA_ONLY if ((ifp->if_flags & IFF_DEBUG) && (ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_IBSS)) XYLog("%s: station %s disassociate (reason %d)\n", ifp->if_xname, ether_sprintf(ni->ni_macaddr), arg1); #endif break; case IEEE80211_FC0_SUBTYPE_ACTION: m = ieee80211_get_action(ic, ni, arg1 >> 16, arg1 & 0xffff, arg2); if (m == NULL) senderr(ENOMEM, is_tx_nombuf); break; default: DPRINTF(("invalid mgmt frame type %u\n", type)); senderr(EINVAL, is_tx_unknownmgt); /* NOTREACHED */ } ret = ieee80211_mgmt_output(ifp, ni, m, type); if (ret == 0) { if (timer) ic->ic_mgt_timer = timer; } else { bad: ieee80211_release_node(ic, ni); } return ret; #undef senderr } /* * Build a RTS (Request To Send) control frame (see 7.2.1.1). */ mbuf_t ieee80211_get_rts(struct ieee80211com *ic, const struct ieee80211_frame *wh, u_int16_t dur) { struct ieee80211_frame_rts *rts; mbuf_t m; mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &m); if (m == NULL) return NULL; size_t l = sizeof(struct ieee80211_frame_rts); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); rts = mtod(m, struct ieee80211_frame_rts *); rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)rts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(rts->i_ra, wh->i_addr1); IEEE80211_ADDR_COPY(rts->i_ta, wh->i_addr2); return m; } /* * Build a CTS-to-self (Clear To Send) control frame (see 7.2.1.2). */ mbuf_t ieee80211_get_cts_to_self(struct ieee80211com *ic, u_int16_t dur) { struct ieee80211_frame_cts *cts; mbuf_t m; mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &m); if (m == NULL) return NULL; size_t l = sizeof(struct ieee80211_frame_cts); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); cts = mtod(m, struct ieee80211_frame_cts *); cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)cts->i_dur = htole16(dur); IEEE80211_ADDR_COPY(cts->i_ra, ic->ic_myaddr); return m; } /* * Build a compressed Block Ack Request control frame. */ mbuf_t ieee80211_get_compressed_bar(struct ieee80211com *ic, struct ieee80211_node *ni, int tid, uint16_t ssn) { struct ieee80211_frame_min *wh; uint8_t *frm; uint16_t ctl; mbuf_t m; mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &m); if (m == NULL) return NULL; size_t l = sizeof(struct ieee80211_frame_min) + sizeof(ctl) + sizeof(ssn); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); wh = mtod(m, struct ieee80211_frame_min *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)wh->i_dur = 0; IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); frm = (uint8_t *)&wh[1]; ctl = IEEE80211_BA_COMPRESSED | (tid << IEEE80211_BA_TID_INFO_SHIFT); LE_WRITE_2(frm, ctl); frm += 2; LE_WRITE_2(frm, ssn << IEEE80211_SEQ_SEQ_SHIFT); frm += 2; l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); mbuf_pkthdr_setrcvif(m, (ifnet_t)ni); // m->m_pkthdr.ph_cookie = ni; return m; } #ifndef IEEE80211_STA_ONLY /*- * Beacon frame format: * [8] Timestamp * [2] Beacon interval * [2] Capability * [tlv] Service Set Identifier (SSID) * [tlv] Supported rates * [tlv] DS Parameter Set (802.11g) * [tlv] IBSS Parameter Set * [tlv] Traffic Indication Map (TIM) * [tlv] ERP Information (802.11g) * [tlv] Extended Supported Rates (802.11g) * [tlv] RSN (802.11i) * [tlv] EDCA Parameter Set (802.11e) * [tlv] HT Capabilities (802.11n) * [tlv] HT Operation (802.11n) */ mbuf_t ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni) { const struct ieee80211_rateset *rs = &ni->ni_rates; struct ieee80211_frame *wh; mbuf_t m; u_int8_t *frm; m = ieee80211_getmgmt(MBUF_DONTWAIT, MT_DATA, 8 + 2 + 2 + 2 + ((ic->ic_userflags & IEEE80211_F_HIDENWID) ? 0 : ni->ni_esslen) + 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) + 2 + 1 + 2 + ((ic->ic_opmode == IEEE80211_M_IBSS) ? 2 : 254) + ((ic->ic_curmode == IEEE80211_MODE_11G) ? 2 + 1 : 0) + ((rs->rs_nrates > IEEE80211_RATE_SIZE) ? 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) + (((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)) ? 2 + IEEE80211_RSNIE_MAXLEN : 0) + ((ic->ic_flags & IEEE80211_F_QOS) ? 2 + 18 : 0) + (((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)) ? 2 + IEEE80211_WPAIE_MAXLEN : 0) + ((ic->ic_flags & IEEE80211_F_HTON) ? 28 + 24 + 26 : 0)); if (m == NULL) return NULL; mbuf_prepend(&m, sizeof(struct ieee80211_frame), MBUF_DONTWAIT); if (m == NULL) return NULL; wh = mtod(m, struct ieee80211_frame *); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_BEACON; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; *(u_int16_t *)wh->i_dur = 0; IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); *(u_int16_t *)wh->i_seq = 0; frm = (u_int8_t *)&wh[1]; memset(frm, 0, 8); frm += 8; /* timestamp is set by hardware */ LE_WRITE_2(frm, ni->ni_intval); frm += 2; frm = ieee80211_add_capinfo(frm, ic, ni); if (ic->ic_userflags & IEEE80211_F_HIDENWID) frm = ieee80211_add_ssid(frm, NULL, 0); else frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); frm = ieee80211_add_rates(frm, rs); frm = ieee80211_add_ds_params(frm, ic, ni); if (ic->ic_opmode == IEEE80211_M_IBSS) frm = ieee80211_add_ibss_params(frm, ni); else frm = ieee80211_add_tim(frm, ic); if (ic->ic_curmode == IEEE80211_MODE_11G) frm = ieee80211_add_erp(frm, ic); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); if ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)) frm = ieee80211_add_rsn(frm, ic, ni); if (ic->ic_flags & IEEE80211_F_QOS) frm = ieee80211_add_edca_params(frm, ic); if ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnprotos & IEEE80211_PROTO_WPA)) frm = ieee80211_add_wpa(frm, ic, ni); if (ic->ic_flags & IEEE80211_F_HTON) { frm = ieee80211_add_htcaps(frm, ic); frm = ieee80211_add_htop(frm, ic); frm = ieee80211_add_wme_param(frm, ic); } size_t l = frm - mtod(m, u_int8_t *); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); mbuf_pkthdr_setrcvif(m, (ifnet_t)ni); // m->m_pkthdr.ph_cookie = ni; return m; } /* * Check if an outgoing MSDU or management frame should be buffered into * the AP for power management. Return 1 if the frame was buffered into * the AP, or 0 if the frame shall be transmitted immediately. */ int ieee80211_pwrsave(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { const struct ieee80211_frame *wh; int pssta = 0; _KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP); if (!(ic->ic_caps & IEEE80211_C_APPMGT)) return 0; wh = mtod(m, struct ieee80211_frame *); if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { /* * Buffer group addressed MSDUs with the Order bit clear * if any associated STAs are in PS mode. */ ieee80211_iterate_nodes(ic, ieee80211_count_pssta, &pssta); if ((wh->i_fc[1] & IEEE80211_FC1_ORDER) || pssta == 0) return 0; ic->ic_tim_mcast_pending = 1; } else { /* * Buffer MSDUs, A-MSDUs or management frames destined for * PS STAs. */ if (ni->ni_pwrsave == IEEE80211_PS_AWAKE || (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) return 0; if (mq_empty(&ni->ni_savedq)) (*ic->ic_set_tim)(ic, ni->ni_associd, 1); } /* NB: ni == ic->ic_bss for broadcast/multicast */ /* * Similar to ieee80211_mgmt_output, store the node in a * special pkthdr field. */ mbuf_pkthdr_setrcvif(m, (ifnet_t)ni); // m->m_pkthdr.ph_cookie = ni; mq_enqueue(&ni->ni_savedq, m); return 1; } #endif /* IEEE80211_STA_ONLY */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_pae_input.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. */ /* $OpenBSD: ieee80211_pae_input.c,v 1.33 2019/09/02 12:54:21 stsp Exp $ */ /*- * Copyright (c) 2007,2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the 4-Way Handshake and Group Key Handshake protocols * (both Supplicant and Authenticator Key Receive state machines) defined in * IEEE Std 802.11-2007 section 8.5. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void ieee80211_recv_4way_msg1(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_4way_msg2(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *, const u_int8_t *); #endif int ieee80211_must_update_group_key(struct ieee80211_key *, const uint8_t *, int); void ieee80211_recv_4way_msg3(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_4way_msg4(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); void ieee80211_recv_4way_msg2or4(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #endif void ieee80211_recv_rsn_group_msg1(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); void ieee80211_recv_wpa_group_msg1(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_recv_group_msg2(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); void ieee80211_recv_eapol_key_req(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #endif /* * Process an incoming EAPOL frame. Notice that we are only interested in * EAPOL-Key frames with an IEEE 802.11 or WPA descriptor type. */ void ieee80211_eapol_key_input(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); struct _ifnet *ifp = &ic->ic_if; struct ether_header *eh; struct ieee80211_eapol_key *key; u_int16_t info, desc; int totlen, bodylen, paylen; ifp->if_ibytes += mbuf_pkthdr_len(m); eh = mtod(m, struct ether_header *); if (IEEE80211_IS_MULTICAST(eh->ether_dhost)) { ifp->if_imcasts++; goto done; } mbuf_adj(m, sizeof(*eh)); if (mbuf_pkthdr_len(m) < sizeof(*key)) goto done; if (mbuf_len(m) < sizeof(*key) && (mbuf_pullup(&m, sizeof(*key)))) { ic->ic_stats.is_rx_nombuf++; goto done; } key = mtod(m, struct ieee80211_eapol_key *); if (key->type != EAPOL_KEY) goto done; ic->ic_stats.is_rx_eapol_key++; if ((ni->ni_rsnprotos == IEEE80211_PROTO_RSN && key->desc != EAPOL_KEY_DESC_IEEE80211) || (ni->ni_rsnprotos == IEEE80211_PROTO_WPA && key->desc != EAPOL_KEY_DESC_WPA)) goto done; /* check packet body length */ bodylen = BE_READ_2(key->len); totlen = 4 + bodylen; if (mbuf_pkthdr_len(m) < totlen || totlen > MCLBYTES) goto done; /* check key data length */ paylen = BE_READ_2(key->paylen); if (paylen > totlen - sizeof(*key)) goto done; info = BE_READ_2(key->info); /* discard EAPOL-Key frames with an unknown descriptor version */ desc = info & EAPOL_KEY_VERSION_MASK; if (desc < EAPOL_KEY_DESC_V1 || desc > EAPOL_KEY_DESC_V3) goto done; if (ieee80211_is_sha256_akm((enum ieee80211_akm)ni->ni_rsnakms)) { if (desc != EAPOL_KEY_DESC_V3) goto done; } else if (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP || ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP) { if (desc != EAPOL_KEY_DESC_V2) goto done; } /* make sure the key data field is contiguous */ if (mbuf_len(m) < totlen && mbuf_pullup(&m, totlen)) { ic->ic_stats.is_rx_nombuf++; goto done; } key = mtod(m, struct ieee80211_eapol_key *); /* determine message type (see 8.5.3.7) */ if (info & EAPOL_KEY_REQUEST) { #ifndef IEEE80211_STA_ONLY /* EAPOL-Key Request frame */ ieee80211_recv_eapol_key_req(ic, key, ni); #endif } else if (info & EAPOL_KEY_PAIRWISE) { /* 4-Way Handshake */ if (info & EAPOL_KEY_KEYMIC) { if (info & EAPOL_KEY_KEYACK) ieee80211_recv_4way_msg3(ic, key, ni); #ifndef IEEE80211_STA_ONLY else ieee80211_recv_4way_msg2or4(ic, key, ni); #endif } else if (info & EAPOL_KEY_KEYACK) ieee80211_recv_4way_msg1(ic, key, ni); } else { /* Group Key Handshake */ if (!(info & EAPOL_KEY_KEYMIC)) goto done; if (info & EAPOL_KEY_KEYACK) { if (key->desc == EAPOL_KEY_DESC_WPA) ieee80211_recv_wpa_group_msg1(ic, key, ni); else ieee80211_recv_rsn_group_msg1(ic, key, ni); } #ifndef IEEE80211_STA_ONLY else ieee80211_recv_group_msg2(ic, key, ni); #endif } done: mbuf_freem(m); } /* * Process Message 1 of the 4-Way Handshake (sent by Authenticator). */ void ieee80211_recv_4way_msg1(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); struct ieee80211_ptk tptk; struct ieee80211_pmk *pmk; const u_int8_t *frm, *efrm; const u_int8_t *pmkid; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_STA && ic->ic_opmode != IEEE80211_M_IBSS) return; #endif /* * Message 1 is always expected while RSN is active since some * APs will rekey the PTK by sending Msg1/4 after some time. */ if (ni->ni_rsn_supp_state == RSNA_SUPP_INITIALIZE) { DPRINTF(("unexpected in state: %d\n", ni->ni_rsn_supp_state)); return; } /* enforce monotonicity of key request replay counter */ if (ni->ni_replaycnt_ok && BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* parse key data field (may contain an encapsulated PMKID) */ frm = (const u_int8_t *)&key[1]; efrm = frm + BE_READ_2(key->paylen); pmkid = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; switch (frm[0]) { case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) break; if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) { switch (frm[5]) { case IEEE80211_KDE_PMKID: pmkid = frm; break; } } break; } frm += 2 + frm[1]; } /* check that the PMKID KDE is valid (if present) */ if (pmkid != NULL && pmkid[1] != 4 + 16) return; if (ieee80211_is_8021x_akm((enum ieee80211_akm)ni->ni_rsnakms)) { /* retrieve the PMK for this (AP,PMKID) */ pmk = ieee80211_pmksa_find(ic, ni, (pmkid != NULL) ? &pmkid[6] : NULL); if (pmk == NULL) { DPRINTF(("no PMK available for %s\n", ether_sprintf(ni->ni_macaddr))); return; } memcpy(ni->ni_pmk, pmk->pmk_key, IEEE80211_PMK_LEN); } else /* use pre-shared key */ memcpy(ni->ni_pmk, ic->ic_psk, IEEE80211_PMK_LEN); ni->ni_flags |= IEEE80211_NODE_PMK; /* save authenticator's nonce (ANonce) */ memcpy(ni->ni_nonce, key->nonce, EAPOL_KEY_NONCE_LEN); /* generate supplicant's nonce (SNonce) */ arc4random_buf(ic->ic_nonce, EAPOL_KEY_NONCE_LEN); /* TPTK = CalcPTK(PMK, ANonce, SNonce) */ ieee80211_derive_ptk((enum ieee80211_akm)ni->ni_rsnakms, ni->ni_pmk, ni->ni_macaddr, ic->ic_myaddr, ni->ni_nonce, ic->ic_nonce, &tptk); /* We are now expecting a new pairwise key. */ ni->ni_flags |= IEEE80211_NODE_RSN_NEW_PTK; if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 1, 4, "4-way", ether_sprintf(ni->ni_macaddr)); /* send message 2 to authenticator using TPTK */ (void)ieee80211_send_4way_msg2(ic, ni, key->replaycnt, &tptk); } #ifndef IEEE80211_STA_ONLY /* * Process Message 2 of the 4-Way Handshake (sent by Supplicant). */ void ieee80211_recv_4way_msg2(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni, const u_int8_t *rsnie) { XYLog("%s\n", __FUNCTION__); struct ieee80211_ptk tptk; if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_IBSS) return; /* discard if we're not expecting this message */ if (ni->ni_rsn_state != RSNA_PTKSTART && ni->ni_rsn_state != RSNA_PTKCALCNEGOTIATING) { DPRINTF(("unexpected in state: %d\n", ni->ni_rsn_state)); return; } ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING; /* NB: replay counter has already been verified by caller */ /* PTK = CalcPTK(ANonce, SNonce) */ ieee80211_derive_ptk((enum ieee80211_akm)ni->ni_rsnakms, ni->ni_pmk, ic->ic_myaddr, ni->ni_macaddr, ni->ni_nonce, key->nonce, &tptk); /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; /* will timeout.. */ } timeout_del(&ni->ni_eapol_to); ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING_2; ni->ni_rsn_retries = 0; /* install TPTK as PTK now that MIC is verified */ memcpy(&ni->ni_ptk, &tptk, sizeof(tptk)); /* * The RSN IE must match bit-wise with what the STA included in its * (Re)Association Request. */ if (ni->ni_rsnie == NULL || rsnie[1] != ni->ni_rsnie[1] || memcmp(rsnie, ni->ni_rsnie, 2 + rsnie[1]) != 0) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_RSN_DIFFERENT_IE); ieee80211_node_leave(ic, ni); return; } if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 2, 4, "4-way", ether_sprintf(ni->ni_macaddr)); /* send message 3 to supplicant */ (void)ieee80211_send_4way_msg3(ic, ni); } #endif /* IEEE80211_STA_ONLY */ /* * Check if a group key must be updated with a new GTK from an EAPOL frame. * Manipulated group key handshake messages could trick clients into * reinstalling an already used group key and hence lower or reset the * associated replay counter. This check prevents such attacks. */ int ieee80211_must_update_group_key(struct ieee80211_key *k, const uint8_t *gtk, int len) { XYLog("%s\n", __FUNCTION__); return (k->k_cipher == IEEE80211_CIPHER_NONE || k->k_len != len || memcmp(k->k_key, gtk, len) != 0); } /* * Process Message 3 of the 4-Way Handshake (sent by Authenticator). */ void ieee80211_recv_4way_msg3(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); struct ieee80211_ptk tptk; struct ieee80211_key *k; const u_int8_t *frm, *efrm; const u_int8_t *rsnie1, *rsnie2, *gtk, *igtk; u_int16_t info, reason = 0; int keylen, deferlink = 0; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_STA && ic->ic_opmode != IEEE80211_M_IBSS) return; #endif /* discard if we're not expecting this message */ if (ni->ni_rsn_supp_state != RSNA_SUPP_PTKNEGOTIATING && ni->ni_rsn_supp_state != RNSA_SUPP_PTKDONE) { DPRINTF(("unexpected in state: %d\n", ni->ni_rsn_supp_state)); return; } /* enforce monotonicity of key request replay counter */ if (ni->ni_replaycnt_ok && BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* make sure that a PMK has been selected */ if (!(ni->ni_flags & IEEE80211_NODE_PMK)) { DPRINTF(("no PMK found for %s\n", ether_sprintf(ni->ni_macaddr))); return; } /* check that ANonce matches that of Message 1 */ if (memcmp(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN) != 0) { DPRINTF(("ANonce does not match msg 1/4\n")); return; } /* TPTK = CalcPTK(PMK, ANonce, SNonce) */ ieee80211_derive_ptk((enum ieee80211_akm)ni->ni_rsnakms, ni->ni_pmk, ni->ni_macaddr, ic->ic_myaddr, key->nonce, ic->ic_nonce, &tptk); info = BE_READ_2(key->info); /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } /* install TPTK as PTK now that MIC is verified */ memcpy(&ni->ni_ptk, &tptk, sizeof(tptk)); /* if encrypted, decrypt Key Data field using KEK */ if ((info & EAPOL_KEY_ENCRYPTED) && ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) { DPRINTF(("decryption failed\n")); return; } /* parse key data field */ frm = (const u_int8_t *)&key[1]; efrm = frm + BE_READ_2(key->paylen); /* * Some WPA1+WPA2 APs (like hostapd) appear to include both WPA and * RSN IEs in message 3/4. We only take into account the IE of the * version of the protocol we negotiated at association time. */ rsnie1 = rsnie2 = gtk = igtk = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; switch (frm[0]) { case IEEE80211_ELEMID_RSN: if (ni->ni_rsnprotos != IEEE80211_PROTO_RSN) break; if (rsnie1 == NULL) rsnie1 = frm; else if (rsnie2 == NULL) rsnie2 = frm; /* ignore others if more than two RSN IEs */ break; case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) break; if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) { switch (frm[5]) { case IEEE80211_KDE_GTK: gtk = frm; break; case IEEE80211_KDE_IGTK: if (ni->ni_flags & IEEE80211_NODE_MFP) igtk = frm; break; } } else if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) { switch (frm[5]) { case 1: /* WPA */ if (ni->ni_rsnprotos != IEEE80211_PROTO_WPA) break; rsnie1 = frm; break; } } break; } frm += 2 + frm[1]; } /* first WPA/RSN IE is mandatory */ if (rsnie1 == NULL) { DPRINTF(("missing RSN IE\n")); return; } /* key data must be encrypted if GTK is included */ if (gtk != NULL && !(info & EAPOL_KEY_ENCRYPTED)) { DPRINTF(("GTK not encrypted\n")); return; } /* GTK KDE must be included if IGTK KDE is present */ if (igtk != NULL && gtk == NULL) { DPRINTF(("IGTK KDE found but GTK KDE missing\n")); return; } /* check that the Install bit is set if using pairwise keys */ if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP && !(info & EAPOL_KEY_INSTALL)) { DPRINTF(("pairwise cipher but !Install\n")); return; } /* * Check that first WPA/RSN IE is identical to the one received in * the beacon or probe response frame. */ if (ni->ni_rsnie == NULL || rsnie1[1] != ni->ni_rsnie[1] || memcmp(rsnie1, ni->ni_rsnie, 2 + rsnie1[1]) != 0) { reason = IEEE80211_REASON_RSN_DIFFERENT_IE; goto deauth; } /* * If a second RSN information element is present, use its pairwise * cipher suite or deauthenticate. */ if (rsnie2 != NULL) { struct ieee80211_rsnparams rsn; if (ieee80211_parse_rsn(ic, rsnie2, &rsn) == 0) { if (rsn.rsn_akms != ni->ni_rsnakms || rsn.rsn_groupcipher != ni->ni_rsngroupcipher || rsn.rsn_nciphers != 1 || !(rsn.rsn_ciphers & ic->ic_rsnciphers)) { reason = IEEE80211_REASON_BAD_PAIRWISE_CIPHER; goto deauth; } /* use pairwise cipher suite of second RSN IE */ ni->ni_rsnciphers = rsn.rsn_ciphers; ni->ni_rsncipher = (enum ieee80211_cipher)ni->ni_rsnciphers; } } /* update the last seen value of the key replay counter field */ ni->ni_replaycnt = BE_READ_8(key->replaycnt); ni->ni_replaycnt_ok = 1; if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 3, 4, "4-way", ether_sprintf(ni->ni_macaddr)); /* send message 4 to authenticator */ if (ieee80211_send_4way_msg4(ic, ni) != 0) return; /* ..authenticator will retry */ /* * Only install a new pairwise key if we are still expecting a new key, * as indicated by the NODE_RSN_NEW_PTK flag. An adversary could be * sending manipulated retransmissions of message 3 of the 4-way * handshake in an attempt to trick us into reinstalling an already * used pairwise key. If this attack succeeded, the incremental nonce * and replay counter associated with the key would be reset. * Against CCMP, the adversary could abuse this to replay and decrypt * packets. Against TKIP, it would become possible to replay, decrypt, * and forge packets. */ if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP && (ni->ni_flags & IEEE80211_NODE_RSN_NEW_PTK)) { u_int64_t prsc; /* check that key length matches that of pairwise cipher */ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher); if (BE_READ_2(key->keylen) != keylen) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } 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, ni->ni_ptk.tk, k->k_len); /* install the PTK */ switch ((*ic->ic_set_key)(ic, ni, k)) { case 0: break; case EBUSY: deferlink = 1; break; default: reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } 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)); if (gtk != NULL) { u_int8_t kid; /* check that key length matches that of group cipher */ keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher); if (gtk[1] != 6 + keylen) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } /* map GTK to 802.11 key */ kid = gtk[6] & 3; k = &ic->ic_nw_keys[kid]; if (ieee80211_must_update_group_key(k, >k[8], keylen)) { 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; XYLog("%s k_len=%d rsc=%02X %02X %02X %02X %02X %02X\n", __FUNCTION__, keylen , key->rsc[0], key->rsc[1], key->rsc[2], key->rsc[3], key->rsc[4], key->rsc[5]); k->k_rsc[0] = LE_READ_6(key->rsc); k->k_len = keylen; memcpy(k->k_key, >k[8], k->k_len); /* install the GTK */ switch ((*ic->ic_set_key)(ic, ni, k)) { case 0: break; case EBUSY: deferlink = 1; break; default: reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } } } if (igtk != NULL) { /* implies MFP && gtk != NULL */ u_int16_t kid; /* check that the IGTK KDE is valid */ if (igtk[1] != 4 + 24) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } kid = LE_READ_2(&igtk[6]); if (kid != 4 && kid != 5) { DPRINTF(("unsupported IGTK id %u\n", kid)); reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } /* map IGTK to 802.11 key */ k = &ic->ic_nw_keys[kid]; if (ieee80211_must_update_group_key(k, &igtk[14], 16)) { memset(k, 0, sizeof(*k)); k->k_id = kid; /* either 4 or 5 */ k->k_cipher = ni->ni_rsngroupmgmtcipher; k->k_flags = IEEE80211_KEY_IGTK; k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */ k->k_len = 16; memcpy(k->k_key, &igtk[14], k->k_len); /* install the IGTK */ switch ((*ic->ic_set_key)(ic, ni, k)) { case 0: break; case EBUSY: deferlink = 1; break; default: reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } } } if (info & EAPOL_KEY_INSTALL) ni->ni_flags |= IEEE80211_NODE_TXRXPROT; if (info & EAPOL_KEY_SECURE) { ni->ni_flags |= IEEE80211_NODE_TXRXPROT; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) #endif { if (deferlink == 0) { DPRINTF(("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; } } deauth: if (reason != 0) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason); ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); } } #ifndef IEEE80211_STA_ONLY /* * Process Message 4 of the 4-Way Handshake (sent by Supplicant). */ void ieee80211_recv_4way_msg4(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_IBSS) return; /* discard if we're not expecting this message */ if (ni->ni_rsn_state != RSNA_PTKINITNEGOTIATING) { DPRINTF(("unexpected in state: %d\n", ni->ni_rsn_state)); return; } /* NB: replay counter has already been verified by caller */ /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; /* will timeout.. */ } timeout_del(&ni->ni_eapol_to); ni->ni_rsn_state = RSNA_PTKINITDONE; ni->ni_rsn_retries = 0; if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) { struct ieee80211_key *k; /* map PTK to 802.11 key */ k = &ni->ni_pairwise_key; memset(k, 0, sizeof(*k)); k->k_cipher = ni->ni_rsncipher; k->k_len = ieee80211_cipher_keylen(k->k_cipher); memcpy(k->k_key, ni->ni_ptk.tk, k->k_len); /* install the PTK */ switch ((*ic->ic_set_key)(ic, ni, k)) { case 0: case EBUSY: break; default: IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_ASSOC_TOOMANY); ieee80211_node_leave(ic, ni); return; } ni->ni_flags |= IEEE80211_NODE_TXRXPROT; } if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) { DPRINTF(("marking port %s valid\n", ether_sprintf(ni->ni_macaddr))); ni->ni_port_valid = 1; } if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 4, 4, "4-way", ether_sprintf(ni->ni_macaddr)); /* initiate a group key handshake for WPA */ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) (void)ieee80211_send_group_msg1(ic, ni); else ni->ni_rsn_gstate = RSNA_IDLE; } /* * Differentiate Message 2 from Message 4 of the 4-Way Handshake based on * the presence of an RSN or WPA Information Element. */ void ieee80211_recv_4way_msg2or4(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); const u_int8_t *frm, *efrm; const u_int8_t *rsnie; if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* parse key data field (check if an RSN IE is present) */ frm = (const u_int8_t *)&key[1]; efrm = frm + BE_READ_2(key->paylen); rsnie = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; switch (frm[0]) { case IEEE80211_ELEMID_RSN: rsnie = frm; break; case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) break; if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) { switch (frm[5]) { case 1: /* WPA */ rsnie = frm; break; } } } frm += 2 + frm[1]; } if (rsnie != NULL) ieee80211_recv_4way_msg2(ic, key, ni, rsnie); else ieee80211_recv_4way_msg4(ic, key, ni); } #endif /* IEEE80211_STA_ONLY */ /* * Process Message 1 of the RSN Group Key Handshake (sent by Authenticator). */ void ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); struct ieee80211_key *k; const u_int8_t *frm, *efrm; const u_int8_t *gtk, *igtk; u_int16_t info, kid, reason = 0; int keylen; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_STA && ic->ic_opmode != IEEE80211_M_IBSS) return; #endif /* discard if we're not expecting this message */ if (ni->ni_rsn_supp_state != RNSA_SUPP_PTKDONE) { DPRINTF(("unexpected in state: %d\n", ni->ni_rsn_supp_state)); return; } /* enforce monotonicity of key request replay counter */ if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } info = BE_READ_2(key->info); /* check that encrypted and decrypt Key Data field using KEK */ if (!(info & EAPOL_KEY_ENCRYPTED) || ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) { DPRINTF(("decryption failed\n")); return; } /* parse key data field (shall contain a GTK KDE) */ frm = (const u_int8_t *)&key[1]; efrm = frm + BE_READ_2(key->paylen); gtk = igtk = NULL; while (frm + 2 <= efrm) { if (frm + 2 + frm[1] > efrm) break; switch (frm[0]) { case IEEE80211_ELEMID_VENDOR: if (frm[1] < 4) break; if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) { switch (frm[5]) { case IEEE80211_KDE_GTK: gtk = frm; break; case IEEE80211_KDE_IGTK: if (ni->ni_flags & IEEE80211_NODE_MFP) igtk = frm; break; } } break; } frm += 2 + frm[1]; } /* check that the GTK KDE is present */ if (gtk == NULL) { DPRINTF(("GTK KDE missing\n")); return; } /* check that key length matches that of group cipher */ keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher); if (gtk[1] != 6 + keylen) return; /* map GTK to 802.11 key */ kid = gtk[6] & 3; k = &ic->ic_nw_keys[kid]; if (ieee80211_must_update_group_key(k, >k[8], keylen)) { 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(key->rsc); k->k_len = keylen; memcpy(k->k_key, >k[8], k->k_len); /* install the GTK */ switch ((*ic->ic_set_key)(ic, ni, k)) { case 0: case EBUSY: break; default: reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } } if (igtk != NULL) { /* implies MFP */ /* check that the IGTK KDE is valid */ if (igtk[1] != 4 + 24) { reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } kid = LE_READ_2(&igtk[6]); if (kid != 4 && kid != 5) { DPRINTF(("unsupported IGTK id %u\n", kid)); reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } /* map IGTK to 802.11 key */ k = &ic->ic_nw_keys[kid]; if (ieee80211_must_update_group_key(k, &igtk[14], 16)) { memset(k, 0, sizeof(*k)); k->k_id = kid; /* either 4 or 5 */ k->k_cipher = ni->ni_rsngroupmgmtcipher; k->k_flags = IEEE80211_KEY_IGTK; k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */ k->k_len = 16; memcpy(k->k_key, &igtk[14], k->k_len); /* install the IGTK */ switch ((*ic->ic_set_key)(ic, ni, k)) { case 0: case EBUSY: break; default: reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } } } if (info & EAPOL_KEY_SECURE) { #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) #endif { DPRINTF(("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; } } /* update the last seen value of the key replay counter field */ ni->ni_replaycnt = BE_READ_8(key->replaycnt); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 1, 2, "group key", ether_sprintf(ni->ni_macaddr)); /* send message 2 to authenticator */ (void)ieee80211_send_group_msg2(ic, ni, NULL); return; deauth: IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, reason); ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); } /* * Process Message 1 of the WPA Group Key Handshake (sent by Authenticator). */ void ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); struct ieee80211_key *k; u_int16_t info; u_int8_t kid; int keylen; const uint8_t *gtk; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_STA && ic->ic_opmode != IEEE80211_M_IBSS) return; #endif /* discard if we're not expecting this message */ if (ni->ni_rsn_supp_state != RNSA_SUPP_PTKDONE) { DPRINTF(("unexpected in state: %d\n", ni->ni_rsn_supp_state)); return; } /* enforce monotonicity of key request replay counter */ if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } /* * EAPOL-Key data field is encrypted even though WPA doesn't set * the ENCRYPTED bit in the info field. */ if (ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) { DPRINTF(("decryption failed\n")); return; } /* check that key length matches that of group cipher */ keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher); if (BE_READ_2(key->keylen) != keylen) return; /* check that the data length is large enough to hold the key */ if (BE_READ_2(key->paylen) < keylen) return; info = BE_READ_2(key->info); /* map GTK to 802.11 key */ kid = (info >> EAPOL_KEY_WPA_KID_SHIFT) & 3; k = &ic->ic_nw_keys[kid]; gtk = (const uint8_t *)&key[1]; /* key data field contains the GTK */ if (ieee80211_must_update_group_key(k, gtk, keylen)) { memset(k, 0, sizeof(*k)); k->k_id = kid; /* 0-3 */ k->k_cipher = ni->ni_rsngroupcipher; k->k_flags = IEEE80211_KEY_GROUP; if (info & EAPOL_KEY_WPA_TX) k->k_flags |= IEEE80211_KEY_TX; k->k_rsc[0] = LE_READ_6(key->rsc); k->k_len = keylen; memcpy(k->k_key, gtk, k->k_len); /* install the GTK */ switch ((*ic->ic_set_key)(ic, ni, k)) { case 0: case EBUSY: break; default: IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return; } } if (info & EAPOL_KEY_SECURE) { #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) #endif { DPRINTF(("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; } } /* update the last seen value of the key replay counter field */ ni->ni_replaycnt = BE_READ_8(key->replaycnt); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 1, 2, "group key", ether_sprintf(ni->ni_macaddr)); /* send message 2 to authenticator */ (void)ieee80211_send_group_msg2(ic, ni, k); } #ifndef IEEE80211_STA_ONLY /* * Process Message 2 of the Group Key Handshake (sent by Supplicant). */ void ieee80211_recv_group_msg2(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_IBSS) return; /* discard if we're not expecting this message */ if (ni->ni_rsn_gstate != RSNA_REKEYNEGOTIATING) { DPRINTF(("%s: unexpected in state: %d\n", ic->ic_if.if_xname, ni->ni_rsn_gstate)); return; } /* enforce monotonicity of key request replay counter */ if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } /* check Key MIC field using KCK */ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } timeout_del(&ni->ni_eapol_to); ni->ni_rsn_gstate = RSNA_REKEYESTABLISHED; if (ni->ni_flags & IEEE80211_NODE_REKEY) { int rekeysta = 0; ni->ni_flags &= ~IEEE80211_NODE_REKEY; ieee80211_iterate_nodes(ic, ieee80211_count_rekeysta, &rekeysta); if (rekeysta == 0) ieee80211_setkeysdone(ic); } ni->ni_flags |= IEEE80211_NODE_TXRXPROT; ni->ni_rsn_gstate = RSNA_IDLE; ni->ni_rsn_retries = 0; if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 2, 2, "group key", ether_sprintf(ni->ni_macaddr)); } /* * EAPOL-Key Request frames are sent by the supplicant to request that the * authenticator initiates either a 4-Way Handshake or Group Key Handshake, * or to report a MIC failure in a TKIP MSDU. */ void ieee80211_recv_eapol_key_req(struct ieee80211com *ic, struct ieee80211_eapol_key *key, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); u_int16_t info; if (ic->ic_opmode != IEEE80211_M_HOSTAP && ic->ic_opmode != IEEE80211_M_IBSS) return; /* discard if we're not expecting this message */ if (ni->ni_rsn_state != RSNA_PTKINITDONE) { DPRINTF(("unexpected in state: %d\n", ni->ni_rsn_state)); return; } /* enforce monotonicity of key request replay counter */ if (ni->ni_reqreplaycnt_ok && BE_READ_8(key->replaycnt) <= ni->ni_reqreplaycnt) { ic->ic_stats.is_rx_eapol_replay++; return; } info = BE_READ_2(key->info); if (!(info & EAPOL_KEY_KEYMIC) || ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) { DPRINTF(("key request MIC failed\n")); ic->ic_stats.is_rx_eapol_badmic++; return; } /* update key request replay counter now that MIC is verified */ ni->ni_reqreplaycnt = BE_READ_8(key->replaycnt); ni->ni_reqreplaycnt_ok = 1; if (info & EAPOL_KEY_ERROR) { /* TKIP MIC failure */ /* ignore reports from STAs not using TKIP */ if (ic->ic_bss->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP && ni->ni_rsncipher != IEEE80211_CIPHER_TKIP) { DPRINTF(("MIC failure report from !TKIP STA: %s\n", ether_sprintf(ni->ni_macaddr))); return; } ic->ic_stats.is_rx_remmicfail++; ieee80211_michael_mic_failure(ic, LE_READ_6(key->rsc)); } else if (info & EAPOL_KEY_PAIRWISE) { /* initiate a 4-Way Handshake */ } else { /* * Should change the GTK, initiate the 4-Way Handshake and * then execute a Group Key Handshake with all supplicants. */ } } #endif /* IEEE80211_STA_ONLY */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_pae_output.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. */ /* $OpenBSD: ieee80211_pae_output.c,v 1.30 2017/12/21 12:09:38 mpi Exp $ */ /*- * Copyright (c) 2007,2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * This code implements the 4-Way Handshake and Group Key Handshake protocols * (both Supplicant and Authenticator Key Transmit state machines) defined in * IEEE Std 802.11-2007 section 8.5. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int ieee80211_send_eapol_key(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, const struct ieee80211_ptk *ptk); #ifndef IEEE80211_STA_ONLY u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, struct ieee80211_node *, const struct ieee80211_key *); u_int8_t *ieee80211_add_pmkid_kde(u_int8_t *, const u_int8_t *); u_int8_t *ieee80211_add_igtk_kde(u_int8_t *, const struct ieee80211_key *); #endif mbuf_t ieee80211_get_eapol_key(int, int, u_int); /* * Send an EAPOL-Key frame to node `ni'. If MIC or encryption is required, * the PTK must be passed (otherwise it can be set to NULL.) */ int ieee80211_send_eapol_key(struct ieee80211com *ic, mbuf_t m, struct ieee80211_node *ni, const struct ieee80211_ptk *ptk) { XYLog("%s\n", __FUNCTION__); struct _ifnet *ifp = &ic->ic_if; struct ether_header *eh; struct ieee80211_eapol_key *key; u_int16_t info; int len, error = 0; mbuf_prepend(&m, sizeof(struct ether_header), MBUF_DONTWAIT); if (m == NULL) return ENOMEM; /* no need to m_pullup here (ok by construction) */ eh = mtod(m, struct ether_header *); eh->ether_type = htons(ETHERTYPE_PAE); IEEE80211_ADDR_COPY(eh->ether_shost, ic->ic_myaddr); IEEE80211_ADDR_COPY(eh->ether_dhost, ni->ni_macaddr); key = (struct ieee80211_eapol_key *)&eh[1]; key->version = EAPOL_VERSION; key->type = EAPOL_KEY; key->desc = (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ? EAPOL_KEY_DESC_IEEE80211 : EAPOL_KEY_DESC_WPA; info = BE_READ_2(key->info); /* use V3 descriptor if KDF is SHA256-based */ if (ieee80211_is_sha256_akm((enum ieee80211_akm)ni->ni_rsnakms)) info |= EAPOL_KEY_DESC_V3; /* use V2 descriptor if pairwise or group cipher is CCMP */ else if (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP || ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP) info |= EAPOL_KEY_DESC_V2; else info |= EAPOL_KEY_DESC_V1; BE_WRITE_2(key->info, info); len = mbuf_len(m) - sizeof(struct ether_header); BE_WRITE_2(key->paylen, len - sizeof(*key)); BE_WRITE_2(key->len, len - 4); #ifndef IEEE80211_STA_ONLY if (info & EAPOL_KEY_ENCRYPTED) { if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) { /* clear "Encrypted" bit for WPA */ info &= ~EAPOL_KEY_ENCRYPTED; BE_WRITE_2(key->info, info); } ieee80211_eapol_key_encrypt(ic, key, ptk->kek); if ((info & EAPOL_KEY_VERSION_MASK) != EAPOL_KEY_DESC_V1) { /* AES Key Wrap adds 8 bytes + padding */ size_t l = sizeof(*eh) + 4 + BE_READ_2(key->len); mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); } } #endif if (info & EAPOL_KEY_KEYMIC) ieee80211_eapol_key_mic(key, ptk->kck); #ifndef IEEE80211_STA_ONLY /* start a 100ms timeout if an answer is expected from supplicant */ if (info & EAPOL_KEY_KEYACK) timeout_add_msec(&ni->ni_eapol_to, 100); #endif error = ifq_enqueue(&ifp->if_snd, m); if (error) { XYLog("%s enqueue fail!!\n", __FUNCTION__); return (error); } (*ifp->if_start)(ifp); return 0; } #ifndef IEEE80211_STA_ONLY /* * Handle EAPOL-Key timeouts (no answer from supplicant). */ void ieee80211_eapol_timeout(void *arg) { struct ieee80211_node *ni = (struct ieee80211_node *)arg; struct ieee80211com *ic = ni->ni_ic; int s; DPRINTF(("no answer from station %s in state %d\n", ether_sprintf(ni->ni_macaddr), ni->ni_rsn_state)); s = splnet(); switch (ni->ni_rsn_state) { case RSNA_PTKSTART: case RSNA_PTKCALCNEGOTIATING: (void)ieee80211_send_4way_msg1(ic, ni); break; case RSNA_PTKINITNEGOTIATING: (void)ieee80211_send_4way_msg3(ic, ni); break; } switch (ni->ni_rsn_gstate) { case RSNA_REKEYNEGOTIATING: (void)ieee80211_send_group_msg1(ic, ni); break; } splx(s); } /* * Add a GTK KDE to an EAPOL-Key frame (see Figure 144). */ u_int8_t * ieee80211_add_gtk_kde(u_int8_t *frm, struct ieee80211_node *ni, const struct ieee80211_key *k) { _KASSERT(k->k_flags & IEEE80211_KEY_GROUP); *frm++ = IEEE80211_ELEMID_VENDOR; *frm++ = 6 + k->k_len; memcpy(frm, IEEE80211_OUI, 3); frm += 3; *frm++ = IEEE80211_KDE_GTK; *frm = k->k_id & 3; /* * The TxRx flag for sending a GTK is always the opposite of whether * the pairwise key is used for data encryption/integrity or not. */ if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP) *frm |= 1 << 2; /* set the Tx bit */ frm++; *frm++ = 0; /* reserved */ memcpy(frm, k->k_key, k->k_len); return frm + k->k_len; } /* * Add a PMKID KDE to an EAPOL-Key frame (see Figure 146). */ u_int8_t * ieee80211_add_pmkid_kde(u_int8_t *frm, const u_int8_t *pmkid) { *frm++ = IEEE80211_ELEMID_VENDOR; *frm++ = 20; memcpy(frm, IEEE80211_OUI, 3); frm += 3; *frm++ = IEEE80211_KDE_PMKID; memcpy(frm, pmkid, IEEE80211_PMKID_LEN); return frm + IEEE80211_PMKID_LEN; } /* * Add an IGTK KDE to an EAPOL-Key frame (see Figure 8-32a). */ u_int8_t * ieee80211_add_igtk_kde(u_int8_t *frm, const struct ieee80211_key *k) { _KASSERT(k->k_flags & IEEE80211_KEY_IGTK); *frm++ = IEEE80211_ELEMID_VENDOR; *frm++ = 4 + 24; memcpy(frm, IEEE80211_OUI, 3); frm += 3; *frm++ = IEEE80211_KDE_IGTK; LE_WRITE_2(frm, k->k_id); frm += 2; LE_WRITE_6(frm, k->k_tsc); frm += 6; /* IPN */ memcpy(frm, k->k_key, 16); return frm + 16; } #endif /* IEEE80211_STA_ONLY */ mbuf_t ieee80211_get_eapol_key(int flags, int type, u_int pktlen) { mbuf_t m; /* reserve space for 802.11 encapsulation and EAPOL-Key header */ pktlen += sizeof(struct ieee80211_frame) + LLC_SNAPFRAMELEN + sizeof(struct ieee80211_eapol_key); if (pktlen > MCLBYTES) panic("EAPOL-Key frame too large: %u", pktlen); mbuf_gethdr(flags, type, &m); if (m == NULL) return NULL; if (pktlen > mbuf_get_mhlen()) { mbuf_mclget(flags, type, &m); if (!(mbuf_flags(m) & MBUF_EXT)) return mbuf_free(m); } mbuf_setdata(m, (char*)mbuf_data(m) + sizeof(struct ieee80211_frame) + LLC_SNAPFRAMELEN, mbuf_len(m) - sizeof(struct ieee80211_frame) - LLC_SNAPFRAMELEN); return m; } #ifndef IEEE80211_STA_ONLY /* * Send 4-Way Handshake Message 1 to the supplicant. */ int ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); struct ieee80211_eapol_key *key; mbuf_t m; u_int16_t info, keylen; u_int8_t *frm; ni->ni_rsn_state = RSNA_PTKSTART; if (++ni->ni_rsn_retries > 3) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_4WAY_TIMEOUT); ieee80211_node_leave(ic, ni); return 0; } m = ieee80211_get_eapol_key(MBUF_DONTWAIT, MT_DATA, (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ? 2 + 20 : 0); if (m == NULL) { XYLog("%s\n ieee80211_get_eapol_key==NULL", __FUNCTION__); return ENOMEM; } key = mtod(m, struct ieee80211_eapol_key *); memset(key, 0, sizeof(*key)); info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK; BE_WRITE_2(key->info, info); /* copy the authenticator's nonce (ANonce) */ memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN); keylen = ieee80211_cipher_keylen(ni->ni_rsncipher); BE_WRITE_2(key->keylen, keylen); frm = (u_int8_t *)&key[1]; /* NB: WPA does not have PMKID KDE */ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN && ieee80211_is_8021x_akm((enum ieee80211_akm)ni->ni_rsnakms)) frm = ieee80211_add_pmkid_kde(frm, ni->ni_pmkid); size_t l = frm - (u_int8_t *)key; mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: sending msg %d/%d of the %s handshake to %s\n", ic->ic_if.if_xname, 1, 4, "4-way", ether_sprintf(ni->ni_macaddr)); ni->ni_replaycnt++; BE_WRITE_8(key->replaycnt, ni->ni_replaycnt); return ieee80211_send_eapol_key(ic, m, ni, NULL); } #endif /* IEEE80211_STA_ONLY */ /* * Send 4-Way Handshake Message 2 to the authenticator. */ int ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni, const u_int8_t *replaycnt, const struct ieee80211_ptk *tptk) { XYLog("%s\n", __FUNCTION__); struct ieee80211_eapol_key *key; mbuf_t m; u_int16_t info; u_int8_t *frm; ni->ni_rsn_supp_state = RSNA_SUPP_PTKNEGOTIATING; m = ieee80211_get_eapol_key(MBUF_DONTWAIT, MT_DATA, (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ? 2 + IEEE80211_WPAIE_MAXLEN : 2 + IEEE80211_RSNIE_MAXLEN); if (m == NULL) return ENOMEM; key = mtod(m, struct ieee80211_eapol_key *); memset(key, 0, sizeof(*key)); info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC; BE_WRITE_2(key->info, info); /* copy key replay counter from Message 1/4 */ memcpy(key->replaycnt, replaycnt, 8); /* copy the supplicant's nonce (SNonce) */ memcpy(key->nonce, ic->ic_nonce, EAPOL_KEY_NONCE_LEN); frm = (u_int8_t *)&key[1]; /* add the WPA/RSN IE used in the (Re)Association Request */ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) { int keylen; frm = ieee80211_add_wpa(frm, ic, ni); /* WPA sets the key length field here */ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher); BE_WRITE_2(key->keylen, keylen); } else /* RSN */ frm = ieee80211_add_rsn(frm, ic, ni); size_t l = frm - (u_int8_t *)key; mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: sending msg %d/%d of the %s handshake to %s, type=%s\n", ic->ic_if.if_xname, 2, 4, "4-way", ether_sprintf(ni->ni_macaddr), ni->ni_rsnprotos == IEEE80211_PROTO_WPA ? "WPA" : "RSN"); return ieee80211_send_eapol_key(ic, m, ni, tptk); } #ifndef IEEE80211_STA_ONLY /* * Send 4-Way Handshake Message 3 to the supplicant. */ int ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); struct ieee80211_eapol_key *key; struct ieee80211_key *k = NULL; mbuf_t m; u_int16_t info, keylen; u_int8_t *frm; ni->ni_rsn_state = RSNA_PTKINITNEGOTIATING; if (++ni->ni_rsn_retries > 3) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_4WAY_TIMEOUT); ieee80211_node_leave(ic, ni); return 0; } if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) { k = &ic->ic_nw_keys[ic->ic_def_txkey]; m = ieee80211_get_eapol_key(MBUF_DONTWAIT, MT_DATA, 2 + IEEE80211_RSNIE_MAXLEN + 2 + 6 + k->k_len + 15 + ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0)); } else { /* WPA */ m = ieee80211_get_eapol_key(MBUF_DONTWAIT, MT_DATA, 2 + IEEE80211_WPAIE_MAXLEN + ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0)); } if (m == NULL) return ENOMEM; key = mtod(m, struct ieee80211_eapol_key *); memset(key, 0, sizeof(*key)); info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC; if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) info |= EAPOL_KEY_INSTALL; /* use same nonce as in Message 1 */ memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN); ni->ni_replaycnt++; BE_WRITE_8(key->replaycnt, ni->ni_replaycnt); keylen = ieee80211_cipher_keylen(ni->ni_rsncipher); BE_WRITE_2(key->keylen, keylen); frm = (u_int8_t *)&key[1]; /* add the WPA/RSN IE included in Beacon/Probe Response */ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) { frm = ieee80211_add_rsn(frm, ic, ic->ic_bss); /* encapsulate the GTK */ frm = ieee80211_add_gtk_kde(frm, ni, k); LE_WRITE_6(key->rsc, k->k_tsc); /* encapsulate the IGTK if MFP was negotiated */ if (ni->ni_flags & IEEE80211_NODE_MFP) { frm = ieee80211_add_igtk_kde(frm, &ic->ic_nw_keys[ic->ic_igtk_kid]); } /* ask that the EAPOL-Key frame be encrypted */ info |= EAPOL_KEY_ENCRYPTED | EAPOL_KEY_SECURE; } else /* WPA */ frm = ieee80211_add_wpa(frm, ic, ic->ic_bss); /* write the key info field */ BE_WRITE_2(key->info, info); size_t l = frm - (u_int8_t *)key; mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: sending msg %d/%d of the %s handshake to %s\n", ic->ic_if.if_xname, 3, 4, "4-way", ether_sprintf(ni->ni_macaddr)); return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk); } #endif /* IEEE80211_STA_ONLY */ /* * Send 4-Way Handshake Message 4 to the authenticator. */ int ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); struct ieee80211_eapol_key *key; mbuf_t m; u_int16_t info; ni->ni_rsn_supp_state = RNSA_SUPP_PTKDONE; m = ieee80211_get_eapol_key(MBUF_DONTWAIT, MT_DATA, 0); if (m == NULL) return ENOMEM; key = mtod(m, struct ieee80211_eapol_key *); memset(key, 0, sizeof(*key)); info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC; /* copy key replay counter from authenticator */ BE_WRITE_8(key->replaycnt, ni->ni_replaycnt); if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) { int keylen; /* WPA sets the key length field here */ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher); BE_WRITE_2(key->keylen, keylen); } else info |= EAPOL_KEY_SECURE; /* write the key info field */ BE_WRITE_2(key->info, info); /* empty key data field */ mbuf_pkthdr_setlen(m, sizeof(*key)); mbuf_setlen(m, sizeof(*key)); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: sending msg %d/%d of the %s handshake to %s\n", ic->ic_if.if_xname, 4, 4, "4-way", ether_sprintf(ni->ni_macaddr)); return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk); } #ifndef IEEE80211_STA_ONLY /* * Send Group Key Handshake Message 1 to the supplicant. */ int ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni) { XYLog("%s Send Group Key Handshake Message 1 to the supplicant.\n", __FUNCTION__); struct ieee80211_eapol_key *key; const struct ieee80211_key *k; mbuf_t m; u_int16_t info; u_int8_t *frm; u_int8_t kid; ni->ni_rsn_gstate = RSNA_REKEYNEGOTIATING; if (++ni->ni_rsn_retries > 3) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_GROUP_TIMEOUT); ieee80211_node_leave(ic, ni); return 0; } if (ni->ni_flags & IEEE80211_NODE_REKEY) kid = (ic->ic_def_txkey == 1) ? 2 : 1; else kid = ic->ic_def_txkey; k = &ic->ic_nw_keys[kid]; m = ieee80211_get_eapol_key(MBUF_DONTWAIT, MT_DATA, ((ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ? k->k_len : 2 + 6 + k->k_len) + ((ni->ni_flags & IEEE80211_NODE_MFP) ? 2 + 28 : 0) + 15); if (m == NULL) return ENOMEM; key = mtod(m, struct ieee80211_eapol_key *); memset(key, 0, sizeof(*key)); info = EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE | EAPOL_KEY_ENCRYPTED; ni->ni_replaycnt++; BE_WRITE_8(key->replaycnt, ni->ni_replaycnt); frm = (u_int8_t *)&key[1]; if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) { /* WPA does not have GTK KDE */ BE_WRITE_2(key->keylen, k->k_len); memcpy(frm, k->k_key, k->k_len); frm += k->k_len; info |= (k->k_id & 0x3) << EAPOL_KEY_WPA_KID_SHIFT; if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP) info |= EAPOL_KEY_WPA_TX; } else { /* RSN */ frm = ieee80211_add_gtk_kde(frm, ni, k); if (ni->ni_flags & IEEE80211_NODE_MFP) { if (ni->ni_flags & IEEE80211_NODE_REKEY) kid = (ic->ic_igtk_kid == 4) ? 5 : 4; else kid = ic->ic_igtk_kid; frm = ieee80211_add_igtk_kde(frm, &ic->ic_nw_keys[kid]); } } /* RSC = last transmit sequence number for the GTK */ LE_WRITE_6(key->rsc, k->k_tsc); /* write the key info field */ BE_WRITE_2(key->info, info); size_t l = frm - (u_int8_t *)key; mbuf_pkthdr_setlen(m, l); mbuf_setlen(m, l); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: sending msg %d/%d of the %s handshake to %s\n", ic->ic_if.if_xname, 1, 2, "group key", ether_sprintf(ni->ni_macaddr)); return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk); } #endif /* IEEE80211_STA_ONLY */ /* * Send Group Key Handshake Message 2 to the authenticator. */ int ieee80211_send_group_msg2(struct ieee80211com *ic, struct ieee80211_node *ni, const struct ieee80211_key *k) { XYLog("%s\n", __FUNCTION__); struct ieee80211_eapol_key *key; u_int16_t info; mbuf_t m; m = ieee80211_get_eapol_key(MBUF_DONTWAIT, MT_DATA, 0); if (m == NULL) return ENOMEM; key = mtod(m, struct ieee80211_eapol_key *); memset(key, 0, sizeof(*key)); info = EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE; /* copy key replay counter from authenticator */ BE_WRITE_8(key->replaycnt, ni->ni_replaycnt); if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) { /* WPA sets the key length and key id fields here */ BE_WRITE_2(key->keylen, k->k_len); info |= (k->k_id & 3) << EAPOL_KEY_WPA_KID_SHIFT; } /* write the key info field */ BE_WRITE_2(key->info, info); /* empty key data field */ mbuf_pkthdr_setlen(m, sizeof(*key)); mbuf_setlen(m, sizeof(*key)); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: sending msg %d/%d of the %s handshake to %s\n", ic->ic_if.if_xname, 2, 2, "group key", ether_sprintf(ni->ni_macaddr)); return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk); } /* * EAPOL-Key Request frames are sent by the supplicant to request that the * authenticator initiates either a 4-Way Handshake or Group Key Handshake, * or to report a MIC failure in a TKIP MSDU. */ int ieee80211_send_eapol_key_req(struct ieee80211com *ic, struct ieee80211_node *ni, u_int16_t info, u_int64_t tsc) { XYLog("%s\n", __FUNCTION__); struct ieee80211_eapol_key *key; mbuf_t m; m = ieee80211_get_eapol_key(MBUF_DONTWAIT, MT_DATA, 0); if (m == NULL) return ENOMEM; key = mtod(m, struct ieee80211_eapol_key *); memset(key, 0, sizeof(*key)); info |= EAPOL_KEY_REQUEST; BE_WRITE_2(key->info, info); /* in case of TKIP MIC failure, fill the RSC field */ if (info & EAPOL_KEY_ERROR) LE_WRITE_6(key->rsc, tsc); /* use our separate key replay counter for key requests */ BE_WRITE_8(key->replaycnt, ni->ni_reqreplaycnt); ni->ni_reqreplaycnt++; /* empty key data field */ mbuf_pkthdr_setlen(m, sizeof(*key)); mbuf_setlen(m, sizeof(*key)); if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: sending EAPOL-Key request to %s\n", ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr)); return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk); } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_priv.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_priv.h,v 1.5 2009/01/26 19:09:41 damien Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _NET80211_IEEE80211_PRIV_H_ #define _NET80211_IEEE80211_PRIV_H_ #ifdef IEEE80211_DEBUG extern int ieee80211_debug; #define DPRINTF(X) do { \ if (ieee80211_debug) { \ XYLog("%s ieee80211: ", __FUNCTION__); \ XYLog X; \ } \ } while(0) #else #define DPRINTF(X) #endif #define SEQ_LT(a,b) \ ((((u_int16_t)(a) - (u_int16_t)(b)) & 0xfff) > 2048) #define IEEE80211_AID_SET(b, w) \ ((w)[IEEE80211_AID(b) / 32] |= (1 << (IEEE80211_AID(b) % 32))) #define IEEE80211_AID_CLR(b, w) \ ((w)[IEEE80211_AID(b) / 32] &= ~(1 << (IEEE80211_AID(b) % 32))) #define IEEE80211_AID_ISSET(b, w) \ ((w)[IEEE80211_AID(b) / 32] & (1 << (IEEE80211_AID(b) % 32))) #define IEEE80211_RSNIE_MAXLEN \ (2 + /* Version */ \ 4 + /* Group Data Cipher Suite */ \ 2 + /* Pairwise Cipher Suite Count */ \ 4 * 2 + /* Pairwise Cipher Suite List (max 2) */ \ 2 + /* AKM Suite List Count */ \ 4 * 4 + /* AKM Suite List (max 4) */ \ 2 + /* RSN Capabilities */ \ 2 + /* PMKID Count */ \ 16 * 1 + /* PMKID List (max 1) */ \ 4) /* 11w: Group Integrity Cipher Suite */ #define IEEE80211_WPAIE_MAXLEN \ (4 + /* MICROSOFT_OUI */ \ 2 + /* Version */ \ 4 + /* Group Cipher Suite */ \ 2 + /* Pairwise Cipher Suite Count */ \ 4 * 2 + /* Pairwise Cipher Suite List (max 2) */ \ 2 + /* AKM Suite List Count */ \ 4 * 2) /* AKM Suite List (max 2) */ struct ieee80211_rsnparams { u_int16_t rsn_nakms; u_int32_t rsn_akms; u_int16_t rsn_nciphers; u_int32_t rsn_ciphers; enum ieee80211_cipher rsn_groupcipher; enum ieee80211_cipher rsn_groupmgmtcipher; u_int16_t rsn_caps; u_int8_t rsn_npmkids; const u_int8_t *rsn_pmkids; }; /* unaligned big endian access */ #define BE_READ_2(p) \ ((u_int16_t) \ ((((const u_int8_t *)(p))[0] << 8) | \ (((const u_int8_t *)(p))[1]))) #define BE_READ_8(p) \ ((u_int64_t)(p)[0] << 56 | (u_int64_t)(p)[1] << 48 | \ (u_int64_t)(p)[2] << 40 | (u_int64_t)(p)[3] << 32 | \ (u_int64_t)(p)[4] << 24 | (u_int64_t)(p)[5] << 16 | \ (u_int64_t)(p)[6] << 8 | (u_int64_t)(p)[7]) #define BE_WRITE_2(p, v) do { \ ((u_int8_t *)(p))[0] = (v) >> 8; \ ((u_int8_t *)(p))[1] = (v) & 0xff; \ } while (0) #define BE_WRITE_8(p, v) do { \ (p)[0] = (v) >> 56; (p)[1] = (v) >> 48; \ (p)[2] = (v) >> 40; (p)[3] = (v) >> 32; \ (p)[4] = (v) >> 24; (p)[5] = (v) >> 16; \ (p)[6] = (v) >> 8; (p)[7] = (v); \ } while (0) /* unaligned little endian access */ #define LE_READ_2(p) \ ((u_int16_t) \ ((((const u_int8_t *)(p))[0]) | \ (((const u_int8_t *)(p))[1] << 8))) #define LE_READ_4(p) \ ((u_int32_t) \ ((((const u_int8_t *)(p))[0]) | \ (((const u_int8_t *)(p))[1] << 8) | \ (((const u_int8_t *)(p))[2] << 16) | \ (((const u_int8_t *)(p))[3] << 24))) #define LE_READ_6(p) \ ((u_int64_t)(p)[5] << 40 | (u_int64_t)(p)[4] << 32 | \ (u_int64_t)(p)[3] << 24 | (u_int64_t)(p)[2] << 16 | \ (u_int64_t)(p)[1] << 8 | (u_int64_t)(p)[0]) #define LE_WRITE_2(p, v) do { \ ((u_int8_t *)(p))[0] = (v) & 0xff; \ ((u_int8_t *)(p))[1] = (v) >> 8; \ } while (0) #define LE_WRITE_4(p, v) do { \ (p)[3] = (v) >> 24; (p)[2] = (v) >> 16; \ (p)[1] = (v) >> 8; (p)[0] = (v); \ } while (0) #define LE_WRITE_6(p, v) do { \ (p)[5] = (v) >> 40; (p)[4] = (v) >> 32; \ (p)[3] = (v) >> 24; (p)[2] = (v) >> 16; \ (p)[1] = (v) >> 8; (p)[0] = (v); \ } while (0) #endif /* _NET80211_IEEE80211_PRIV_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_proto.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. */ /* $OpenBSD: ieee80211_proto.c,v 1.95 2019/09/02 12:54:21 stsp Exp $ */ /* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * Copyright (c) 2008, 2009 Damien Bergamini * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * IEEE 802.11 protocol support. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char * const ieee80211_mgt_subtype_name[] = { "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", "probe_req", "probe_resp", "reserved#6", "reserved#7", "beacon", "atim", "disassoc", "auth", "deauth", "action", "action_noack", "reserved#15" }; const char * const ieee80211_state_name[IEEE80211_S_MAX] = { "INIT", /* IEEE80211_S_INIT */ "SCAN", /* IEEE80211_S_SCAN */ "AUTH", /* IEEE80211_S_AUTH */ "ASSOC", /* IEEE80211_S_ASSOC */ "RUN" /* IEEE80211_S_RUN */ }; const char * const ieee80211_phymode_name[] = { "auto", /* IEEE80211_MODE_AUTO */ "11a", /* IEEE80211_MODE_11A */ "11b", /* IEEE80211_MODE_11B */ "11g", /* IEEE80211_MODE_11G */ "11n", /* IEEE80211_MODE_11N */ "11ac", /* IEEE80211_MODE_11AC */ "11ax", /* IEEE80211_MODE_11AX */ }; void ieee80211_set_beacon_miss_threshold(struct ieee80211com *); int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); void ieee80211_proto_attach(struct _ifnet *ifp) { struct ieee80211com *ic = (struct ieee80211com *)ifp; mq_init(&ic->ic_mgtq, IFQ_MAXLEN, IPL_NET); mq_init(&ic->ic_pwrsaveq, IFQ_MAXLEN, IPL_NET); ifp->if_hdrlen = sizeof(struct ieee80211_frame); ic->ic_rtsthreshold = IEEE80211_RTS_MAX; ic->ic_fragthreshold = 2346; /* XXX not used yet */ ic->ic_fixed_rate = -1; /* no fixed rate */ ic->ic_fixed_mcs = -1; /* no fixed mcs */ ic->ic_protmode = IEEE80211_PROT_CTSONLY; /* protocol state change handler */ ic->ic_newstate = ieee80211_newstate; /* initialize management frame handlers */ ic->ic_recv_mgmt = ieee80211_recv_mgmt; ic->ic_send_mgmt = ieee80211_send_mgmt; } void ieee80211_proto_detach(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = (struct ieee80211com *)ifp; mq_purge(&ic->ic_mgtq); mq_purge(&ic->ic_pwrsaveq); } void ieee80211_print_essid(const u_int8_t *essid, int len) { int i; const u_int8_t *p; XYLog("%s\n", essid); // if (len > IEEE80211_NWID_LEN) // len = IEEE80211_NWID_LEN; // /* determine printable or not */ // for (i = 0, p = essid; i < len; i++, p++) { // if (*p < ' ' || *p > 0x7e) // break; // } // if (i == len) { // XYLog("\""); // for (i = 0, p = essid; i < len; i++, p++) // XYLog("%c", *p); // XYLog("\""); // } else { // XYLog("0x"); // for (i = 0, p = essid; i < len; i++, p++) // XYLog("%02x", *p); // } } #ifdef IEEE80211_DEBUG void ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi) { struct ieee80211_frame *wh; int i; wh = (struct ieee80211_frame *)buf; switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { case IEEE80211_FC1_DIR_NODS: XYLog("NODS %s", ether_sprintf(wh->i_addr2)); XYLog("->%s", ether_sprintf(wh->i_addr1)); XYLog("(%s)", ether_sprintf(wh->i_addr3)); break; case IEEE80211_FC1_DIR_TODS: XYLog("TODS %s", ether_sprintf(wh->i_addr2)); XYLog("->%s", ether_sprintf(wh->i_addr3)); XYLog("(%s)", ether_sprintf(wh->i_addr1)); break; case IEEE80211_FC1_DIR_FROMDS: XYLog("FRDS %s", ether_sprintf(wh->i_addr3)); XYLog("->%s", ether_sprintf(wh->i_addr1)); XYLog("(%s)", ether_sprintf(wh->i_addr2)); break; case IEEE80211_FC1_DIR_DSTODS: XYLog("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); XYLog("->%s", ether_sprintf(wh->i_addr3)); XYLog("(%s", ether_sprintf(wh->i_addr2)); XYLog("->%s)", ether_sprintf(wh->i_addr1)); break; } switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { case IEEE80211_FC0_TYPE_DATA: XYLog(" data"); break; case IEEE80211_FC0_TYPE_MGT: XYLog(" %s", ieee80211_mgt_subtype_name[ (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >> IEEE80211_FC0_SUBTYPE_SHIFT]); break; default: XYLog(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); break; } if (wh->i_fc[1] & IEEE80211_FC1_WEP) XYLog(" WEP"); if (rate >= 0) XYLog(" %d%sM", rate / 2, (rate & 1) ? ".5" : ""); if (rssi >= 0) XYLog(" +%d", rssi); XYLog("\n"); if (len > 0) { for (i = 0; i < len; i++) { if ((i & 1) == 0) XYLog(" "); XYLog("%02x", buf[i]); } XYLog("\n"); } } #endif int ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) { #define RV(v) ((v) & IEEE80211_RATE_VAL) int i, j, ignore, error; int okrate, badrate, fixedrate; const struct ieee80211_rateset *srs; struct ieee80211_rateset *nrs; u_int8_t r; /* * If the fixed rate check was requested but no fixed rate has been * defined then just remove the check. */ if ((flags & IEEE80211_F_DOFRATE) && ic->ic_fixed_rate == -1) flags &= ~IEEE80211_F_DOFRATE; error = 0; okrate = badrate = fixedrate = 0; srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; nrs = &ni->ni_rates; for (i = 0; i < nrs->rs_nrates; ) { ignore = 0; if (flags & IEEE80211_F_DOSORT) { /* * Sort rates. */ for (j = i + 1; j < nrs->rs_nrates; j++) { if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { r = nrs->rs_rates[i]; nrs->rs_rates[i] = nrs->rs_rates[j]; nrs->rs_rates[j] = r; } } } r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; badrate = r; if (flags & IEEE80211_F_DOFRATE) { /* * Check fixed rate is included. */ if (r == RV(srs->rs_rates[ic->ic_fixed_rate])) fixedrate = r; } if (flags & IEEE80211_F_DONEGO) { /* * Check against supported rates. */ for (j = 0; j < srs->rs_nrates; j++) { if (r == RV(srs->rs_rates[j])) { /* * Overwrite with the supported rate * value so any basic rate bit is set. * This insures that response we send * to stations have the necessary basic * rate bit set. */ nrs->rs_rates[i] = srs->rs_rates[j]; break; } } if (j == srs->rs_nrates) { /* * A rate in the node's rate set is not * supported. If this is a basic rate and we * are operating as an AP then this is an error. * Otherwise we just discard/ignore the rate. * Note that this is important for 11b stations * when they want to associate with an 11g AP. */ #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP && (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) error++; #endif ignore++; } } if (flags & IEEE80211_F_DODEL) { /* * Delete unacceptable rates. */ if (ignore) { nrs->rs_nrates--; for (j = i; j < nrs->rs_nrates; j++) nrs->rs_rates[j] = nrs->rs_rates[j + 1]; nrs->rs_rates[j] = 0; continue; } } if (!ignore) okrate = nrs->rs_rates[i]; i++; } if (okrate == 0 || error != 0 || ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0)) return badrate | IEEE80211_RATE_BASIC; else return RV(okrate); #undef RV } /* * Reset 11g-related state. */ void ieee80211_reset_erp(struct ieee80211com *ic) { ic->ic_flags &= ~IEEE80211_F_USEPROT; ieee80211_set_shortslottime(ic, ic->ic_curmode == IEEE80211_MODE_11A || (ic->ic_curmode == IEEE80211_MODE_11N && IEEE80211_IS_CHAN_5GHZ(ic->ic_ibss_chan)) #ifndef IEEE80211_STA_ONLY || ((ic->ic_curmode == IEEE80211_MODE_11G || (ic->ic_curmode == IEEE80211_MODE_11N && IEEE80211_IS_CHAN_2GHZ(ic->ic_ibss_chan))) && ic->ic_opmode == IEEE80211_M_HOSTAP && (ic->ic_caps & IEEE80211_C_SHSLOT)) #endif ); if (ic->ic_curmode == IEEE80211_MODE_11A || (ic->ic_curmode == IEEE80211_MODE_11N && IEEE80211_IS_CHAN_5GHZ(ic->ic_ibss_chan)) || (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) ic->ic_flags |= IEEE80211_F_SHPREAMBLE; else ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; } /* * Set the short slot time state and notify the driver. */ void ieee80211_set_shortslottime(struct ieee80211com *ic, int on) { if (on) ic->ic_flags |= IEEE80211_F_SHSLOT; else ic->ic_flags &= ~IEEE80211_F_SHSLOT; /* notify the driver */ if (ic->ic_updateslot != NULL) ic->ic_updateslot(ic); } /* * This function is called by the 802.1X PACP machine (via an ioctl) when * the transmit key machine (4-Way Handshake for 802.11) should run. */ int ieee80211_keyrun(struct ieee80211com *ic, u_int8_t *macaddr) { XYLog("%s\n", __FUNCTION__); struct ieee80211_node *ni = ic->ic_bss; #ifndef IEEE80211_STA_ONLY struct ieee80211_pmk *pmk; #endif /* STA must be associated or AP must be ready */ if (ic->ic_state != IEEE80211_S_RUN || !(ic->ic_flags & IEEE80211_F_RSNON)) return ENETDOWN; ni->ni_rsn_supp_state = RSNA_SUPP_PTKSTART; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_STA) #endif return 0; /* supplicant only, do nothing */ #ifndef IEEE80211_STA_ONLY /* find the STA with which we must start the key exchange */ if ((ni = ieee80211_find_node(ic, macaddr)) == NULL) { DPRINTF(("no node found for %s\n", ether_sprintf(macaddr))); return EINVAL; } /* check that the STA is in the correct state */ if (ni->ni_state != IEEE80211_STA_ASSOC || ni->ni_rsn_state != RSNA_AUTHENTICATION_2) { DPRINTF(("unexpected in state %d\n", ni->ni_rsn_state)); return EINVAL; } ni->ni_rsn_state = RSNA_INITPMK; /* make sure a PMK is available for this STA, otherwise deauth it */ if ((pmk = ieee80211_pmksa_find(ic, ni, NULL)) == NULL) { DPRINTF(("no PMK available for %s\n", ether_sprintf(macaddr))); IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); ieee80211_node_leave(ic, ni); return EINVAL; } memcpy(ni->ni_pmk, pmk->pmk_key, IEEE80211_PMK_LEN); memcpy(ni->ni_pmkid, pmk->pmk_pmkid, IEEE80211_PMKID_LEN); ni->ni_flags |= IEEE80211_NODE_PMK; /* initiate key exchange (4-Way Handshake) with STA */ return ieee80211_send_4way_msg1(ic, ni); #endif /* IEEE80211_STA_ONLY */ } #ifndef IEEE80211_STA_ONLY /* * Initiate a group key handshake with a node. */ static void ieee80211_node_gtk_rekey(void *arg, struct ieee80211_node *ni) { struct ieee80211com *ic = (struct ieee80211com *)arg; if (ni->ni_state != IEEE80211_STA_ASSOC || ni->ni_rsn_gstate != RSNA_IDLE) return; /* initiate a group key handshake with STA */ ni->ni_flags |= IEEE80211_NODE_REKEY; if (ieee80211_send_group_msg1(ic, ni) != 0) ni->ni_flags &= ~IEEE80211_NODE_REKEY; } /* * This function is called in HostAP mode when the group key needs to be * changed. */ void ieee80211_setkeys(struct ieee80211com *ic) { struct ieee80211_key *k; u_int8_t kid; int rekeysta = 0; /* Swap(GM, GN) */ kid = (ic->ic_def_txkey == 1) ? 2 : 1; k = &ic->ic_nw_keys[kid]; memset(k, 0, sizeof(*k)); k->k_id = kid; k->k_cipher = ic->ic_bss->ni_rsngroupcipher; k->k_flags = IEEE80211_KEY_GROUP | IEEE80211_KEY_TX; k->k_len = ieee80211_cipher_keylen(k->k_cipher); arc4random_buf(k->k_key, k->k_len); if (ic->ic_caps & IEEE80211_C_MFP) { /* Swap(GM_igtk, GN_igtk) */ kid = (ic->ic_igtk_kid == 4) ? 5 : 4; k = &ic->ic_nw_keys[kid]; memset(k, 0, sizeof(*k)); k->k_id = kid; k->k_cipher = ic->ic_bss->ni_rsngroupmgmtcipher; k->k_flags = IEEE80211_KEY_IGTK | IEEE80211_KEY_TX; k->k_len = 16; arc4random_buf(k->k_key, k->k_len); } ieee80211_iterate_nodes(ic, ieee80211_node_gtk_rekey, ic); ieee80211_iterate_nodes(ic, ieee80211_count_rekeysta, &rekeysta); if (rekeysta == 0) ieee80211_setkeysdone(ic); } /* * The group key handshake has been completed with all associated stations. */ void ieee80211_setkeysdone(struct ieee80211com *ic) { u_int8_t kid; /* install GTK */ kid = (ic->ic_def_txkey == 1) ? 2 : 1; switch ((*ic->ic_set_key)(ic, ic->ic_bss, &ic->ic_nw_keys[kid])) { case 0: case EBUSY: ic->ic_def_txkey = kid; break; default: break; } if (ic->ic_caps & IEEE80211_C_MFP) { /* install IGTK */ kid = (ic->ic_igtk_kid == 4) ? 5 : 4; switch ((*ic->ic_set_key)(ic, ic->ic_bss, &ic->ic_nw_keys[kid])) { case 0: case EBUSY: ic->ic_igtk_kid = kid; break; default: break; } } } /* * Group key lifetime has expired, update it. */ void ieee80211_gtk_rekey_timeout(void *arg) { struct ieee80211com *ic = (struct ieee80211com *)arg; int s; s = splnet(); ieee80211_setkeys(ic); splx(s); /* re-schedule a GTK rekeying after 3600s */ timeout_add_sec(&ic->ic_rsn_timeout, 3600); } void ieee80211_sa_query_timeout(void *arg) { struct ieee80211_node *ni = (struct ieee80211_node *)arg; struct ieee80211com *ic = ni->ni_ic; int s; s = splnet(); if (++ni->ni_sa_query_count >= 3) { ni->ni_flags &= ~IEEE80211_NODE_SA_QUERY; ni->ni_flags |= IEEE80211_NODE_SA_QUERY_FAILED; } else /* retry SA Query Request */ ieee80211_sa_query_request(ic, ni); splx(s); } /* * Request that a SA Query Request frame be sent to a specified peer STA * to which the STA is associated. */ void ieee80211_sa_query_request(struct ieee80211com *ic, struct ieee80211_node *ni) { /* MLME-SAQuery.request */ if (!(ni->ni_flags & IEEE80211_NODE_SA_QUERY)) { ni->ni_flags |= IEEE80211_NODE_SA_QUERY; ni->ni_flags &= ~IEEE80211_NODE_SA_QUERY_FAILED; ni->ni_sa_query_count = 0; } /* generate new Transaction Identifier */ ni->ni_sa_query_trid++; /* send SA Query Request */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_SA_QUERY, IEEE80211_ACTION_SA_QUERY_REQ, 0); timeout_add_msec(&ni->ni_sa_query_to, 10); } #endif /* IEEE80211_STA_ONLY */ void ieee80211_ht_negotiate_chw(struct ieee80211com *ic, struct ieee80211_node *ni) { int ht_param; if (!ni || !ni->ni_chan) return; ni->ni_chw = IEEE80211_CHAN_WIDTH_20; ni->ni_chan->ic_center_freq1 = ni->ni_chan->ic_freq; if (((ic->ic_htcaps & IEEE80211_HTCAP_40INTOLERANT) || (ni->ni_htcaps & IEEE80211_HTCAP_40INTOLERANT) || (ic->ic_userflags & IEEE80211_F_NOHT40)) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { ni->ni_chw = IEEE80211_CHAN_WIDTH_20; } else if ((ni->ni_htcaps & IEEE80211_HTCAP_CBW20_40) && IEEE80211_IS_CHAN_HT40(ni->ni_chan) && (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40)) { ht_param = ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK; if ((ht_param == IEEE80211_HTOP0_SCO_SCA) || (ht_param == IEEE80211_HTOP0_SCO_SCB)) ni->ni_chw = IEEE80211_CHAN_WIDTH_40; } if (ni->ni_chw == IEEE80211_CHAN_WIDTH_40) { if ((ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK) == IEEE80211_HTOP0_SCO_SCA) ni->ni_chan->ic_center_freq1 = ni->ni_chan->ic_freq + 10; else ni->ni_chan->ic_center_freq1 = ni->ni_chan->ic_freq - 10; } } void ieee80211_ht_negotiate(struct ieee80211com *ic, struct ieee80211_node *ni) { int i; ni->ni_flags &= ~(IEEE80211_NODE_HT | IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40); ni->ni_chw = IEEE80211_CHAN_WIDTH_20; ni->ni_chan->ic_center_freq1 = ni->ni_chan->ic_freq; /* Check if we support HT. */ if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11N)) == 0) return; /* Check if HT support has been explicitly disabled. */ if ((ic->ic_flags & IEEE80211_F_HTON) == 0) return; /* * Check if the peer supports HT. * Require at least one of the mandatory MCS. * MCS 0-7 are mandatory but some APs have particular MCS disabled. */ if (!ieee80211_node_supports_ht(ni)) { ic->ic_stats.is_ht_nego_no_mandatory_mcs++; return; } if (ic->ic_opmode == IEEE80211_M_STA) { /* We must support the AP's basic MCS set. */ for (i = 0; i < IEEE80211_HT_NUM_MCS; i++) { if (isset(ni->ni_basic_mcs, i) && !isset(ic->ic_sup_mcs, i)) { ic->ic_stats.is_ht_nego_no_basic_mcs++; return; } } } /* * Don't allow group cipher (includes WEP) or TKIP * for pairwise encryption (see 802.11-2012 11.1.6). */ if (ic->ic_flags & IEEE80211_F_WEPON) { ic->ic_stats.is_ht_nego_bad_crypto++; return; } if ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnciphers & IEEE80211_CIPHER_USEGROUP || ni->ni_rsnciphers & IEEE80211_CIPHER_TKIP)) { ic->ic_stats.is_ht_nego_bad_crypto++; return; } ni->ni_flags |= IEEE80211_NODE_HT; if (ieee80211_node_supports_ht_sgi20(ni)) ni->ni_flags |= IEEE80211_NODE_HT_SGI20; ieee80211_ht_negotiate_chw(ic, ni); if (ni->ni_chw == IEEE80211_CHAN_WIDTH_40 && ieee80211_node_supports_ht_sgi40(ni)) ni->ni_flags |= IEEE80211_NODE_HT_SGI40; XYLog("%s chan_width=%s\n", __FUNCTION__, ieee80211_chan_width_name[ni->ni_chw]); } void ieee80211_vht_negotiate(struct ieee80211com *ic, struct ieee80211_node *ni) { uint8_t ext_nss_bw_supp, supp_chwidth; uint16_t cf0, cf1; int ccfs0, ccfs1, ccfs2; int ccf0, ccf1; bool support_80_80 = false; bool support_160 = false; ni->ni_flags &= ~(IEEE80211_NODE_VHT | IEEE80211_NODE_VHT_SGI80 | IEEE80211_NODE_VHT_SGI160); /* Check if we support VHT. */ if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11AC)) == 0) return; if (ic->ic_userflags & IEEE80211_F_NOVHT) return; /* Check if VHT support has been explicitly disabled. */ if ((ic->ic_flags & IEEE80211_F_VHTON) == 0) return; if (!IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) return; if (!ieee80211_node_supports_vht(ni)) { ic->ic_stats.is_vht_nego_no_mandatory_mcs++; return; } /* * Don't allow group cipher (includes WEP) or TKIP * for pairwise encryption (see 802.11-2012 11.1.6). */ if (ic->ic_flags & IEEE80211_F_WEPON) { ic->ic_stats.is_vht_nego_bad_crypto++; return; } if ((ic->ic_flags & IEEE80211_F_RSNON) && (ni->ni_rsnciphers & IEEE80211_CIPHER_USEGROUP || ni->ni_rsnciphers & IEEE80211_CIPHER_TKIP)) { ic->ic_stats.is_vht_nego_bad_crypto++; return; } support_160 = (ni->ni_vhtcaps & (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK | IEEE80211_VHTCAP_EXT_NSS_BW_MASK)); support_80_80 = ((ni->ni_vhtcaps & IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160_80P80MHZ) || (ni->ni_vhtcaps & IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ && ni->ni_vhtcaps & IEEE80211_VHTCAP_EXT_NSS_BW_MASK) || ((ni->ni_vhtcaps & IEEE80211_VHTCAP_EXT_NSS_BW_MASK) >> IEEE80211_VHTCAP_EXT_NSS_BW_SHIFT > 1)); ext_nss_bw_supp = u32_get_bits(ni->ni_vhtcaps, IEEE80211_VHTCAP_EXT_NSS_BW_MASK); supp_chwidth = u32_get_bits(ni->ni_vhtcaps, IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK); ccfs0 = ni->ni_vht_chan1; ccfs1 = ni->ni_vht_chan2; ccfs2 = (le16toh(ni->ni_htop1) & IEEE80211_HT_OP_MODE_CCFS2_MASK) >> IEEE80211_HT_OP_MODE_CCFS2_SHIFT; ccf0 = ccfs0; if ((ic->ic_caps & IEEE80211_C_SUPPORTS_VHT_EXT_NSS_BW) == 0) ext_nss_bw_supp = 0; /* * Cf. IEEE 802.11 Table 9-250 * * We really just consider that because it's inefficient to connect * at a higher bandwidth than we'll actually be able to use. */ switch ((supp_chwidth << 4) | ext_nss_bw_supp) { default: case 0x00: ccf1 = 0; support_160 = false; support_80_80 = false; break; case 0x01: support_80_80 = false; case 0x02: case 0x03: ccf1 = ccfs2; break; case 0x10: ccf1 = ccfs1; break; case 0x11: case 0x12: if (!ccfs1) ccf1 = ccfs2; else ccf1 = ccfs1; break; case 0x13: case 0x20: case 0x23: ccf1 = ccfs1; break; } cf0 = ieee80211_ieee2mhz(ccf0, ni->ni_chan->ic_flags); cf1 = ieee80211_ieee2mhz(ccf1, ni->ni_chan->ic_flags); switch (ni->ni_vht_chanwidth) { case IEEE80211_VHT_CHANWIDTH_80P80MHZ: ni->ni_chw = IEEE80211_CHAN_WIDTH_80P80; ni->ni_chan->ic_center_freq1 = cf0; ni->ni_chan->ic_center_freq2 = cf1; break; case IEEE80211_VHT_CHANWIDTH_160MHZ: ni->ni_chw = IEEE80211_CHAN_WIDTH_160; ni->ni_chan->ic_center_freq1 = cf0; break; case IEEE80211_VHT_CHANWIDTH_80MHZ: ni->ni_chw = IEEE80211_CHAN_WIDTH_80; ni->ni_chan->ic_center_freq1 = cf0; /* If needed, adjust based on the newer interop workaround. */ if (ccf1) { unsigned int diff = abs(ccf1 - ccf0); if ((diff == 8) && support_160) { ni->ni_chw = IEEE80211_CHAN_WIDTH_160; ni->ni_chan->ic_center_freq1 = cf1; } else if ((diff > 8) && support_80_80) { ni->ni_chw = IEEE80211_CHAN_WIDTH_80P80; ni->ni_chan->ic_center_freq2 = cf1; } } break; case IEEE80211_VHT_CHANWIDTH_USE_HT: /* Use HT negotiate information */ break; default: return; } ni->ni_flags |= IEEE80211_NODE_VHT; if (ieee80211_node_supports_vht_sgi80(ni)) ni->ni_flags |= IEEE80211_NODE_VHT_SGI80; if (ieee80211_node_supports_vht_sgi160(ni)) ni->ni_flags |= IEEE80211_NODE_VHT_SGI160; XYLog("%s chan_width=%s support_160=%d support_80_80=%d\n", __FUNCTION__, ieee80211_chan_width_name[ni->ni_chw], support_160, support_80_80); } void ieee80211_he_negotiate(struct ieee80211com *ic, struct ieee80211_node *ni) { XYLog("%s\n", __FUNCTION__); uint8_t ext_nss_bw_supp, supp_chwidth; uint16_t cf0, cf1; int ccfs0, ccfs1, ccfs2; int ccf0, ccf1; bool support_80_80 = false; bool support_160 = false; struct ieee80211_vht_operation *he_oper_vht = (struct ieee80211_vht_operation *)ni->ni_he_optional; ni->ni_flags &= ~IEEE80211_NODE_HE; /* Check if we support HE. */ if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11AX)) == 0) return; /* Check if HE support has been explicitly disabled. */ if ((ic->ic_flags & IEEE80211_F_HEON) == 0) return; ni->ni_flags |= IEEE80211_NODE_HE; if (!(htole32(ni->ni_he_oper_params) & IEEE80211_HE_OPERATION_VHT_OPER_INFO)) return; support_160 = (ni->ni_vhtcaps & (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK | IEEE80211_VHTCAP_EXT_NSS_BW_MASK)); support_80_80 = ((ni->ni_vhtcaps & IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160_80P80MHZ) || (ni->ni_vhtcaps & IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ && ni->ni_vhtcaps & IEEE80211_VHTCAP_EXT_NSS_BW_MASK) || ((ni->ni_vhtcaps & IEEE80211_VHTCAP_EXT_NSS_BW_MASK) >> IEEE80211_VHTCAP_EXT_NSS_BW_SHIFT > 1)); ext_nss_bw_supp = u32_get_bits(ni->ni_vhtcaps, IEEE80211_VHTCAP_EXT_NSS_BW_MASK); supp_chwidth = u32_get_bits(ni->ni_vhtcaps, IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK); ccfs0 = he_oper_vht->center_freq_seg0_idx; ccfs1 = he_oper_vht->center_freq_seg1_idx; ccfs2 = (le16toh(ni->ni_htop1) & IEEE80211_HT_OP_MODE_CCFS2_MASK) >> IEEE80211_HT_OP_MODE_CCFS2_SHIFT; ccf0 = ccfs0; if ((ic->ic_caps & IEEE80211_C_SUPPORTS_VHT_EXT_NSS_BW) == 0) ext_nss_bw_supp = 0; /* * Cf. IEEE 802.11 Table 9-250 * * We really just consider that because it's inefficient to connect * at a higher bandwidth than we'll actually be able to use. */ switch ((supp_chwidth << 4) | ext_nss_bw_supp) { default: case 0x00: ccf1 = 0; support_160 = false; support_80_80 = false; break; case 0x01: support_80_80 = false; case 0x02: case 0x03: ccf1 = ccfs2; break; case 0x10: ccf1 = ccfs1; break; case 0x11: case 0x12: if (!ccfs1) ccf1 = ccfs2; else ccf1 = ccfs1; break; case 0x13: case 0x20: case 0x23: ccf1 = ccfs1; break; } cf0 = ieee80211_ieee2mhz(ccf0, ni->ni_chan->ic_flags); cf1 = ieee80211_ieee2mhz(ccf1, ni->ni_chan->ic_flags); switch (he_oper_vht->chan_width) { case IEEE80211_VHT_CHANWIDTH_80P80MHZ: ni->ni_chw = IEEE80211_CHAN_WIDTH_80P80; ni->ni_chan->ic_center_freq1 = cf0; ni->ni_chan->ic_center_freq2 = cf1; break; case IEEE80211_VHT_CHANWIDTH_160MHZ: ni->ni_chw = IEEE80211_CHAN_WIDTH_160; ni->ni_chan->ic_center_freq1 = cf0; break; case IEEE80211_VHT_CHANWIDTH_80MHZ: ni->ni_chw = IEEE80211_CHAN_WIDTH_80; ni->ni_chan->ic_center_freq1 = cf0; /* If needed, adjust based on the newer interop workaround. */ if (ccf1) { unsigned int diff = abs(ccf1 - ccf0); if ((diff == 8) && support_160) { ni->ni_chw = IEEE80211_CHAN_WIDTH_160; ni->ni_chan->ic_center_freq1 = cf1; } else if ((diff > 8) && support_80_80) { ni->ni_chw = IEEE80211_CHAN_WIDTH_80P80; ni->ni_chan->ic_center_freq2 = cf1; } } break; case IEEE80211_VHT_CHANWIDTH_USE_HT: /* Use HT negotiate information */ break; default: return; } XYLog("%s chan_width=%s\n", __FUNCTION__, ieee80211_chan_width_name[ni->ni_chw]); } void ieee80211_sta_set_rx_nss(struct ieee80211com *ic, struct ieee80211_node *ni) { uint8_t ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, rx_nss; bool support_160; if (ni->ni_flags & IEEE80211_NODE_HE) { int i; uint8_t rx_mcs_80 = 0, rx_mcs_160 = 0; uint16_t mcs_160_map = le16toh(ni->ni_he_mcs_nss_supp.rx_mcs_160); uint16_t mcs_80_map = le16toh(ni->ni_he_mcs_nss_supp.rx_mcs_80); for (i = 7; i >= 0; i--) { uint8_t mcs_160 = (mcs_160_map >> (2 * i)) & 3; if (mcs_160 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { rx_mcs_160 = i + 1; break; } } for (i = 7; i >= 0; i--) { uint8_t mcs_80 = (mcs_80_map >> (2 * i)) & 3; if (mcs_80 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { rx_mcs_80 = i + 1; break; } } support_160 = ni->ni_he_cap_elem.phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; if (support_160) he_rx_nss = min(rx_mcs_80, rx_mcs_160); else he_rx_nss = rx_mcs_80; } if (ni->ni_flags & IEEE80211_NODE_HT) { if (ni->ni_rxmcs[0]) ht_rx_nss++; if (ni->ni_rxmcs[1]) ht_rx_nss++; if (ni->ni_rxmcs[2]) ht_rx_nss++; if (ni->ni_rxmcs[3]) ht_rx_nss++; /* FIXME: consider rx_highest? */ } if (ni->ni_flags & IEEE80211_NODE_VHT) { int i; uint16_t rx_mcs_map; rx_mcs_map = le16toh(ni->ni_vht_mcsinfo.rx_mcs_map); for (i = 7; i >= 0; i--) { uint8_t mcs = (rx_mcs_map >> (2 * i)) & 3; if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) { vht_rx_nss = i + 1; break; } } /* FIXME: consider rx_highest? */ } rx_nss = max(vht_rx_nss, ht_rx_nss); rx_nss = max(he_rx_nss, rx_nss); ni->ni_rx_nss = max_t(u8, 1, rx_nss); XYLog("%s ni_rx_nss: %d\n", __FUNCTION__, ni->ni_rx_nss); } void ieee80211_tx_ba_timeout(void *arg) { struct ieee80211_tx_ba *ba = (struct ieee80211_tx_ba *)arg; struct ieee80211_node *ni = ba->ba_ni; struct ieee80211com *ic = ni->ni_ic; u_int8_t tid; int s; s = splnet(); tid = ((caddr_t)ba - (caddr_t)ni->ni_tx_ba) / sizeof(*ba); if (ba->ba_state == IEEE80211_BA_REQUESTED) { /* MLME-ADDBA.confirm(TIMEOUT) */ ba->ba_state = IEEE80211_BA_INIT; if (ni->ni_addba_req_intval[tid] < IEEE80211_ADDBA_REQ_INTVAL_MAX) ni->ni_addba_req_intval[tid]++; /* * In case the peer believes there is an existing * block ack agreement with us, try to delete it. */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, IEEE80211_ACTION_DELBA, IEEE80211_REASON_SETUP_REQUIRED << 16 | 1 << 8 | tid); } else if (ba->ba_state == IEEE80211_BA_AGREED) { /* Block Ack inactivity timeout */ ic->ic_stats.is_ht_tx_ba_timeout++; ieee80211_delba_request(ic, ni, IEEE80211_REASON_TIMEOUT, 1, tid); } splx(s); } void ieee80211_rx_ba_timeout(void *arg) { struct ieee80211_rx_ba *ba = (struct ieee80211_rx_ba *)arg; struct ieee80211_node *ni = ba->ba_ni; struct ieee80211com *ic = ni->ni_ic; u_int8_t tid; int s; ic->ic_stats.is_ht_rx_ba_timeout++; s = splnet(); /* Block Ack inactivity timeout */ tid = ((caddr_t)ba - (caddr_t)ni->ni_rx_ba) / sizeof(*ba); ieee80211_delba_request(ic, ni, IEEE80211_REASON_TIMEOUT, 0, tid); splx(s); } /* * Request initiation of Block Ack with the specified peer. */ int ieee80211_addba_request(struct ieee80211com *ic, struct ieee80211_node *ni, u_int16_t ssn, u_int8_t tid) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; if (ba->ba_state != IEEE80211_BA_INIT) return EBUSY; /* MLME-ADDBA.request */ /* setup Block Ack */ ba->ba_ni = ni; ba->ba_state = IEEE80211_BA_REQUESTED; ba->ba_token = ic->ic_dialog_token++; ba->ba_timeout_val = 0; timeout_set(&ba->ba_to, ieee80211_tx_ba_timeout, ba); ba->ba_winsize = IEEE80211_BA_MAX_WINSZ; ba->ba_winstart = ssn; ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; ba->ba_params = (ba->ba_winsize << IEEE80211_ADDBA_BUFSZ_SHIFT) | (tid << IEEE80211_ADDBA_TID_SHIFT); if (ic->ic_caps & IEEE80211_C_AMSDU_IN_AMPDU) { ba->ba_params |= IEEE80211_ADDBA_AMSDU; } if ((ic->ic_htcaps & IEEE80211_HTCAP_DELAYEDBA) == 0) /* immediate BA */ ba->ba_params |= IEEE80211_ADDBA_BA_POLICY; if ((ic->ic_caps & IEEE80211_C_TX_AMPDU_SETUP_IN_HW) && ic->ic_ampdu_tx_start != NULL) { int err = ic->ic_ampdu_tx_start(ic, ni, tid); if (err && err != EBUSY) { /* driver failed to setup, rollback */ ieee80211_addba_resp_refuse(ic, ni, tid, IEEE80211_STATUS_UNSPECIFIED); } else if (err == 0) ieee80211_addba_resp_accept(ic, ni, tid); return err; /* The device will send an ADDBA frame. */ } timeout_add_sec(&ba->ba_to, 1); /* dot11ADDBAResponseTimeout */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, IEEE80211_ACTION_ADDBA_REQ, tid); return 0; } /* * Request the deletion of Block Ack with a peer and notify driver. */ void ieee80211_delba_request(struct ieee80211com *ic, struct ieee80211_node *ni, u_int16_t reason, u_int8_t dir, u_int8_t tid) { /* MLME-DELBA.request */ if (reason) { /* transmit a DELBA frame */ IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA, IEEE80211_ACTION_DELBA, reason << 16 | dir << 8 | tid); } if (dir) { /* MLME-DELBA.confirm(Originator) */ struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; if (ic->ic_ampdu_tx_stop != NULL) ic->ic_ampdu_tx_stop(ic, ni, tid); ba->ba_state = IEEE80211_BA_INIT; /* stop Block Ack inactivity timer */ timeout_del(&ba->ba_to); } else { /* MLME-DELBA.confirm(Recipient) */ struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; int i; if (ic->ic_ampdu_rx_stop != NULL) ic->ic_ampdu_rx_stop(ic, ni, tid); ba->ba_state = IEEE80211_BA_INIT; /* stop Block Ack inactivity timer */ timeout_del(&ba->ba_to); timeout_del(&ba->ba_gap_to); if (ba->ba_buf != NULL) { /* free all MSDUs stored in reordering buffer */ for (i = 0; i < IEEE80211_BA_MAX_WINSZ; i++) mbuf_freem(ba->ba_buf[i].m); /* free reordering buffer */ free(ba->ba_buf); ba->ba_buf = NULL; } } } #ifndef IEEE80211_STA_ONLY void ieee80211_auth_open_confirm(struct ieee80211com *ic, struct ieee80211_node *ni, uint16_t seq) { struct _ifnet *ifp = &ic->ic_if; IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, seq + 1); if (ifp->if_flags & IFF_DEBUG) XYLog("%s: station %s %s authenticated (open)\n", ifp->if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr), ni->ni_state != IEEE80211_STA_CACHE ? "newly" : "already"); ieee80211_node_newstate(ni, IEEE80211_STA_AUTH); } #endif void ieee80211_try_another_bss(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct ieee80211_node *curbs, *selbs; struct _ifnet *ifp = &ic->ic_if; /* Don't select our current AP again. */ curbs = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); if (curbs) { curbs->ni_fails++; ieee80211_node_newstate(curbs, IEEE80211_STA_CACHE); } /* Try a different AP from the same ESS if available. */ if (ic->ic_caps & IEEE80211_C_SCANALLBAND) { /* * Make sure we will consider APs on all bands during * access point selection in ieee80211_node_choose_bss(). * During multi-band scans, our previous AP may be trying * to steer us onto another band by denying authentication. */ ieee80211_setmode(ic, IEEE80211_MODE_AUTO); } selbs = ieee80211_node_choose_bss(ic, 0, NULL); if (selbs == NULL) return; /* Should not happen but seriously, don't try the same AP again. */ if (memcmp(selbs->ni_macaddr, ic->ic_bss->ni_macaddr, IEEE80211_NWID_LEN) == 0) return; if (ifp->if_flags & IFF_DEBUG) XYLog("%s: trying AP %s on channel %d instead\n", ifp->if_xname, ether_sprintf(selbs->ni_macaddr), ieee80211_chan2ieee(ic, selbs->ni_chan)); /* Triggers an AUTH->AUTH transition, avoiding another SCAN. */ ieee80211_node_join_bss(ic, selbs); } void ieee80211_auth_open(struct ieee80211com *ic, const struct ieee80211_frame *wh, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi, u_int16_t seq, u_int16_t status) { XYLog("%s\n", __FUNCTION__); struct _ifnet *ifp = &ic->ic_if; switch (ic->ic_opmode) { #ifndef IEEE80211_STA_ONLY case IEEE80211_M_IBSS: if (ic->ic_state != IEEE80211_S_RUN || seq != IEEE80211_AUTH_OPEN_REQUEST) { DPRINTF(("discard auth from %s; state %u, seq %u\n", ether_sprintf((u_int8_t *)wh->i_addr2), ic->ic_state, seq)); ic->ic_stats.is_rx_bad_auth++; return; } ieee80211_new_state(ic, IEEE80211_S_AUTH, wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); /* In IBSS mode no (re)association frames are sent. */ if (ic->ic_flags & IEEE80211_F_RSNON) ni->ni_rsn_supp_state = RSNA_SUPP_PTKSTART; break; case IEEE80211_M_AHDEMO: /* should not come here */ break; case IEEE80211_M_HOSTAP: if (ic->ic_state != IEEE80211_S_RUN || seq != IEEE80211_AUTH_OPEN_REQUEST) { DPRINTF(("discard auth from %s; state %u, seq %u\n", ether_sprintf((u_int8_t *)wh->i_addr2), ic->ic_state, seq)); ic->ic_stats.is_rx_bad_auth++; return; } if (ni == ic->ic_bss) { ni = ieee80211_find_node(ic, wh->i_addr2); if (ni == NULL) ni = ieee80211_alloc_node(ic, wh->i_addr2); if (ni == NULL) { return; } IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid); ni->ni_rssi = rxi->rxi_rssi; ni->ni_rstamp = rxi->rxi_tstamp; ni->ni_chan = ic->ic_bss->ni_chan; } /* * Drivers may want to set up state before confirming. * In which case this returns EBUSY and the driver will * later call ieee80211_auth_open_confirm() by itself. */ if (ic->ic_newauth && ic->ic_newauth(ic, ni, ni->ni_state != IEEE80211_STA_CACHE, seq) != 0) break; ieee80211_auth_open_confirm(ic, ni, seq); break; #endif /* IEEE80211_STA_ONLY */ case IEEE80211_M_STA: if (ic->ic_state != IEEE80211_S_AUTH || seq != IEEE80211_AUTH_OPEN_RESPONSE) { ic->ic_stats.is_rx_bad_auth++; DPRINTF(("discard auth from %s; state %u, seq %u\n", ether_sprintf((u_int8_t *)wh->i_addr2), ic->ic_state, seq)); return; } if (ic->ic_flags & IEEE80211_F_RSNON) { /* XXX not here! */ ic->ic_bss->ni_flags &= ~IEEE80211_NODE_TXRXPROT; ic->ic_bss->ni_port_valid = 0; ic->ic_bss->ni_replaycnt_ok = 0; (*ic->ic_delete_key)(ic, ic->ic_bss, &ic->ic_bss->ni_pairwise_key); } if (status != 0) { if (ifp->if_flags & IFF_DEBUG) XYLog("%s: open authentication failed " "(status %d) for %s\n", ifp->if_xname, status, ether_sprintf((u_int8_t *)wh->i_addr3)); if (ni != ic->ic_bss) ni->ni_fails++; else ieee80211_try_another_bss(ic); ic->ic_stats.is_rx_auth_fail++; return; } ieee80211_new_state(ic, IEEE80211_S_ASSOC, wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); break; default: break; } } void ieee80211_set_beacon_miss_threshold(struct ieee80211com *ic) { struct _ifnet *ifp = &ic->ic_if; /* * Scale the missed beacon counter threshold to the AP's actual * beacon interval. */ int btimeout = MIN(IEEE80211_BEACON_MISS_THRES * ic->ic_bss->ni_intval, IEEE80211_BEACON_MISS_THRES * (IEEE80211_DUR_TU / 10)); /* Ensure that at least one beacon may be missed. */ btimeout = MAX(btimeout, 2 * ic->ic_bss->ni_intval); if (ic->ic_bss->ni_intval > 0) /* don't crash if interval is bogus */ ic->ic_bmissthres = btimeout / ic->ic_bss->ni_intval; if (ifp->if_flags & IFF_DEBUG) XYLog("%s: missed beacon threshold set to %d beacons, " "beacon interval is %u TU\n", ifp->if_xname, ic->ic_bmissthres, ic->ic_bss->ni_intval); } /* Tell our peer, and the driver, to stop A-MPDU Tx for all TIDs. */ void ieee80211_stop_ampdu_tx(struct ieee80211com *ic, struct ieee80211_node *ni, int mgt) { int tid; for (tid = 0; tid < nitems(ni->ni_tx_ba); tid++) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; if (ba->ba_state != IEEE80211_BA_AGREED) continue; ieee80211_delba_request(ic, ni, ((ic->ic_caps & IEEE80211_C_TX_AMPDU_SETUP_IN_HW) || mgt == -1) ? 0 : IEEE80211_REASON_AUTH_LEAVE, 1, tid); } } void ieee80211_check_wpa_supplicant_failure(struct ieee80211com *ic, struct ieee80211_node *ni) { struct ieee80211_node *ni2; if (ic->ic_opmode != IEEE80211_M_STA #ifndef IEEE80211_STA_ONLY && ic->ic_opmode != IEEE80211_M_IBSS #endif ) return; if (ni->ni_rsn_supp_state != RSNA_SUPP_PTKNEGOTIATING) return; ni->ni_assoc_fail |= IEEE80211_NODE_ASSOCFAIL_WPA_KEY; if (ni != ic->ic_bss) return; /* Also update the copy of our AP's node in the node cache. */ ni2 = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); if (ni2) ni2->ni_assoc_fail |= ic->ic_bss->ni_assoc_fail; } int ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt) { struct _ifnet *ifp = &ic->ic_if; struct ieee80211_node *ni; enum ieee80211_state ostate; u_int rate; #ifndef IEEE80211_STA_ONLY int s; #endif ostate = ic->ic_state; if (ifp->if_flags & IFF_DEBUG) XYLog("%s: %s -> %s\n", ifp->if_xname, ieee80211_state_name[ostate], ieee80211_state_name[nstate]); ic->ic_state = nstate; /* state transition */ ni = ic->ic_bss; /* NB: no reference held */ ieee80211_set_link_state(ic, LINK_STATE_DOWN); ic->ic_xflags &= ~IEEE80211_F_TX_MGMT_ONLY; switch (nstate) { case IEEE80211_S_INIT: /* * If mgt = -1, driver is already partway down, so do * not send management frames. */ switch (ostate) { case IEEE80211_S_INIT: break; case IEEE80211_S_RUN: if (mgt == -1) goto justcleanup; ieee80211_stop_ampdu_tx(ic, ni, mgt); ieee80211_ba_del(ni); switch (ic->ic_opmode) { case IEEE80211_M_STA: IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_ASSOC_LEAVE); break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_HOSTAP: s = splnet(); RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) { if (ni->ni_state != IEEE80211_STA_ASSOC) continue; IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, IEEE80211_REASON_ASSOC_LEAVE); } splx(s); break; #endif default: break; } /* FALLTHROUGH */ case IEEE80211_S_ASSOC: if (mgt == -1) goto justcleanup; switch (ic->ic_opmode) { case IEEE80211_M_STA: IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_HOSTAP: s = splnet(); RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); } splx(s); break; #endif default: break; } /* FALLTHROUGH */ case IEEE80211_S_AUTH: case IEEE80211_S_SCAN: justcleanup: #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) timeout_del(&ic->ic_rsn_timeout); #endif ieee80211_ba_del(ni); timeout_del(&ic->ic_bgscan_timeout); ic->ic_bgscan_fail = 0; ic->ic_mgt_timer = 0; mq_purge(&ic->ic_mgtq); mq_purge(&ic->ic_pwrsaveq); ieee80211_free_allnodes(ic, 1); break; } ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; ni->ni_assoc_fail = 0; if (ic->ic_flags & IEEE80211_F_RSNON) ieee80211_crypto_clear_groupkeys(ic); break; case IEEE80211_S_SCAN: ic->ic_flags &= ~IEEE80211_F_SIBSS; /* initialize bss for probe request */ IEEE80211_ADDR_COPY(ni->ni_macaddr, etherbroadcastaddr); IEEE80211_ADDR_COPY(ni->ni_bssid, etherbroadcastaddr); ni->ni_rates = ic->ic_sup_rates[ ieee80211_chan2mode(ic, ni->ni_chan)]; ni->ni_associd = 0; ni->ni_rstamp = 0; ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; if (ic->ic_flags & IEEE80211_F_RSNON) ieee80211_crypto_clear_groupkeys(ic); switch (ostate) { case IEEE80211_S_INIT: #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP && ic->ic_des_chan != IEEE80211_CHAN_ANYC) { /* * AP operation and we already have a channel; * bypass the scan and startup immediately. */ ieee80211_create_ibss(ic, ic->ic_des_chan); } else #endif ieee80211_begin_scan(ifp); break; case IEEE80211_S_SCAN: /* scan next */ if (ic->ic_flags & IEEE80211_F_ASCAN) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); } break; case IEEE80211_S_RUN: /* beacon miss */ if (ifp->if_flags & IFF_DEBUG) { /* XXX bssid clobbered above */ XYLog("%s: no recent beacons from %s;" " rescanning\n", ifp->if_xname, ether_sprintf(ic->ic_bss->ni_bssid)); } timeout_del(&ic->ic_bgscan_timeout); ic->ic_bgscan_fail = 0; ieee80211_stop_ampdu_tx(ic, ni, mgt); ieee80211_free_allnodes(ic, 1); /* FALLTHROUGH */ case IEEE80211_S_AUTH: case IEEE80211_S_ASSOC: /* timeout restart scan */ ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); if (ni != NULL) ni->ni_fails++; ieee80211_begin_scan(ifp); break; } break; case IEEE80211_S_AUTH: ieee80211_clean_sta_bss_node(ic); if (ostate == IEEE80211_S_RUN) ieee80211_check_wpa_supplicant_failure(ic, ni); ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; if (ic->ic_flags & IEEE80211_F_RSNON) ieee80211_crypto_clear_groupkeys(ic); switch (ostate) { case IEEE80211_S_INIT: if (ifp->if_flags & IFF_DEBUG) XYLog("%s: invalid transition %s -> %s\n", ifp->if_xname, ieee80211_state_name[ostate], ieee80211_state_name[nstate]); break; case IEEE80211_S_SCAN: IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, 1); break; case IEEE80211_S_AUTH: case IEEE80211_S_ASSOC: switch (mgt) { case IEEE80211_FC0_SUBTYPE_AUTH: if (ic->ic_opmode == IEEE80211_M_STA) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, IEEE80211_AUTH_OPEN_REQUEST); } break; case IEEE80211_FC0_SUBTYPE_DEAUTH: /* ignore and retry scan on timeout */ break; } break; case IEEE80211_S_RUN: timeout_del(&ic->ic_bgscan_timeout); ic->ic_bgscan_fail = 0; ieee80211_stop_ampdu_tx(ic, ni, mgt); ieee80211_ba_del(ni); switch (mgt) { case IEEE80211_FC0_SUBTYPE_AUTH: IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, 2); ic->ic_state = ostate; /* stay RUN */ break; case IEEE80211_FC0_SUBTYPE_DEAUTH: /* try to reauth */ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, 1); break; } break; } break; case IEEE80211_S_ASSOC: switch (ostate) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: case IEEE80211_S_ASSOC: if (ifp->if_flags & IFF_DEBUG) XYLog("%s: invalid transition %s -> %s\n", ifp->if_xname, ieee80211_state_name[ostate], ieee80211_state_name[nstate]); break; case IEEE80211_S_AUTH: IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); break; case IEEE80211_S_RUN: ieee80211_stop_ampdu_tx(ic, ni, mgt); ieee80211_ba_del(ni); IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); break; } break; case IEEE80211_S_RUN: switch (ostate) { case IEEE80211_S_INIT: if (ic->ic_opmode == IEEE80211_M_MONITOR) break; case IEEE80211_S_AUTH: case IEEE80211_S_RUN: if (ifp->if_flags & IFF_DEBUG) XYLog("%s: invalid transition %s -> %s\n", ifp->if_xname, ieee80211_state_name[ostate], ieee80211_state_name[nstate]); break; case IEEE80211_S_SCAN: /* adhoc/hostap mode */ case IEEE80211_S_ASSOC: /* infra mode */ if (ni->ni_txrate >= ni->ni_rates.rs_nrates) panic("%s: bogus xmit rate %u setup", __FUNCTION__, ni->ni_txrate); if (ifp->if_flags & IFF_DEBUG) { XYLog("%s: %s with %s ssid ", ifp->if_xname, ic->ic_opmode == IEEE80211_M_STA ? "associated" : "synchronized", ether_sprintf(ni->ni_bssid)); ieee80211_print_essid(ic->ic_bss->ni_essid, ni->ni_esslen); rate = ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL; XYLog(" channel %d", ieee80211_chan2ieee(ic, ni->ni_chan)); if (ni->ni_flags & IEEE80211_NODE_HT) XYLog(" start MCS %u", ni->ni_txmcs); else XYLog(" start %u%sMb", rate / 2, (rate & 1) ? ".5" : ""); XYLog(" %s preamble %s slot time%s%s%s%s\n", (ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? "short" : "long", (ic->ic_flags & IEEE80211_F_SHSLOT) ? "short" : "long", (ic->ic_flags & IEEE80211_F_USEPROT) ? " protection enabled" : "", (ni->ni_flags & IEEE80211_NODE_HT) ? " HT enabled" : "", (ni->ni_flags & IEEE80211_NODE_VHT) ? " VHT enabled" : "", (ni->ni_flags & IEEE80211_NODE_HE) ? " HE enabled" : ""); } #ifdef USE_APPLE_SUPPLICANT { #elif (defined IO80211FAMILY_V2) if (ieee80211_is_8021x_akm((enum ieee80211_akm)ni->ni_rsnakms) || !(ic->ic_flags & IEEE80211_F_RSNON)) { #else if (!(ic->ic_flags & IEEE80211_F_RSNON)) { #endif /* * NB: When RSN is enabled, we defer setting * the link up until the port is valid. */ ieee80211_set_link_state(ic, LINK_STATE_UP); ni->ni_assoc_fail = 0; } ni->ni_fails = 0; ni = ieee80211_find_node(ic, ni->ni_macaddr); if (ni) ni->ni_fails = 0; ic->ic_mgt_timer = 0; ieee80211_set_beacon_miss_threshold(ic); (*ifp->if_start)(ifp); break; } break; } return 0; } void ieee80211_set_link_state(struct ieee80211com *ic, int nstate) { struct _ifnet *ifp = &ic->ic_if; int link_state; switch (ic->ic_opmode) { #ifndef IEEE80211_STA_ONLY case IEEE80211_M_IBSS: case IEEE80211_M_HOSTAP: nstate = LINK_STATE_UNKNOWN; break; #endif case IEEE80211_M_MONITOR: nstate = LINK_STATE_DOWN; break; default: break; } link_state = nstate; if (link_state != ifp->if_link_state) { ifp->if_link_state = link_state; if (link_state == LINK_STATE_UP) { XYLog("%s LINK_STATE_IS_UP\n", __FUNCTION__); ifp->controller->setLinkStatus(kIONetworkLinkValid | kIONetworkLinkActive, ifp->controller->getCurrentMedium()); } else { XYLog("%s LINK_STATE_IS_DOWN\n", __FUNCTION__); ifp->controller->setLinkStatus(kIONetworkLinkValid); } } // if (nstate != ifp->if_link_state) { // ifp->if_link_state = nstate; // if (LINK_STATE_IS_UP(nstate)) { // struct if_ieee80211_data ifie; // memset(&ifie, 0, sizeof(ifie)); // ifie.ifie_nwid_len = ic->ic_bss->ni_esslen; // memcpy(ifie.ifie_nwid, ic->ic_bss->ni_essid, // sizeof(ifie.ifie_nwid)); // memcpy(ifie.ifie_addr, ic->ic_bss->ni_bssid, // sizeof(ifie.ifie_addr)); // ifie.ifie_channel = ieee80211_chan2ieee(ic, // ic->ic_bss->ni_chan); // ifie.ifie_flags = ic->ic_flags; // ifie.ifie_xflags = ic->ic_xflags; // rtm_80211info(&ic->ic_if, &ifie); // } // if_link_state_change(ifp); // } } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_proto.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_proto.h,v 1.46 2019/09/12 12:55:07 stsp Exp $ */ /* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_proto.h,v 1.4 2003/08/19 22:17:03 sam Exp $ */ #ifndef _NET80211_IEEE80211_PROTO_H_ #define _NET80211_IEEE80211_PROTO_H_ /* * 802.11 protocol implementation definitions. */ enum ieee80211_state { IEEE80211_S_INIT = 0, /* default state */ IEEE80211_S_SCAN = 1, /* scanning */ IEEE80211_S_AUTH = 2, /* try to authenticate */ IEEE80211_S_ASSOC = 3, /* try to assoc */ IEEE80211_S_RUN = 4 /* associated */ }; #define IEEE80211_S_MAX (IEEE80211_S_RUN+1) #define IEEE80211_SEND_MGMT(_ic,_ni,_type,_arg) \ ((*(_ic)->ic_send_mgmt)(_ic, _ni, _type, _arg, 0)) /* shortcut */ #define IEEE80211_SEND_ACTION(_ic,_ni,_categ,_action,_arg) \ ((*(_ic)->ic_send_mgmt)(_ic, _ni, IEEE80211_FC0_SUBTYPE_ACTION, \ (_categ) << 16 | (_action), _arg)) extern const char * const ieee80211_mgt_subtype_name[]; extern const char * const ieee80211_state_name[IEEE80211_S_MAX]; extern const char * const ieee80211_phymode_name[]; extern void ieee80211_proto_attach(struct _ifnet *); extern void ieee80211_proto_detach(struct _ifnet *); struct ieee80211_node; struct ieee80211_rxinfo; struct ieee80211_rsnparams; extern void ieee80211_set_link_state(struct ieee80211com *, int); extern u_int ieee80211_get_hdrlen(const struct ieee80211_frame *); extern int ieee80211_classify(struct ieee80211com *, mbuf_t); extern void ieee80211_inputm(struct _ifnet *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *, struct mbuf_list *); extern void ieee80211_input(struct _ifnet *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *); extern int ieee80211_output(struct _ifnet *, mbuf_t, struct sockaddr *, struct rtentry *); extern void ieee80211_recv_mgmt(struct ieee80211com *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *, int); extern int ieee80211_send_mgmt(struct ieee80211com *, struct ieee80211_node *, int, int, int); extern void ieee80211_eapol_key_input(struct ieee80211com *, mbuf_t, struct ieee80211_node *); extern void ieee80211_tx_compressed_bar(struct ieee80211com *, struct ieee80211_node *, int, uint16_t); extern mbuf_t ieee80211_encap(struct _ifnet *, mbuf_t, struct ieee80211_node **); extern mbuf_t ieee80211_get_rts(struct ieee80211com *, const struct ieee80211_frame *, u_int16_t); extern mbuf_t ieee80211_get_cts_to_self(struct ieee80211com *, u_int16_t); extern mbuf_t ieee80211_get_compressed_bar(struct ieee80211com *, struct ieee80211_node *, int, uint16_t); extern mbuf_t ieee80211_beacon_alloc(struct ieee80211com *, struct ieee80211_node *); extern int ieee80211_save_ie(const u_int8_t *, u_int8_t **); extern int ieee80211_save_ie_tlv(const u_int8_t *, u_int8_t **, uint32_t *, uint32_t save_len); extern void ieee80211_eapol_timeout(void *); extern int ieee80211_send_4way_msg1(struct ieee80211com *, struct ieee80211_node *); extern int ieee80211_send_4way_msg2(struct ieee80211com *, struct ieee80211_node *, const u_int8_t *, const struct ieee80211_ptk *); extern int ieee80211_send_4way_msg3(struct ieee80211com *, struct ieee80211_node *); extern int ieee80211_send_4way_msg4(struct ieee80211com *, struct ieee80211_node *); extern int ieee80211_send_group_msg1(struct ieee80211com *, struct ieee80211_node *); extern int ieee80211_send_group_msg2(struct ieee80211com *, struct ieee80211_node *, const struct ieee80211_key *); extern int ieee80211_send_eapol_key_req(struct ieee80211com *, struct ieee80211_node *, u_int16_t, u_int64_t); extern int ieee80211_pwrsave(struct ieee80211com *, mbuf_t, struct ieee80211_node *); #define ieee80211_new_state(_ic, _nstate, _arg) \ do { \ XYLog("%s %d nstate=%d\n", __FUNCTION__, __LINE__, (_nstate)); \ (((_ic)->ic_newstate)((_ic), (_nstate), (_arg))); \ } while (0) extern enum ieee80211_edca_ac ieee80211_up_to_ac(struct ieee80211com *, int); extern u_int8_t *ieee80211_add_capinfo(u_int8_t *, struct ieee80211com *, const struct ieee80211_node *); extern u_int8_t *ieee80211_add_ssid(u_int8_t *, const u_int8_t *, u_int); extern u_int8_t *ieee80211_add_rates(u_int8_t *, const struct ieee80211_rateset *); extern u_int8_t *ieee80211_add_fh_params(u_int8_t *, struct ieee80211com *, const struct ieee80211_node *); extern u_int8_t *ieee80211_add_ds_params(u_int8_t *, struct ieee80211com *, const struct ieee80211_node *); extern u_int8_t *ieee80211_add_tim(u_int8_t *, struct ieee80211com *); extern u_int8_t *ieee80211_add_ibss_params(u_int8_t *, const struct ieee80211_node *); extern u_int8_t *ieee80211_add_edca_params(u_int8_t *, struct ieee80211com *); extern u_int8_t *ieee80211_add_erp(u_int8_t *, struct ieee80211com *); extern u_int8_t *ieee80211_add_qos_capability(u_int8_t *, struct ieee80211com *); extern u_int8_t *ieee80211_add_rsn(u_int8_t *, struct ieee80211com *, const struct ieee80211_node *); extern u_int8_t *ieee80211_add_wpa(u_int8_t *, struct ieee80211com *, const struct ieee80211_node *); extern u_int8_t *ieee80211_add_xrates(u_int8_t *, const struct ieee80211_rateset *); extern u_int8_t *ieee80211_add_htcaps(u_int8_t *, struct ieee80211com *); extern u_int8_t *ieee80211_add_htop(u_int8_t *, struct ieee80211com *); extern u_int8_t *ieee80211_add_tie(u_int8_t *, u_int8_t, u_int32_t); extern u_int8_t *ieee80211_add_vhtcaps(u_int8_t *, struct ieee80211com *); extern u_int8_t *ieee80211_add_hecaps(u_int8_t *, struct ieee80211com *); extern int ieee80211_parse_rsn(struct ieee80211com *, const u_int8_t *, struct ieee80211_rsnparams *); extern int ieee80211_parse_wpa(struct ieee80211com *, const u_int8_t *, struct ieee80211_rsnparams *); extern void ieee80211_print_essid(const u_int8_t *, int); #ifdef IEEE80211_DEBUG extern void ieee80211_dump_pkt(const u_int8_t *, int, int, int); #endif extern int ieee80211_ibss_merge(struct ieee80211com *, struct ieee80211_node *, u_int64_t); extern void ieee80211_reset_erp(struct ieee80211com *); extern void ieee80211_set_shortslottime(struct ieee80211com *, int); extern void ieee80211_auth_open_confirm(struct ieee80211com *, struct ieee80211_node *, uint16_t); extern void ieee80211_auth_open(struct ieee80211com *, const struct ieee80211_frame *, struct ieee80211_node *, struct ieee80211_rxinfo *rs, u_int16_t, u_int16_t); extern void ieee80211_stop_ampdu_tx(struct ieee80211com *, struct ieee80211_node *, int); extern void ieee80211_gtk_rekey_timeout(void *); extern int ieee80211_keyrun(struct ieee80211com *, u_int8_t *); extern void ieee80211_setkeys(struct ieee80211com *); extern void ieee80211_setkeysdone(struct ieee80211com *); extern void ieee80211_sa_query_timeout(void *); extern void ieee80211_sa_query_request(struct ieee80211com *, struct ieee80211_node *); extern void ieee80211_ht_negotiate_chw(struct ieee80211com *, struct ieee80211_node *); extern void ieee80211_ht_negotiate(struct ieee80211com *, struct ieee80211_node *); extern void ieee80211_vht_negotiate(struct ieee80211com *, struct ieee80211_node *); extern void ieee80211_he_negotiate(struct ieee80211com *, struct ieee80211_node *); extern void ieee80211_sta_set_rx_nss(struct ieee80211com *, struct ieee80211_node *); extern void ieee80211_tx_ba_timeout(void *); extern void ieee80211_rx_ba_timeout(void *); extern int ieee80211_addba_request(struct ieee80211com *, struct ieee80211_node *, u_int16_t, u_int8_t); extern void ieee80211_delba_request(struct ieee80211com *, struct ieee80211_node *, u_int16_t, u_int8_t, u_int8_t); extern void ieee80211_addba_req_accept(struct ieee80211com *, struct ieee80211_node *, uint8_t); extern void ieee80211_addba_req_refuse(struct ieee80211com *, struct ieee80211_node *, uint8_t); extern void ieee80211_addba_resp_accept(struct ieee80211com *, struct ieee80211_node *, uint8_t); extern void ieee80211_addba_resp_refuse(struct ieee80211com *, struct ieee80211_node *, uint8_t, uint16_t); extern void ieee80211_output_ba_move_window(struct ieee80211com *, struct ieee80211_node *, uint8_t, uint16_t); extern void ieee80211_output_ba_move_window_to_first_unacked( struct ieee80211com *, struct ieee80211_node *, uint8_t, uint16_t); extern void ieee80211_output_ba_record_ack(struct ieee80211com *, struct ieee80211_node *, uint8_t, uint16_t); #endif /* _NET80211_IEEE80211_PROTO_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_ra.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. */ /* * Copyright (c) 2021 Christian Ehrhardt * Copyright (c) 2016, 2021 Stefan Sperling * Copyright (c) 2016 Theo Buehler * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include int ieee80211_ra_next_intra_rate(struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *); const struct ieee80211_ra_rate * ieee80211_ra_next_rateset( struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *); int ieee80211_ra_best_mcs_in_rateset(struct ieee80211_ra_node *, const struct ieee80211_ra_rate *); void ieee80211_ra_probe_next_rateset(struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *, const struct ieee80211_ra_rate *); int ieee80211_ra_next_mcs(struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *); void ieee80211_ra_probe_done(struct ieee80211_ra_node *); int ieee80211_ra_intra_mode_ra_finished( struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *); void ieee80211_ra_trigger_next_rateset(struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *); int ieee80211_ra_inter_mode_ra_finished( struct ieee80211_ra_node *, struct ieee80211_node *); int ieee80211_ra_best_rate(struct ieee80211_ra_node *, struct ieee80211_node *); void ieee80211_ra_probe_next_rate(struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *); int ieee80211_ra_valid_tx_mcs(struct ieee80211_node *, int); uint32_t ieee80211_ra_valid_rates(struct ieee80211com *, struct ieee80211_node *); int ieee80211_ra_probe_valid(struct ieee80211_ra_goodput_stats *); /* We use fixed point arithmetic with 64 bit integers. */ #define RA_FP_SHIFT 21 #define RA_FP_INT(x) (x ## ULL << RA_FP_SHIFT) /* the integer x */ #define RA_FP_1 RA_FP_INT(1) /* Multiply two fixed point numbers. */ #define RA_FP_MUL(a, b) \ (((a) * (b)) >> RA_FP_SHIFT) /* Divide two fixed point numbers. */ #define RA_FP_DIV(a, b) \ (b == 0 ? (uint64_t)-1 : (((a) << RA_FP_SHIFT) / (b))) #ifdef RA_DEBUG #define DPRINTF(x) do { if (ra_debug > 0) printf x; } while (0) #define DPRINTFN(n, x) do { if (ra_debug >= (n)) printf x; } while (0) int ra_debug = 0; #else #define DPRINTF(x) do { ; } while (0) #define DPRINTFN(n, x) do { ; } while (0) #endif #ifdef RA_DEBUG void ra_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp) { uint64_t tmp; /* integer part */ *i = (fp >> RA_FP_SHIFT); /* fractional part */ tmp = (fp & ((uint64_t)-1 >> (64 - RA_FP_SHIFT))); tmp *= 100; *f = (uint32_t)(tmp >> RA_FP_SHIFT); } char * ra_fp_sprintf(uint64_t fp) { uint32_t i, f; static char buf[64]; int ret; ra_fixedp_split(&i, &f, fp); ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f); if (ret == -1 || ret >= sizeof(buf)) return "ERR"; return buf; } #endif /* RA_DEBUG */ static int is_ht(struct ieee80211_node *ni) { return (ni->ni_flags & IEEE80211_NODE_HT); } static int is_vht(struct ieee80211_node *ni) { return (ni->ni_flags & IEEE80211_NODE_VHT); } static int is_he(struct ieee80211_node *ni) { return (ni->ni_flags & IEEE80211_NODE_HE); } static int support_nss(struct ieee80211_node *ni) { uint32_t ntxstreams = 0; struct ieee80211com *ic = ni->ni_ic; int i; if ((ic->ic_tx_mcs_set & IEEE80211_TX_RX_MCS_NOT_EQUAL) == 0) { for (i = 0; i < 4; i++) { if ((is_vht(ni) || is_he(ni)) && ic->ic_vht_sup_mcs[i] == 0) { break; } else if (ic->ic_sup_mcs[i] == 0) { break; } ntxstreams++; if (ntxstreams >= ni->ni_rx_nss) break; } return ntxstreams; } return MIN(1 + ((ic->ic_tx_mcs_set & IEEE80211_TX_SPATIAL_STREAMS) >> 2), ni->ni_rx_nss); } static void build_rateset(struct ieee80211_ra_node *rn, enum ieee80211_phymode mode) { int i; struct ieee80211_ra_rate *ra_rate; const struct ieee80211_ht_rateset *ht_rate; const struct ieee80211_vht_rateset *vht_rate; const struct ieee80211_he_rateset *he_rate; rn->rs_phymode = mode; switch (rn->rs_phymode) { case IEEE80211_MODE_11N: rn->active_rs_count = IEEE80211_HT_NUM_RATESETS; for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) { ra_rate = &rn->active_rs[i]; ht_rate = &ieee80211_std_ratesets_11n[i]; ra_rate->band_width = (i >= IEEE80211_HT_RATESET_CBW40_SISO ? IEEE80211_CHAN_WIDTH_40 : IEEE80211_CHAN_WIDTH_20); ra_rate->max_mcs = ht_rate->max_mcs; ra_rate->min_mcs = ht_rate->min_mcs; ra_rate->nrates = ht_rate->nrates; ra_rate->sgi = ht_rate->sgi; ra_rate->nss = (ht_rate->max_mcs + 1) / 8; ra_rate->rs_index = i; memcpy(ra_rate->rates, ht_rate->rates, sizeof(ht_rate->rates)); } break; case IEEE80211_MODE_11AC: rn->active_rs_count = IEEE80211_VHT_NUM_RATESETS; for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) { ra_rate = &rn->active_rs[i]; vht_rate = &ieee80211_std_ratesets_11ac[i]; int bw = IEEE80211_CHAN_WIDTH_20; switch (i / 4) { case 0: bw = IEEE80211_CHAN_WIDTH_20; break; case 1: bw = IEEE80211_CHAN_WIDTH_40; break; case 2: bw = IEEE80211_CHAN_WIDTH_80; break; case 3: bw = IEEE80211_CHAN_WIDTH_160; break; default: break; } ra_rate->band_width = bw; ra_rate->max_mcs = vht_rate->nrates - 1; ra_rate->min_mcs = 0; ra_rate->nrates = vht_rate->nrates; ra_rate->sgi = vht_rate->sgi; ra_rate->nss = vht_rate->num_ss; ra_rate->rs_index = i; memcpy(ra_rate->rates, vht_rate->rates, sizeof(vht_rate->rates)); } break; case IEEE80211_MODE_11AX: rn->active_rs_count = IEEE80211_HT_NUM_RATESETS; for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) { ra_rate = &rn->active_rs[i]; he_rate = &ieee80211_std_ratesets_11ax[i]; int bw = IEEE80211_CHAN_WIDTH_20; switch (i / 2) { case 0: bw = IEEE80211_CHAN_WIDTH_20; break; case 1: bw = IEEE80211_CHAN_WIDTH_40; break; case 2: bw = IEEE80211_CHAN_WIDTH_80; break; case 3: bw = IEEE80211_CHAN_WIDTH_160; break; default: break; } ra_rate->band_width = bw; ra_rate->max_mcs = he_rate->nrates - 1; ra_rate->min_mcs = 0; ra_rate->sgi = 0; ra_rate->nss = ((i + 1) % 2) + 1; ra_rate->nrates = he_rate->nrates; ra_rate->rs_index = i; memcpy(ra_rate->rates, he_rate->rates, sizeof(he_rate->rates)); } break; default: XYLog("%s invalid mode=%d\n", __FUNCTION__, mode); break; } } const struct ieee80211_ra_rate * ieee80211_ra_get_rateset(struct ieee80211_ra_node *ra, struct ieee80211com *ic, struct ieee80211_node *ni, int mcs) { int i; int sup_nss = support_nss(ni); struct ieee80211_ra_rate *last_ra_rate = &ra->active_rs[ra->rs_index]; if (last_ra_rate->min_mcs <= mcs && mcs <= last_ra_rate->max_mcs) { return last_ra_rate; } int search_direction = mcs - last_ra_rate->max_mcs; for (i = ra->rs_index; (search_direction > 0 ? (i <= ra->active_rs_count - 1) : (i >= 0)); search_direction > 0 ? i++ : i--) { const struct ieee80211_ra_rate *ra_rate = &ra->active_rs[i]; if (ra_rate->sgi && !ieee80211_node_supports_sgi(ni)) continue; if (ra_rate->nss > sup_nss) continue; if (ra_rate->band_width > ni->ni_chw) continue; if (mcs >= ra_rate->min_mcs && mcs <= ra_rate->max_mcs) return ra_rate; } panic("%s mcs=%d rs_count=%d sgi=%d nss=%d bw=%d rate==NULL!!!!\n", __FUNCTION__, mcs, ra->active_rs_count, ra->sgi, ra->nss, ra->bw); } int ieee80211_ra_use_ht_sgi(struct ieee80211_node *ni) { if ((ni->ni_chw == IEEE80211_CHAN_WIDTH_40) && ieee80211_node_supports_ht_chan40(ni)) { if (ni->ni_flags & IEEE80211_NODE_HT_SGI40) return 1; } else if (ni->ni_flags & IEEE80211_NODE_HT_SGI20) return 1; return 0; } /* * Update goodput statistics. */ uint64_t ieee80211_ra_get_txrate(struct ieee80211_ra_node *ra, struct ieee80211com *ic, struct ieee80211_node *ni, int mcs) { const struct ieee80211_ra_rate *rs; uint64_t txrate; rs = ieee80211_ra_get_rateset(ra, ic, ni, mcs); txrate = rs->rates[mcs - rs->min_mcs]; txrate <<= RA_FP_SHIFT; /* convert to fixed-point */ txrate *= 500; /* convert to kbit/s */ txrate /= 1000; /* convert to mbit/s */ return txrate; } /* * Rate selection. */ /* A rate's goodput has to be at least this much larger to be "better". */ #define IEEE80211_RA_RATE_THRESHOLD (RA_FP_1 / 64) /* ~ 0.015 */ int ieee80211_ra_next_lower_intra_rate(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni) { const struct ieee80211_ra_rate *rs; int i, next; rs = ieee80211_ra_get_rateset(rn, ic, ni, ni->ni_txmcs); if (ni->ni_txmcs == rs->min_mcs) return rs->min_mcs; next = ni->ni_txmcs; for (i = rs->nrates - 1; i >= 0; i--) { if ((rn->valid_rates & (1 << (i + rs->min_mcs))) == 0) continue; if (i + rs->min_mcs < ni->ni_txmcs) { next = i + rs->min_mcs; break; } } return next; } int ieee80211_ra_next_intra_rate(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni) { const struct ieee80211_ra_rate *rs; int i, next; rs = ieee80211_ra_get_rateset(rn, ic, ni, ni->ni_txmcs); if (ni->ni_txmcs == rs->max_mcs) return rs->max_mcs; next = ni->ni_txmcs; for (i = 0; i < rs->nrates; i++) { if ((rn->valid_rates & (1 << (i + rs->min_mcs))) == 0) continue; if (i + rs->min_mcs > ni->ni_txmcs) { next = i + rs->min_mcs; break; } } return next; } const struct ieee80211_ra_rate * ieee80211_ra_next_rateset(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni) { const struct ieee80211_ra_rate *rs, *rsnext = NULL; int next = 0; bool found = false; rs = ieee80211_ra_get_rateset(rn, ic, ni, ni->ni_txmcs); if (rn->probing & IEEE80211_RA_PROBING_UP) { next = rs->rs_index; while (next < rn->active_rs_count - 1) { next++; rsnext = &rn->active_rs[next]; if (rsnext->band_width > ni->ni_chw) continue; if (rsnext->nss > support_nss(ni)) continue; found = true; break; } } else if (rn->probing & IEEE80211_RA_PROBING_DOWN) { next = rs->rs_index; while (next > 0) { next--; rsnext = &rn->active_rs[next]; if (rsnext->band_width > ni->ni_chw) continue; if (rsnext->nss > support_nss(ni)) continue; found = true; break; } } else panic("%s: invalid probing mode %d", __func__, rn->probing); if (found) { #ifdef RA_DEBUG DPRINTF(("%s rs befor_idx=%d after_idx=%d sgi=%d nss=%d sup_nss=%d bw=%d probing=%d\n", __FUNCTION__, rs->rs_index, rsnext->rs_index, rsnext->sgi, rsnext->nss, support_nss(ni), rsnext->band_width, rn->probing)); #endif return rsnext; } return NULL; // if ((rsnext->mcs_mask & rn->valid_rates) == 0) // return NULL; } int ieee80211_ra_best_mcs_in_rateset(struct ieee80211_ra_node *rn, const struct ieee80211_ra_rate *rs) { uint64_t gmax = 0; int i, best_mcs = rs->min_mcs; for (i = 0; i < rs->nrates; i++) { int mcs = rs->min_mcs + i; struct ieee80211_ra_goodput_stats *g = &rn->g[mcs]; if (((1 << mcs) & rn->valid_rates) == 0) continue; if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) { gmax = g->measured; best_mcs = mcs; } } return best_mcs; } void ieee80211_ra_probe_next_rateset(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni, const struct ieee80211_ra_rate *rsnext) { const struct ieee80211_ra_rate *rs; struct ieee80211_ra_goodput_stats *g; int best_mcs, i; /* Find most recently measured best MCS from the current rateset. */ rs = ieee80211_ra_get_rateset(rn, ic, ni, ni->ni_txmcs); best_mcs = ieee80211_ra_best_mcs_in_rateset(rn, rs); /* Switch to the next rateset. */ ni->ni_txmcs = rsnext->min_mcs; rn->bw = rsnext->band_width; rn->nss = rsnext->nss; rn->sgi = rsnext->sgi; rn->rs_index = rsnext->rs_index; if ((rn->valid_rates & (1 << rsnext->min_mcs)) == 0) ni->ni_txmcs = ieee80211_ra_next_intra_rate(rn, ic, ni); /* Select the lowest rate from the next rateset with loss-free * goodput close to the current best measurement. */ g = &rn->g[best_mcs]; for (i = 0; i < rsnext->nrates; i++) { int mcs = rsnext->min_mcs + i; uint64_t txrate = rsnext->rates[i]; if ((rn->valid_rates & (1 << mcs)) == 0) continue; txrate = txrate * 500; /* convert to kbit/s */ txrate <<= RA_FP_SHIFT; /* convert to fixed-point */ txrate /= 1000; /* convert to mbit/s */ if (txrate > g->measured + IEEE80211_RA_RATE_THRESHOLD) { ni->ni_txmcs = mcs; break; } } /* If all rates are lower the maximum rate is the closest match. */ if (i == rsnext->nrates) ni->ni_txmcs = rsnext->max_mcs; /* Add rates from the next rateset as candidates. */ rn->candidate_rates |= (1 << ni->ni_txmcs); if (rn->probing & IEEE80211_RA_PROBING_UP) { rn->candidate_rates |= (1 << ieee80211_ra_next_intra_rate(rn, ic, ni)); } else if (rn->probing & IEEE80211_RA_PROBING_DOWN) { rn->candidate_rates |= (1 << ieee80211_ra_next_lower_intra_rate(rn, ic, ni)); } else panic("%s: invalid probing mode %d", __func__, rn->probing); } int ieee80211_ra_next_mcs(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni) { int next; if (rn->probing & IEEE80211_RA_PROBING_DOWN) next = ieee80211_ra_next_lower_intra_rate(rn, ic, ni); else if (rn->probing & IEEE80211_RA_PROBING_UP) next = ieee80211_ra_next_intra_rate(rn, ic, ni); else panic("%s: invalid probing mode %d", __func__, rn->probing); return next; } void ieee80211_ra_probe_clear(struct ieee80211_ra_node *rn, struct ieee80211_node *ni) { struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs]; g->nprobe_pkts = 0; g->nprobe_fail = 0; } int ieee80211_ra_probe_valid(struct ieee80211_ra_goodput_stats *g) { /* 128 packets make up a valid probe in any case. */ if (g->nprobe_pkts >= 128) return 1; /* 8 packets with > 75% loss make a valid probe, too. */ if (g->nprobe_pkts >= 8 && g->nprobe_pkts - g->nprobe_fail < g->nprobe_pkts / 4) return 1; return 0; } void ieee80211_ra_probe_done(struct ieee80211_ra_node *rn) { rn->probing = IEEE80211_RA_NOT_PROBING; rn->probed_rates = 0; rn->valid_probes = 0; rn->candidate_rates = 0; } int ieee80211_ra_intra_mode_ra_finished(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni) { const struct ieee80211_ra_rate *rs; struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs]; int next_mcs, best_mcs; uint64_t next_rate; rn->probed_rates = (rn->probed_rates | (1 << ni->ni_txmcs)); /* Check if the min/max MCS in this rateset has been probed. */ rs = ieee80211_ra_get_rateset(rn, ic, ni, ni->ni_txmcs); if (rn->probing & IEEE80211_RA_PROBING_DOWN) { if (ni->ni_txmcs == rs->min_mcs || rn->probed_rates & (1 << rs->min_mcs)) { ieee80211_ra_trigger_next_rateset(rn, ic, ni); return 1; } } else if (rn->probing & IEEE80211_RA_PROBING_UP) { if (ni->ni_txmcs == rs->max_mcs || rn->probed_rates & (1 << rs->max_mcs)) { ieee80211_ra_trigger_next_rateset(rn, ic, ni); return 1; } } /* * Check if the measured goodput is loss-free and better than the * loss-free goodput of the candidate rate. */ next_mcs = ieee80211_ra_next_mcs(rn, ic, ni); if (next_mcs == ni->ni_txmcs) { ieee80211_ra_trigger_next_rateset(rn, ic, ni); return 1; } next_rate = ieee80211_ra_get_txrate(rn, ic, ni, next_mcs); if (g->loss == 0 && g->measured >= next_rate + IEEE80211_RA_RATE_THRESHOLD) { ieee80211_ra_trigger_next_rateset(rn, ic, ni); return 1; } /* Check if we had a better measurement at a previously probed MCS. */ best_mcs = ieee80211_ra_best_mcs_in_rateset(rn, rs); if (best_mcs != ni->ni_txmcs && (rn->probed_rates & (1 << best_mcs))) { if ((rn->probing & IEEE80211_RA_PROBING_UP) && best_mcs < ni->ni_txmcs) { ieee80211_ra_trigger_next_rateset(rn, ic, ni); return 1; } if ((rn->probing & IEEE80211_RA_PROBING_DOWN) && best_mcs > ni->ni_txmcs) { ieee80211_ra_trigger_next_rateset(rn, ic, ni); return 1; } } /* Check if all rates in the set of candidate rates have been probed. */ if ((rn->candidate_rates & rn->probed_rates) == rn->candidate_rates) { /* Remain in the current rateset until above checks trigger. */ rn->probing &= ~IEEE80211_RA_PROBING_INTER; return 1; } return 0; } void ieee80211_ra_trigger_next_rateset(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni) { const struct ieee80211_ra_rate *rsnext; rsnext = ieee80211_ra_next_rateset(rn, ic, ni); if (rsnext) { ieee80211_ra_probe_next_rateset(rn, ic, ni, rsnext); rn->probing |= IEEE80211_RA_PROBING_INTER; } else rn->probing &= ~IEEE80211_RA_PROBING_INTER; } int ieee80211_ra_inter_mode_ra_finished(struct ieee80211_ra_node *rn, struct ieee80211_node *ni) { return ((rn->probing & IEEE80211_RA_PROBING_INTER) == 0); } int ieee80211_ra_best_rate(struct ieee80211_ra_node *rn, struct ieee80211_node *ni) { int i, best = rn->best_mcs; uint64_t gmax = rn->g[rn->best_mcs].measured; for (i = 0; i < nitems(rn->g); i++) { struct ieee80211_ra_goodput_stats *g = &rn->g[i]; if (((1 << i) & rn->valid_rates) == 0) continue; if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) { gmax = g->measured; best = i; } } #ifdef RA_DEBUG if (rn->best_mcs != best) { DPRINTF(("MCS %d is best; MCS{cur|avg|loss}:", best)); for (i = 0; i < IEEE80211_HT_RATESET_NUM_MCS; i++) { struct ieee80211_ra_goodput_stats *g = &rn->g[i]; if ((rn->valid_rates & (1 << i)) == 0) continue; DPRINTF((" %d{%s|", i, ra_fp_sprintf(g->measured))); DPRINTF(("%s|", ra_fp_sprintf(g->average))); DPRINTF(("%s%%}", ra_fp_sprintf(g->loss))); } DPRINTF(("\n")); } #endif return best; } void ieee80211_ra_probe_next_rate(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni) { /* Select the next rate to probe. */ rn->probed_rates |= (1 << ni->ni_txmcs); ni->ni_txmcs = ieee80211_ra_next_mcs(rn, ic, ni); } int ieee80211_ra_valid_tx_mcs(struct ieee80211_node *ni, int mcs) { struct ieee80211com *ic = ni->ni_ic; uint32_t ntxstreams = support_nss(ni); static const int max_ht_mcs[] = { 7, 15, 23, 31 }; static const int max_vht_mcs = 9; if ((ic->ic_tx_mcs_set & IEEE80211_TX_RX_MCS_NOT_EQUAL) == 0) { if (is_he(ni) || is_vht(ni)) return isset(ic->ic_vht_sup_mcs, mcs); return isset(ic->ic_sup_mcs, mcs); } if (is_he(ni) || is_vht(ni)) return mcs < max_vht_mcs && isset(ic->ic_vht_sup_mcs, mcs); if (ntxstreams < 1 || ntxstreams > 4) panic("invalid number of Tx streams: %u", ntxstreams); return (mcs <= max_ht_mcs[ntxstreams - 1] && isset(ic->ic_sup_mcs, mcs)); } int ieee80211_ra_vht_highest_rx_mcs(struct ieee80211_node *ni, int nss) { uint16_t rx_mcs; rx_mcs = le16toh(ni->ni_vht_mcsinfo.rx_mcs_map) & (IEEE80211_VHT_MCS_NOT_SUPPORTED << (2 * (nss - 1))); rx_mcs >>= (2 * (nss - 1)); return rx_mcs; } int ieee80211_ra_valid_rx_mcs(struct ieee80211_node *ni, int mcs) { uint16_t rx_mcs; if (is_he(ni) || is_vht(ni)) { rx_mcs = ieee80211_ra_vht_highest_rx_mcs(ni, ni->ni_rx_nss > 1 ? 2 : 1); if (rx_mcs == 0 && mcs == 8) return 0; else if (rx_mcs == 1 && mcs == 9) return 0; if (mcs == 9 && ni->ni_chw == IEEE80211_CHAN_WIDTH_20) return 0; } else if (!isset(ni->ni_rxmcs, mcs)) return 0; return 1; } uint32_t ieee80211_ra_valid_rates(struct ieee80211com *ic, struct ieee80211_node *ni) { uint32_t valid_mcs = 0; uint32_t max_mcs = (is_he(ni) || is_vht(ni)) ? IEEE80211_VHT_RATESET_NUM_MCS : IEEE80211_HT_RATESET_NUM_MCS; int i; for (i = 0; i < max_mcs; i++) { if (!ieee80211_ra_valid_rx_mcs(ni, i)) continue; if (!ieee80211_ra_valid_tx_mcs(ni, i)) continue; valid_mcs |= (1 << i); } return valid_mcs; } void ieee80211_ra_add_stats_ht(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni, int mcs, uint32_t total, uint32_t fail) { static const uint64_t alpha = RA_FP_1 / 8; /* 1/8 = 0.125 */ static const uint64_t beta = RA_FP_1 / 4; /* 1/4 = 0.25 */ int s; struct ieee80211_ra_goodput_stats *g; uint64_t sfer, rate, delta; /* * Ignore invalid values. These values may come from hardware * so asserting valid values via panic is not appropriate. */ if (mcs < 0 || mcs >= IEEE80211_HT_RATESET_NUM_MCS) return; if (total == 0) return; s = splnet(); g = &rn->g[mcs]; g->nprobe_pkts += total; g->nprobe_fail += fail; if (!ieee80211_ra_probe_valid(g)) { splx(s); return; } rn->valid_probes |= 1U << mcs; if (g->nprobe_fail > g->nprobe_pkts) { DPRINTF(("%s fail %u > pkts %u\n", ether_sprintf(ni->ni_macaddr), g->nprobe_fail, g->nprobe_pkts)); g->nprobe_fail = g->nprobe_pkts; } sfer = g->nprobe_fail << RA_FP_SHIFT; sfer /= g->nprobe_pkts; g->nprobe_fail = 0; g->nprobe_pkts = 0; rate = ieee80211_ra_get_txrate(rn, ic, ni, mcs); g->loss = sfer * 100; g->measured = RA_FP_MUL(RA_FP_1 - sfer, rate); g->average = RA_FP_MUL(RA_FP_1 - alpha, g->average); g->average += RA_FP_MUL(alpha, g->measured); g->stddeviation = RA_FP_MUL(RA_FP_1 - beta, g->stddeviation); if (g->average > g->measured) delta = g->average - g->measured; else delta = g->measured - g->average; g->stddeviation += RA_FP_MUL(beta, delta); splx(s); } void ieee80211_ra_choose(struct ieee80211_ra_node *rn, struct ieee80211com *ic, struct ieee80211_node *ni) { struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs]; int s; const struct ieee80211_ra_rate *rs, *rsnext; s = splnet(); if (rn->valid_rates == 0) rn->valid_rates = ieee80211_ra_valid_rates(ic, ni); if (rn->probing) { /* Probe another rate or settle at the best rate. */ if (!(rn->valid_probes & (1UL << ni->ni_txmcs))) { splx(s); return; } ieee80211_ra_probe_clear(rn, ni); if (!ieee80211_ra_intra_mode_ra_finished(rn, ic, ni)) { ieee80211_ra_probe_next_rate(rn, ic, ni); DPRINTFN(3, ("probing MCS %d\n", ni->ni_txmcs)); } else if (ieee80211_ra_inter_mode_ra_finished(rn, ni)) { rn->best_mcs = ieee80211_ra_best_rate(rn, ni); ni->ni_txmcs = rn->best_mcs; ieee80211_ra_probe_done(rn); } splx(s); return; } else { rn->valid_probes = 0; } rs = ieee80211_ra_get_rateset(rn, ic, ni, ni->ni_txmcs); if ((g->measured >> RA_FP_SHIFT) == 0LL || (g->average >= 3 * g->stddeviation && g->measured < g->average - 3 * g->stddeviation)) { /* Channel becomes bad. Probe downwards. */ rn->probing = IEEE80211_RA_PROBING_DOWN; rn->probed_rates = 0; if (ni->ni_txmcs == rs->min_mcs) { rsnext = ieee80211_ra_next_rateset(rn, ic, ni); if (rsnext) { ieee80211_ra_probe_next_rateset(rn, ic, ni, rsnext); } else { /* Cannot probe further down. */ rn->probing = IEEE80211_RA_NOT_PROBING; } } else { ni->ni_txmcs = ieee80211_ra_next_mcs(rn, ic, ni); rn->candidate_rates = (1 << ni->ni_txmcs); } } else if (g->loss < 2 * RA_FP_1 || g->measured > g->average + 3 * g->stddeviation) { /* Channel becomes good. */ rn->probing = IEEE80211_RA_PROBING_UP; rn->probed_rates = 0; if (ni->ni_txmcs == rs->max_mcs) { rsnext = ieee80211_ra_next_rateset(rn, ic, ni); if (rsnext) { ieee80211_ra_probe_next_rateset(rn, ic, ni, rsnext); } else { /* Cannot probe further up. */ rn->probing = IEEE80211_RA_NOT_PROBING; } } else { ni->ni_txmcs = ieee80211_ra_next_mcs(rn, ic, ni); rn->candidate_rates = (1 << ni->ni_txmcs); } } else { /* Remain at current rate. */ rn->probing = IEEE80211_RA_NOT_PROBING; rn->probed_rates = 0; rn->candidate_rates = 0; } splx(s); if (rn->probing) { if (rn->probing & IEEE80211_RA_PROBING_UP) DPRINTFN(2, ("channel becomes good; probe up\n")); else DPRINTFN(2, ("channel becomes bad; probe down\n")); DPRINTFN(3, ("measured: %s Mbit/s\n", ra_fp_sprintf(g->measured))); DPRINTFN(3, ("average: %s Mbit/s\n", ra_fp_sprintf(g->average))); DPRINTFN(3, ("stddeviation: %s\n", ra_fp_sprintf(g->stddeviation))); DPRINTFN(3, ("loss: %s%%\n", ra_fp_sprintf(g->loss))); } } void ieee80211_ra_node_init(struct ieee80211com *ic, struct ieee80211_ra_node *rn, struct ieee80211_node *ni) { memset(rn, 0, sizeof(*rn)); build_rateset(rn, (enum ieee80211_phymode)ic->ic_curmode); rn->bw = ni->ni_chw; rn->sgi = ieee80211_node_supports_sgi(ni); rn->nss = support_nss(ni); switch (ni->ni_chw) { case IEEE80211_CHAN_WIDTH_20: if (is_he(ni)) { rn->rs_index = IEEE80211_HE_RATESET_SISO; } else if (is_vht(ni)) { rn->rs_index = IEEE80211_VHT_RATESET_SISO; } else if (is_ht(ni)) { rn->rs_index = IEEE80211_HT_RATESET_SISO; } break; case IEEE80211_CHAN_WIDTH_40: if (is_he(ni)) { rn->rs_index = IEEE80211_HE_RATESET_SISO_40; } else if (is_vht(ni)) { rn->rs_index = IEEE80211_VHT_RATESET_SISO_40; } else if (is_ht(ni)) { rn->rs_index = IEEE80211_HT_RATESET_CBW40_SISO; } break; case IEEE80211_CHAN_WIDTH_80: if (is_he(ni)) { rn->rs_index = IEEE80211_HE_RATESET_SISO_80; } else if (is_vht(ni)) { rn->rs_index = IEEE80211_VHT_RATESET_SISO_80; } break; case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: if (is_he(ni)) { rn->rs_index = IEEE80211_HE_RATESET_SISO_160; } else if (is_vht(ni)) { rn->rs_index = IEEE80211_VHT_RATESET_SISO_160; } break; default: rn->rs_index = 0; break; } } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_ra.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_ra.h,v 1.1 2021/03/12 16:26:27 stsp Exp $ */ /* * Copyright (c) 2021 Christian Ehrhardt * Copyright (c) 2021 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _NET80211_IEEE80211_RA_H_ #define _NET80211_IEEE80211_RA_H_ /* * Goodput statistics struct. Measures the effective data rate of an MCS. * All uint64_t numbers in this struct use fixed-point arithmetic. */ struct ieee80211_ra_goodput_stats { uint64_t measured; /* Most recently measured goodput. */ uint64_t average; /* Average measured goodput. */ uint64_t stddeviation; /* Goodput standard deviation. */ uint64_t loss; /* This rate's loss percentage SFER. */ uint32_t nprobe_pkts; /* Number of packets in current probe. */ uint32_t nprobe_fail; /* Number of failed packets. */ }; #define IEEE80211_RATESET_MAX_NRATES 11 #define IEEE80211_RATESET_MAX_RATE_SET max(IEEE80211_HT_NUM_RATESETS, IEEE80211_VHT_NUM_RATESETS) struct ieee80211_ra_rate { int min_mcs; int max_mcs; int band_width; int sgi; int nss; int rs_index; uint32_t nrates; uint32_t rates[IEEE80211_RATESET_MAX_NRATES]; /* 500 kbit/s units */ }; /* * Rate adaptation state. * * Drivers should not modify any fields of this structure directly. * Use ieee80211_ra_init() and ieee80211_ra_add_stats() only. */ struct ieee80211_ra_node { /* Bitmaps MCS 0-31. */ uint32_t valid_probes; uint32_t valid_rates; uint32_t candidate_rates; uint32_t probed_rates; /* Probing state. */ int probing; #define IEEE80211_RA_NOT_PROBING 0x0 #define IEEE80211_RA_PROBING_DOWN 0x1 #define IEEE80211_RA_PROBING_UP 0x2 #define IEEE80211_RA_PROBING_INTER 0x4 /* combined with UP or DOWN */ /* The current best MCS found by probing. */ int best_mcs; /* Goodput statistics for each MCS. */ struct ieee80211_ra_goodput_stats g[IEEE80211_HT_RATESET_NUM_MCS]; int bw; int sgi; int nss; int rs_index; uint32_t active_rs_count; enum ieee80211_phymode rs_phymode; struct ieee80211_ra_rate active_rs[IEEE80211_RATESET_MAX_RATE_SET]; }; /* Initialize rate adaptation state. */ void ieee80211_ra_node_init(struct ieee80211com *, struct ieee80211_ra_node *, struct ieee80211_node *); /* * Drivers report information about 802.11n/HT Tx attempts here. * mcs: The HT MCS used during this Tx attempt. * total: How many Tx attempts (initial attempt + any retries) were made? * fail: How many of these Tx attempts failed? */ void ieee80211_ra_add_stats_ht(struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *, int mcs, unsigned int total, unsigned int fail); /* Drivers call this function to update ni->ni_txmcs. */ void ieee80211_ra_choose(struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *); /* Get the HT rateset for a particular HT MCS with SGI on/off. */ const struct ieee80211_ra_rate *ieee80211_ra_get_rateset(struct ieee80211_ra_node *, struct ieee80211com *, struct ieee80211_node *, int); /* Check whether SGI should be used. */ int ieee80211_ra_use_ht_sgi(struct ieee80211_node *); #endif /* _NET80211_IEEE80211_RA_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_radiotap.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_radiotap.h,v 1.16 2020/10/09 08:53:16 mpi Exp $ */ /* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.3 2004/04/05 22:13:21 sam Exp $ */ /* $NetBSD: ieee80211_radiotap.h,v 1.9 2004/06/06 04:13:28 dyoung Exp $ */ /*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #ifndef _NET_IF_IEEE80211RADIOTAP_H_ #define _NET_IF_IEEE80211RADIOTAP_H_ /* A generic radio capture format is desirable. There is one for * Linux, but it is neither rigidly defined (there were not even * units given for some fields) nor easily extensible. * * I suggest the following extensible radio capture format. It is * based on a bitmap indicating which fields are present. * * I am trying to describe precisely what the application programmer * should expect in the following, and for that reason I tell the * units and origin of each measurement (where it applies), or else I * use sufficiently weaselly language ("is a monotonically nondecreasing * function of...") that I cannot set false expectations for lawyerly * readers. */ /* XXX tcpdump/libpcap do not tolerate variable-length headers, * yet, so we pad every radiotap header to 64 bytes. Ugh. */ #define IEEE80211_RADIOTAP_HDRLEN 64 /* The radio capture header precedes the 802.11 header. */ struct ieee80211_radiotap_header { u_int8_t it_version; /* Version 0. Only increases * for drastic changes, * introduction of compatible * new fields does not count. */ u_int8_t it_pad; u_int16_t it_len; /* length of the whole * header in bytes, including * it_version, it_pad, * it_len, and data fields. */ u_int32_t it_present; /* A bitmap telling which * fields are present. Set bit 31 * (0x80000000) to extend the * bitmap by another 32 bits. * Additional extensions are made * by setting bit 31. */ } __packed; /* Name Data type Units * ---- --------- ----- * * IEEE80211_RADIOTAP_TSFT u_int64_t microseconds * * Value in microseconds of the MAC's 64-bit 802.11 Time * Synchronization Function timer when the first bit of the * MPDU arrived at the MAC. For received frames, only. * * IEEE80211_RADIOTAP_CHANNEL 2 x u_int16_t MHz, bitmap * * Tx/Rx frequency in MHz, followed by flags (see below). * * IEEE80211_RADIOTAP_FHSS u_int16_t see below * * For frequency-hopping radios, the hop set (first byte) * and pattern (second byte). * * IEEE80211_RADIOTAP_RATE u_int8_t 500kb/s or MCS index * * Tx/Rx data rate in units of 500kb/s. If the high bit (0x80) is set * the remaining bits contain an MCS index instead of a date rate. * * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from * one milliwatt (dBm) * * RF signal power at the antenna, decibel difference from * one milliwatt. * * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from * one milliwatt (dBm) * * RF noise power at the antenna, decibel difference from one * milliwatt. * * IEEE80211_RADIOTAP_DB_ANTSIGNAL u_int8_t decibel (dB) * * RF signal power at the antenna, decibel difference from an * arbitrary, fixed reference. * * IEEE80211_RADIOTAP_DB_ANTNOISE u_int8_t decibel (dB) * * RF noise power at the antenna, decibel difference from an * arbitrary, fixed reference point. * * IEEE80211_RADIOTAP_BARKER_CODE_LOCK u_int16_t unitless * * Quality of Barker code lock. Unitless. Monotonically * nondecreasing with "better" lock strength. Called "Signal * Quality" in datasheets. (Is there a standard way to measure * this?) * * IEEE80211_RADIOTAP_TX_ATTENUATION u_int16_t unitless * * Transmit power expressed as unitless distance from max * power set at factory calibration. 0 is max power. * Monotonically nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u_int16_t decibels (dB) * * Transmit power expressed as decibel distance from max power * set at factory calibration. 0 is max power. Monotonically * nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from * one milliwatt (dBm) * * Transmit power expressed as dBm (decibels from a 1 milliwatt * reference). This is the absolute power level measured at * the antenna port. * * IEEE80211_RADIOTAP_FLAGS u_int8_t bitmap * * Properties of transmitted and received frames. See flags * defined below. * * IEEE80211_RADIOTAP_ANTENNA u_int8_t antenna index * * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. * * IEEE80211_RADIOTAP_FCS u_int32_t data * * FCS from frame in network byte order. * * IEEE80211_RADIOTAP_RSSI 2x u_int8_t RSSI, max RSSI * * A relative Received Signal Strength Index */ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_TSFT = 0, IEEE80211_RADIOTAP_FLAGS = 1, IEEE80211_RADIOTAP_RATE = 2, IEEE80211_RADIOTAP_CHANNEL = 3, IEEE80211_RADIOTAP_FHSS = 4, IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, IEEE80211_RADIOTAP_LOCK_QUALITY = 7, IEEE80211_RADIOTAP_TX_ATTENUATION = 8, IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, IEEE80211_RADIOTAP_DBM_TX_POWER = 10, IEEE80211_RADIOTAP_ANTENNA = 11, IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, IEEE80211_RADIOTAP_DB_ANTNOISE = 13, IEEE80211_RADIOTAP_FCS = 14, IEEE80211_RADIOTAP_RSSI = 16, IEEE80211_RADIOTAP_EXT = 31 }; #ifndef _KERNEL /* For IEEE80211_RADIOTAP_CHANNEL */ #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel */ #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ #define IEEE80211_CHAN_XR 0x1000 /* Extended range OFDM channel */ #define IEEE80211_CHAN_HT 0x2000 /* 11n/HT channel */ #define IEEE80211_CHAN_VHT 0x4000 /* 11ac/VHT channel */ #endif /* !_KERNEL */ /* For IEEE80211_RADIOTAP_FLAGS */ #define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received * during CFP */ #define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received * with short * preamble */ #define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received * with WEP encryption */ #define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received * with fragmentation */ #define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ #endif /* _NET_IF_IEEE80211RADIOTAP_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_regdomain.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. */ /* $OpenBSD: ieee80211_regdomain.c,v 1.10 2015/11/24 13:45:06 mpi Exp $ */ /* * Copyright (c) 2004, 2005 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Basic regulation domain extensions for the IEEE 802.11 stack */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int ieee80211_regdomain_compare_cn(const void *, const void *); int ieee80211_regdomain_compare_rn(const void *, const void *); static const struct ieee80211_regdomainname ieee80211_r_names[] = IEEE80211_REGDOMAIN_NAMES; static const struct ieee80211_regdomainmap ieee80211_r_map[] = IEEE80211_REGDOMAIN_MAP; static const struct ieee80211_countryname ieee80211_r_ctry[] = IEEE80211_REGDOMAIN_COUNTRY_NAMES; #ifndef bsearch const void *bsearch(const void *, const void *, size_t, size_t, int (*)(const void *, const void *)); const void * bsearch(const void *key, const void *base0, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { const char *base = (const char *)base0; int lim, cmp; const void *p; for (lim = nmemb; lim != 0; lim >>= 1) { p = base + (lim >> 1) * size; cmp = (*compar)(key, p); if (cmp == 0) return ((const void *)p); if (cmp > 0) { /* key > p: move right */ base = (const char *)p + size; lim--; } /* else move left */ } return (NULL); } #endif int ieee80211_regdomain_compare_cn(const void *a, const void *b) { return (strcmp(((const struct ieee80211_countryname*)a)->cn_name, ((const struct ieee80211_countryname*)b)->cn_name)); } int ieee80211_regdomain_compare_rn(const void *a, const void *b) { return (strcmp(((const struct ieee80211_regdomainname*)a)->rn_name, ((const struct ieee80211_regdomainname*)b)->rn_name)); } u_int16_t ieee80211_name2countrycode(const char *name) { const struct ieee80211_countryname key = { CTRY_DEFAULT, name }, *value; if ((value = (const struct ieee80211_countryname*)bsearch((const void *)&key, (const void *)&ieee80211_r_ctry, nitems(ieee80211_r_ctry), sizeof(struct ieee80211_countryname), ieee80211_regdomain_compare_cn)) != NULL) return (value->cn_code); return (CTRY_DEFAULT); } u_int32_t ieee80211_name2regdomain(const char *name) { const struct ieee80211_regdomainname *value; struct ieee80211_regdomainname key; key.rn_domain = DMN_DEFAULT; key.rn_name = name; if ((value = (const struct ieee80211_regdomainname *)bsearch((const void *)&key, (const void *)&ieee80211_r_names, nitems(ieee80211_r_names), sizeof(struct ieee80211_regdomainname), ieee80211_regdomain_compare_rn)) != NULL) return ((u_int32_t)value->rn_domain); return ((u_int32_t)DMN_DEFAULT); } const char * ieee80211_countrycode2name(u_int16_t code) { int i; /* Linear search over the table */ for (i = 0; i < (sizeof(ieee80211_r_ctry) / sizeof(ieee80211_r_ctry[0])); i++) if (ieee80211_r_ctry[i].cn_code == code) return (ieee80211_r_ctry[i].cn_name); return (NULL); } const char * ieee80211_regdomain2name(u_int32_t regdomain) { int i; /* Linear search over the table */ for (i = 0; i < (sizeof(ieee80211_r_names) / sizeof(ieee80211_r_names[0])); i++) if (ieee80211_r_names[i].rn_domain == regdomain) return (ieee80211_r_names[i].rn_name); return (ieee80211_r_names[0].rn_name); } u_int32_t ieee80211_regdomain2flag(u_int16_t regdomain, u_int16_t mhz) { int i; for (i = 0; i < (sizeof(ieee80211_r_map) / sizeof(ieee80211_r_map[0])); i++) { if (ieee80211_r_map[i].rm_domain == regdomain) { if (mhz >= 2000 && mhz <= 3000) return ((u_int32_t) ieee80211_r_map[i].rm_domain_2ghz); if (mhz >= IEEE80211_CHANNELS_5GHZ_MIN && mhz <= IEEE80211_CHANNELS_5GHZ_MAX) return ((u_int32_t) ieee80211_r_map[i].rm_domain_5ghz); } } return ((u_int32_t)DMN_DEBUG); } u_int32_t ieee80211_countrycode2regdomain(u_int16_t code) { int i; for (i = 0; i < nitems(ieee80211_r_ctry); i++) if (ieee80211_r_ctry[i].cn_code == code) return (ieee80211_r_ctry[i].cn_domain); return ((u_int32_t)DMN_DEFAULT); } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_regdomain.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_regdomain.h,v 1.9 2016/01/12 09:28:09 stsp Exp $ */ /* * Copyright (c) 2004, 2005 Reyk Floeter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _NET80211_IEEE80211_REGDOMAIN_H_ #define _NET80211_IEEE80211_REGDOMAIN_H_ typedef u_int32_t ieee80211_regdomain_t; enum ieee80211_regdomain { DMN_DEFAULT = 0x00, DMN_NULL_WORLD = 0x03, DMN_NULL_ETSIB = 0x07, DMN_NULL_ETSIC = 0x08, DMN_FCC1_FCCA = 0x10, DMN_FCC1_WORLD = 0x11, DMN_FCC2_FCCA = 0x20, DMN_FCC2_WORLD = 0x21, DMN_FCC2_ETSIC = 0x22, DMN_FRANCE_NULL = 0x31, DMN_FCC3_FCCA = 0x3A, DMN_ETSI1_WORLD = 0x37, DMN_ETSI3_ETSIA = 0x32, DMN_ETSI2_WORLD = 0x35, DMN_ETSI3_WORLD = 0x36, DMN_ETSI4_WORLD = 0x30, DMN_ETSI4_ETSIC = 0x38, DMN_ETSI5_WORLD = 0x39, DMN_ETSI6_WORLD = 0x34, DMN_ETSI_NULL = 0x33, DMN_MKK1_MKKA = 0x40, DMN_MKK1_MKKB = 0x41, DMN_APL4_WORLD = 0x42, DMN_MKK2_MKKA = 0x43, DMN_APL_NULL = 0x44, DMN_APL2_WORLD = 0x45, DMN_APL2_APLC = 0x46, DMN_APL3_WORLD = 0x47, DMN_MKK1_FCCA = 0x48, DMN_APL2_APLD = 0x49, DMN_MKK1_MKKA1 = 0x4A, DMN_MKK1_MKKA2 = 0x4B, DMN_APL1_WORLD = 0x52, DMN_APL1_FCCA = 0x53, DMN_APL1_APLA = 0x54, DMN_APL1_ETSIC = 0x55, DMN_APL2_ETSIC = 0x56, DMN_APL5_WORLD = 0x58, DMN_WOR0_WORLD = 0x60, DMN_WOR1_WORLD = 0x61, DMN_WOR2_WORLD = 0x62, DMN_WOR3_WORLD = 0x63, DMN_WOR4_WORLD = 0x64, DMN_WOR5_ETSIC = 0x65, DMN_WOR01_WORLD = 0x66, DMN_WOR02_WORLD = 0x67, DMN_EU1_WORLD = 0x68, DMN_WOR9_WORLD = 0x69, DMN_WORA_WORLD = 0x6A, DMN_APL1 = 0xf0000001, DMN_APL2 = 0xf0000002, DMN_APL3 = 0xf0000004, DMN_APL4 = 0xf0000008, DMN_APL5 = 0xf0000010, DMN_ETSI1 = 0xf0000020, DMN_ETSI2 = 0xf0000040, DMN_ETSI3 = 0xf0000080, DMN_ETSI4 = 0xf0000100, DMN_ETSI5 = 0xf0000200, DMN_ETSI6 = 0xf0000400, DMN_ETSIA = 0xf0000800, DMN_ETSIB = 0xf0001000, DMN_ETSIC = 0xf0002000, DMN_FCC1 = 0xf0004000, DMN_FCC2 = 0xf0008000, DMN_FCC3 = 0xf0010000, DMN_FCCA = 0xf0020000, DMN_APLD = 0xf0040000, DMN_MKK1 = 0xf0080000, DMN_MKK2 = 0xf0100000, DMN_MKKA = 0xf0200000, DMN_NULL = 0xf0400000, DMN_WORLD = 0xf0800000, DMN_DEBUG = 0xf1000000 /* used for debugging */ }; #define IEEE80211_DMN(_d) ((_d) & ~0xf0000000) struct ieee80211_regdomainname { u_int32_t rn_domain; const char *rn_name; }; #define IEEE80211_REGDOMAIN_NAMES { \ { DMN_APL1, "APL1" }, \ { DMN_APL1_APLA, "APL1A" }, \ { DMN_APL1_ETSIC, "APL1_ETSIC" }, \ { DMN_APL1_FCCA, "APL1_FCCA" }, \ { DMN_APL1_WORLD, "APL1W" }, \ { DMN_APL2, "APL2" }, \ { DMN_APL2_APLC, "APL2C" }, \ { DMN_APL2_APLD, "APL2D" }, \ { DMN_APL2_ETSIC, "APL2_ETSIC" }, \ { DMN_APL2_WORLD, "APL2W" }, \ { DMN_APL3, "APL3" }, \ { DMN_APL3_WORLD, "APL3W" }, \ { DMN_APL4, "APL4" }, \ { DMN_APL4_WORLD, "APL4W" }, \ { DMN_APL5, "APL5" }, \ { DMN_APL5_WORLD, "APL5W" }, \ { DMN_APLD, "APLD" }, \ { DMN_APL_NULL, "APL" }, \ { DMN_DEBUG, "DEBUG" }, \ { DMN_ETSI1, "ETSI1" }, \ { DMN_ETSI1_WORLD, "ETSI1W" }, \ { DMN_ETSI2, "ETSI2" }, \ { DMN_ETSI2_WORLD, "ETSI2W" }, \ { DMN_ETSI3, "ETSI3" }, \ { DMN_ETSI3_ETSIA, "ETSI3A" }, \ { DMN_ETSI3_WORLD, "ETSI3W," }, \ { DMN_ETSI4, "ETSI4" }, \ { DMN_ETSI4_ETSIC, "ETSI4C" }, \ { DMN_ETSI4_WORLD, "ETSI4W" }, \ { DMN_ETSI5, "ETSI5" }, \ { DMN_ETSI5_WORLD, "ETSI5W" }, \ { DMN_ETSI6, "ETSI6" }, \ { DMN_ETSI6_WORLD, "ETSI6W" }, \ { DMN_ETSIA, "ETSIA" }, \ { DMN_ETSIB, "ETSIB" }, \ { DMN_ETSIC, "ETSIC" }, \ { DMN_ETSI_NULL, "ETSI" }, \ { DMN_EU1_WORLD, "EU1W" }, \ { DMN_FCC1, "FCC1" }, \ { DMN_FCC1_FCCA, "FCC1A" }, \ { DMN_FCC1_WORLD, "FCC1W" }, \ { DMN_FCC2, "FCC2" }, \ { DMN_FCC2_ETSIC, "FCC2C" }, \ { DMN_FCC2_FCCA, "FCC2A" }, \ { DMN_FCC2_WORLD, "FCC2W" }, \ { DMN_FCC3, "FCC3" }, \ { DMN_FCC3_FCCA, "FCC3A" }, \ { DMN_FCCA, "FCCA" }, \ { DMN_FRANCE_NULL, "FRANCE" }, \ { DMN_MKK1, "MKK1" }, \ { DMN_MKK1_FCCA, "MKK1_FCCA" }, \ { DMN_MKK1_MKKA, "MKK1A" }, \ { DMN_MKK1_MKKA1, "MKK1A1" }, \ { DMN_MKK1_MKKA2, "MKK1A2" }, \ { DMN_MKK1_MKKB, "MKK1B" }, \ { DMN_MKK2, "MKK2" }, \ { DMN_MKK2_MKKA, "MKK2A" }, \ { DMN_MKKA, "MKKA" }, \ { DMN_DEFAULT, "NONE" }, \ { DMN_NULL, "NONE" }, \ { DMN_NULL_ETSIB, "ETSIB" }, \ { DMN_NULL_ETSIC, "ETSIC" }, \ { DMN_WOR01_WORLD, "WOR01W" }, \ { DMN_WOR02_WORLD, "WOR02W" }, \ { DMN_WOR0_WORLD, "WOR0W" }, \ { DMN_WOR1_WORLD, "WOR1W" }, \ { DMN_WOR2_WORLD, "WOR2W" }, \ { DMN_WOR3_WORLD, "WOR3W" }, \ { DMN_WOR4_WORLD, "WOR4W" }, \ { DMN_WOR5_ETSIC, "WOR5_ETSIC" }, \ { DMN_WOR9_WORLD, "WOR9W" }, \ { DMN_WORA_WORLD, "WORAW" }, \ { DMN_NULL_WORLD, "WORLD" }, \ { DMN_WORLD, "WORLD" } \ } struct ieee80211_regdomainmap { u_int16_t rm_domain; u_int32_t rm_domain_5ghz; u_int32_t rm_domain_2ghz; }; #define IEEE80211_REGDOMAIN_MAP { \ { DMN_DEFAULT, DMN_DEBUG, DMN_DEBUG }, \ { DMN_NULL_WORLD, DMN_NULL, DMN_WORLD }, \ { DMN_NULL_ETSIB, DMN_NULL, DMN_ETSIB }, \ { DMN_NULL_ETSIC, DMN_NULL, DMN_ETSIC }, \ { DMN_FCC1_FCCA, DMN_FCC1, DMN_FCCA }, \ { DMN_FCC1_WORLD, DMN_FCC1, DMN_WORLD }, \ { DMN_FCC2_FCCA, DMN_FCC2, DMN_FCCA }, \ { DMN_FCC2_WORLD, DMN_FCC2, DMN_WORLD }, \ { DMN_FCC2_ETSIC, DMN_FCC2, DMN_ETSIC }, \ { DMN_FRANCE_NULL, DMN_ETSI3, DMN_ETSI3 }, \ { DMN_FCC3_FCCA, DMN_FCC3, DMN_WORLD }, \ { DMN_ETSI1_WORLD, DMN_ETSI1, DMN_WORLD }, \ { DMN_ETSI3_ETSIA, DMN_ETSI3, DMN_WORLD }, \ { DMN_ETSI2_WORLD, DMN_ETSI2, DMN_WORLD }, \ { DMN_ETSI3_WORLD, DMN_ETSI3, DMN_WORLD }, \ { DMN_ETSI4_WORLD, DMN_ETSI4, DMN_WORLD }, \ { DMN_ETSI4_ETSIC, DMN_ETSI4, DMN_ETSIC }, \ { DMN_ETSI5_WORLD, DMN_ETSI5, DMN_WORLD }, \ { DMN_ETSI6_WORLD, DMN_ETSI6, DMN_WORLD }, \ { DMN_ETSI_NULL, DMN_ETSI1, DMN_ETSI1 }, \ { DMN_MKK1_MKKA, DMN_MKK1, DMN_MKKA }, \ { DMN_MKK1_MKKB, DMN_MKK1, DMN_MKKA }, \ { DMN_APL4_WORLD, DMN_APL4, DMN_WORLD }, \ { DMN_MKK2_MKKA, DMN_MKK2, DMN_MKKA }, \ { DMN_APL_NULL, DMN_APL1, DMN_NULL }, \ { DMN_APL2_WORLD, DMN_APL2, DMN_WORLD }, \ { DMN_APL2_APLC, DMN_APL2, DMN_WORLD }, \ { DMN_APL3_WORLD, DMN_APL3, DMN_WORLD }, \ { DMN_MKK1_FCCA, DMN_MKK1, DMN_FCCA }, \ { DMN_APL2_APLD, DMN_APL2, DMN_APLD }, \ { DMN_MKK1_MKKA1, DMN_MKK1, DMN_MKKA }, \ { DMN_MKK1_MKKA2, DMN_MKK1, DMN_MKKA }, \ { DMN_APL1_WORLD, DMN_APL1, DMN_WORLD }, \ { DMN_APL1_FCCA, DMN_APL1, DMN_FCCA }, \ { DMN_APL1_APLA, DMN_APL1, DMN_WORLD }, \ { DMN_APL1_ETSIC, DMN_APL1, DMN_ETSIC }, \ { DMN_APL2_ETSIC, DMN_APL2, DMN_ETSIC }, \ { DMN_APL5_WORLD, DMN_APL5, DMN_WORLD }, \ { DMN_WOR0_WORLD, DMN_WORLD, DMN_WORLD }, \ { DMN_WOR1_WORLD, DMN_WORLD, DMN_WORLD }, \ { DMN_WOR2_WORLD, DMN_WORLD, DMN_WORLD }, \ { DMN_WOR3_WORLD, DMN_WORLD, DMN_WORLD }, \ { DMN_WOR4_WORLD, DMN_WORLD, DMN_WORLD }, \ { DMN_WOR5_ETSIC, DMN_WORLD, DMN_WORLD }, \ { DMN_WOR01_WORLD, DMN_WORLD, DMN_WORLD }, \ { DMN_WOR02_WORLD, DMN_WORLD, DMN_WORLD }, \ { DMN_EU1_WORLD, DMN_ETSI1, DMN_WORLD }, \ { DMN_WOR9_WORLD, DMN_WORLD, DMN_WORLD }, \ { DMN_WORA_WORLD, DMN_WORLD, DMN_WORLD }, \ } enum ieee80211_countrycode { CTRY_DEFAULT = 0, /* Default domain (NA) */ CTRY_ALBANIA = 8, /* Albania */ CTRY_ALGERIA = 12, /* Algeria */ CTRY_ARGENTINA = 32, /* Argentina */ CTRY_ARMENIA = 51, /* Armenia */ CTRY_AUSTRALIA = 36, /* Australia */ CTRY_AUSTRIA = 40, /* Austria */ CTRY_AZERBAIJAN = 31, /* Azerbaijan */ CTRY_BAHRAIN = 48, /* Bahrain */ CTRY_BELARUS = 112, /* Belarus */ CTRY_BELGIUM = 56, /* Belgium */ CTRY_BELIZE = 84, /* Belize */ CTRY_BOLIVIA = 68, /* Bolivia */ CTRY_BRAZIL = 76, /* Brazil */ CTRY_BRUNEI_DARUSSALAM = 96, /* Brunei Darussalam */ CTRY_BULGARIA = 100, /* Bulgaria */ CTRY_CANADA = 124, /* Canada */ CTRY_CHILE = 152, /* Chile */ CTRY_CHINA = 156, /* People's Republic of China */ CTRY_COLOMBIA = 170, /* Colombia */ CTRY_COSTA_RICA = 188, /* Costa Rica */ CTRY_CROATIA = 191, /* Croatia */ CTRY_CYPRUS = 196, /* Cyprus */ CTRY_CZECH = 203, /* Czech Republic */ CTRY_DENMARK = 208, /* Denmark */ CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */ CTRY_ECUADOR = 218, /* Ecuador */ CTRY_EGYPT = 818, /* Egypt */ CTRY_EL_SALVADOR = 222, /* El Salvador */ CTRY_ESTONIA = 233, /* Estonia */ CTRY_FAEROE_ISLANDS = 234, /* Faeroe Islands */ CTRY_FINLAND = 246, /* Finland */ CTRY_FRANCE = 250, /* France */ CTRY_FRANCE2 = 255, /* France2 */ CTRY_GEORGIA = 268, /* Georgia */ CTRY_GERMANY = 276, /* Germany */ CTRY_GREECE = 300, /* Greece */ CTRY_GUATEMALA = 320, /* Guatemala */ CTRY_HONDURAS = 340, /* Honduras */ CTRY_HONG_KONG = 344, /* Hong Kong S.A.R., P.R.C. */ CTRY_HUNGARY = 348, /* Hungary */ CTRY_ICELAND = 352, /* Iceland */ CTRY_INDIA = 356, /* India */ CTRY_INDONESIA = 360, /* Indonesia */ CTRY_IRAN = 364, /* Iran */ CTRY_IRAQ = 368, /* Iraq */ CTRY_IRELAND = 372, /* Ireland */ CTRY_ISRAEL = 376, /* Israel */ CTRY_ITALY = 380, /* Italy */ CTRY_JAMAICA = 388, /* Jamaica */ CTRY_JAPAN = 392, /* Japan */ CTRY_JAPAN1 = 393, /* Japan (JP1) */ CTRY_JAPAN2 = 394, /* Japan (JP0) */ CTRY_JAPAN3 = 395, /* Japan (JP1-1) */ CTRY_JAPAN4 = 396, /* Japan (JE1) */ CTRY_JAPAN5 = 397, /* Japan (JE2) */ CTRY_JORDAN = 400, /* Jordan */ CTRY_KAZAKHSTAN = 398, /* Kazakhstan */ CTRY_KENYA = 404, /* Kenya */ CTRY_KOREA_NORTH = 408, /* North Korea */ CTRY_KOREA_ROC = 410, /* South Korea */ CTRY_KOREA_ROC2 = 411, /* South Korea */ CTRY_KUWAIT = 414, /* Kuwait */ CTRY_LATVIA = 428, /* Latvia */ CTRY_LEBANON = 422, /* Lebanon */ CTRY_LIBYA = 434, /* Libya */ CTRY_LIECHTENSTEIN = 438, /* Liechtenstein */ CTRY_LITHUANIA = 440, /* Lithuania */ CTRY_LUXEMBOURG = 442, /* Luxembourg */ CTRY_MACAU = 446, /* Macau */ CTRY_MACEDONIA = 807, /* Republic of Macedonia */ CTRY_MALAYSIA = 458, /* Malaysia */ CTRY_MEXICO = 484, /* Mexico */ CTRY_MONACO = 492, /* Principality of Monaco */ CTRY_MOROCCO = 504, /* Morocco */ CTRY_NETHERLANDS = 528, /* Netherlands */ CTRY_NEW_ZEALAND = 554, /* New Zealand */ CTRY_NICARAGUA = 558, /* Nicaragua */ CTRY_NORWAY = 578, /* Norway */ CTRY_OMAN = 512, /* Oman */ CTRY_PAKISTAN = 586, /* Islamic Republic of Pakistan */ CTRY_PANAMA = 591, /* Panama */ CTRY_PARAGUAY = 600, /* Paraguay */ CTRY_PERU = 604, /* Peru */ CTRY_PHILIPPINES = 608, /* Republic of the Philippines */ CTRY_POLAND = 616, /* Poland */ CTRY_PORTUGAL = 620, /* Portugal */ CTRY_PUERTO_RICO = 630, /* Puerto Rico */ CTRY_QATAR = 634, /* Qatar */ CTRY_ROMANIA = 642, /* Romania */ CTRY_RUSSIA = 643, /* Russia */ CTRY_SAUDI_ARABIA = 682, /* Saudi Arabia */ CTRY_SINGAPORE = 702, /* Singapore */ CTRY_SLOVAKIA = 703, /* Slovak Republic */ CTRY_SLOVENIA = 705, /* Slovenia */ CTRY_SOUTH_AFRICA = 710, /* South Africa */ CTRY_SPAIN = 724, /* Spain */ CTRY_SRI_LANKA = 728, /* Sri Lanka */ CTRY_SWEDEN = 752, /* Sweden */ CTRY_SWITZERLAND = 756, /* Switzerland */ CTRY_SYRIA = 760, /* Syria */ CTRY_TAIWAN = 158, /* Taiwan */ CTRY_THAILAND = 764, /* Thailand */ CTRY_TRINIDAD_Y_TOBAGO = 780, /* Trinidad y Tobago */ CTRY_TUNISIA = 788, /* Tunisia */ CTRY_TURKEY = 792, /* Turkey */ CTRY_UAE = 784, /* U.A.E. */ CTRY_UKRAINE = 804, /* Ukraine */ CTRY_UNITED_KINGDOM = 826, /* United Kingdom */ CTRY_UNITED_STATES = 840, /* United States */ CTRY_URUGUAY = 858, /* Uruguay */ CTRY_UZBEKISTAN = 860, /* Uzbekistan */ CTRY_VENEZUELA = 862, /* Venezuela */ CTRY_VIET_NAM = 704, /* Viet Nam */ CTRY_YEMEN = 887, /* Yemen */ CTRY_ZIMBABWE = 716, /* Zimbabwe */ }; struct ieee80211_countryname { u_int16_t cn_code; const char *cn_name; u_int32_t cn_domain; }; #define IEEE80211_REGDOMAIN_COUNTRY_NAMES { \ { CTRY_DEFAULT, "00", DMN_DEFAULT }, \ { CTRY_UAE, "ae", DMN_NULL_WORLD }, \ { CTRY_ALBANIA, "al", DMN_NULL_WORLD }, \ { CTRY_ARMENIA, "am", DMN_ETSI4_WORLD }, \ { CTRY_ARGENTINA, "ar", DMN_APL3_WORLD }, \ { CTRY_AUSTRIA, "at", DMN_ETSI5_WORLD }, \ { CTRY_AUSTRALIA, "au", DMN_FCC2_WORLD }, \ { CTRY_AZERBAIJAN, "az", DMN_ETSI4_WORLD }, \ { CTRY_BELGIUM, "be", DMN_ETSI4_WORLD }, \ { CTRY_BULGARIA, "bg", DMN_ETSI6_WORLD }, \ { CTRY_BAHRAIN, "bh", DMN_NULL_WORLD }, \ { CTRY_BRUNEI_DARUSSALAM, "bn", DMN_APL1_WORLD }, \ { CTRY_BOLIVIA, "bo", DMN_APL1_ETSIC }, \ { CTRY_BRAZIL, "br", DMN_NULL_ETSIC }, \ { CTRY_BELARUS, "by", DMN_NULL_WORLD }, \ { CTRY_BELIZE, "bz", DMN_NULL_ETSIC }, \ { CTRY_CANADA, "ca", DMN_FCC2_FCCA }, \ { CTRY_SWITZERLAND, "ch", DMN_ETSI2_WORLD }, \ { CTRY_CHILE, "cl", DMN_APL5_WORLD }, \ { CTRY_CHINA, "cn", DMN_APL1_WORLD }, \ { CTRY_COLOMBIA, "co", DMN_FCC1_FCCA }, \ { CTRY_COSTA_RICA, "cr", DMN_NULL_WORLD }, \ { CTRY_CYPRUS, "cy", DMN_ETSI1_WORLD }, \ { CTRY_CZECH, "cz", DMN_ETSI3_WORLD }, \ { CTRY_GERMANY, "de", DMN_ETSI1_WORLD }, \ { CTRY_DENMARK, "dk", DMN_ETSI1_WORLD }, \ { CTRY_DOMINICAN_REPUBLIC, "do", DMN_FCC1_FCCA }, \ { CTRY_ALGERIA, "dz", DMN_NULL_WORLD }, \ { CTRY_ECUADOR, "ec", DMN_NULL_WORLD }, \ { CTRY_ESTONIA, "ee", DMN_ETSI1_WORLD }, \ { CTRY_EGYPT, "eg", DMN_NULL_WORLD }, \ { CTRY_SPAIN, "es", DMN_ETSI1_WORLD }, \ { CTRY_FRANCE2, "f2", DMN_ETSI3_WORLD }, \ { CTRY_FINLAND, "fi", DMN_ETSI1_WORLD }, \ { CTRY_FAEROE_ISLANDS, "fo", DMN_NULL_WORLD }, \ { CTRY_FRANCE, "fr", DMN_ETSI3_WORLD }, \ { CTRY_GEORGIA, "ge", DMN_ETSI4_WORLD }, \ { CTRY_GREECE, "gr", DMN_NULL_WORLD }, \ { CTRY_GUATEMALA, "gt", DMN_FCC1_FCCA }, \ { CTRY_HONG_KONG, "hk", DMN_FCC2_WORLD }, \ { CTRY_HONDURAS, "hn", DMN_NULL_WORLD }, \ { CTRY_CROATIA, "hr", DMN_ETSI3_WORLD }, \ { CTRY_HUNGARY, "hu", DMN_ETSI2_WORLD }, \ { CTRY_INDONESIA, "id", DMN_NULL_WORLD }, \ { CTRY_IRELAND, "ie", DMN_ETSI1_WORLD }, \ { CTRY_ISRAEL, "il", DMN_NULL_WORLD }, \ { CTRY_INDIA, "in", DMN_NULL_WORLD }, \ { CTRY_IRAQ, "iq", DMN_NULL_WORLD }, \ { CTRY_IRAN, "ir", DMN_APL1_WORLD }, \ { CTRY_ICELAND, "is", DMN_ETSI1_WORLD }, \ { CTRY_ITALY, "it", DMN_ETSI1_WORLD }, \ { CTRY_JAPAN1, "j1", DMN_MKK1_MKKB }, \ { CTRY_JAPAN2, "j2", DMN_MKK1_FCCA }, \ { CTRY_JAPAN3, "j3", DMN_MKK2_MKKA }, \ { CTRY_JAPAN4, "j4", DMN_MKK1_MKKA1 }, \ { CTRY_JAPAN5, "j5", DMN_MKK1_MKKA2 }, \ { CTRY_JAMAICA, "jm", DMN_NULL_WORLD }, \ { CTRY_JORDAN, "jo", DMN_NULL_WORLD }, \ { CTRY_JAPAN, "jp", DMN_MKK1_MKKA }, \ { CTRY_KOREA_ROC2, "k2", DMN_APL2_APLD }, \ { CTRY_KENYA, "ke", DMN_NULL_WORLD }, \ { CTRY_KOREA_NORTH, "kp", DMN_APL2_WORLD }, \ { CTRY_KOREA_ROC, "kr", DMN_APL2_WORLD }, \ { CTRY_KUWAIT, "kw", DMN_NULL_WORLD }, \ { CTRY_KAZAKHSTAN, "kz", DMN_NULL_WORLD }, \ { CTRY_LEBANON, "lb", DMN_NULL_WORLD }, \ { CTRY_LIECHTENSTEIN, "li", DMN_ETSI2_WORLD }, \ { CTRY_SRI_LANKA, "lk", DMN_NULL_WORLD }, \ { CTRY_LITHUANIA, "lt", DMN_ETSI1_WORLD }, \ { CTRY_LUXEMBOURG, "lu", DMN_ETSI1_WORLD }, \ { CTRY_LATVIA, "lv", DMN_NULL_WORLD }, \ { CTRY_LIBYA, "ly", DMN_NULL_WORLD }, \ { CTRY_MOROCCO, "ma", DMN_NULL_WORLD }, \ { CTRY_MONACO, "mc", DMN_ETSI4_WORLD }, \ { CTRY_MACEDONIA, "mk", DMN_NULL_WORLD }, \ { CTRY_MACAU, "mo", DMN_FCC2_WORLD }, \ { CTRY_MEXICO, "mx", DMN_FCC1_FCCA }, \ { CTRY_MALAYSIA, "my", DMN_NULL_WORLD }, \ { CTRY_NICARAGUA, "ni", DMN_NULL_WORLD }, \ { CTRY_NETHERLANDS, "nl", DMN_ETSI1_WORLD }, \ { CTRY_NORWAY, "no", DMN_ETSI1_WORLD }, \ { CTRY_NEW_ZEALAND, "nz", DMN_FCC2_ETSIC }, \ { CTRY_OMAN, "om", DMN_NULL_WORLD }, \ { CTRY_PANAMA, "pa", DMN_FCC1_FCCA }, \ { CTRY_PERU, "pe", DMN_NULL_WORLD }, \ { CTRY_PHILIPPINES, "ph", DMN_FCC1_WORLD }, \ { CTRY_PAKISTAN, "pk", DMN_NULL_WORLD }, \ { CTRY_POLAND, "pl", DMN_ETSI1_WORLD }, \ { CTRY_PUERTO_RICO, "pr", DMN_FCC1_FCCA }, \ { CTRY_PORTUGAL, "pt", DMN_ETSI1_WORLD }, \ { CTRY_PARAGUAY, "py", DMN_NULL_WORLD }, \ { CTRY_QATAR, "qa", DMN_NULL_WORLD }, \ { CTRY_ROMANIA, "ro", DMN_NULL_WORLD }, \ { CTRY_RUSSIA, "ru", DMN_NULL_WORLD }, \ { CTRY_SAUDI_ARABIA, "sa", DMN_NULL_WORLD }, \ { CTRY_SWEDEN, "se", DMN_ETSI1_WORLD }, \ { CTRY_SINGAPORE, "sg", DMN_APL4_WORLD }, \ { CTRY_SLOVENIA, "si", DMN_ETSI1_WORLD }, \ { CTRY_SLOVAKIA, "sk", DMN_ETSI3_WORLD }, \ { CTRY_EL_SALVADOR, "sv", DMN_NULL_WORLD }, \ { CTRY_SYRIA, "sy", DMN_NULL_WORLD }, \ { CTRY_THAILAND, "th", DMN_APL2_WORLD }, \ { CTRY_TUNISIA, "tn", DMN_ETSI3_WORLD }, \ { CTRY_TURKEY, "tr", DMN_ETSI3_WORLD }, \ { CTRY_TRINIDAD_Y_TOBAGO, "tt", DMN_ETSI4_WORLD }, \ { CTRY_TAIWAN, "tw", DMN_APL3_WORLD }, \ { CTRY_UKRAINE, "ua", DMN_NULL_WORLD }, \ { CTRY_UNITED_KINGDOM, "uk", DMN_ETSI1_WORLD }, \ { CTRY_UNITED_STATES, "us", DMN_FCC1_FCCA }, \ { CTRY_URUGUAY, "uy", DMN_APL2_WORLD }, \ { CTRY_UZBEKISTAN, "uz", DMN_FCC3_FCCA }, \ { CTRY_VENEZUELA, "ve", DMN_APL2_ETSIC }, \ { CTRY_VIET_NAM, "vn", DMN_NULL_WORLD }, \ { CTRY_YEMEN, "ye", DMN_NULL_WORLD }, \ { CTRY_SOUTH_AFRICA, "za", DMN_ETSI1_WORLD }, \ { CTRY_ZIMBABWE, "zw", DMN_NULL_WORLD }, \ } enum ieee80211_ctl { CTL_11A = 0x00, CTL_11B = 0x01, CTL_11G = 0x02, CTL_TURBO = 0x03, CTL_TURBO_G = 0x04, CTL_FCC = 0x10, CTL_ETSI = 0x30, CTL_MKK = 0x40, CTL_NONE = 0xff }; #define IEEE80211_CHANNELS_2GHZ_MIN 2412 /* 2GHz channel 1 */ #define IEEE80211_CHANNELS_2GHZ_MAX 2732 /* 2GHz channel 26 */ struct ieee80211_regchannel { u_int16_t rc_channel; u_int32_t rc_domain; u_int32_t rc_mode; }; #define IEEE80211_CHANNELS_2GHZ { \ { 2412, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2417, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2422, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2427, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2432, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2437, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2442, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2447, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2452, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2457, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2462, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2467, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2472, DMN_APLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ \ { 2432, DMN_ETSIB, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2442, DMN_ETSIB, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ \ { 2412, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2417, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2422, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2427, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2432, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2442, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2447, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2452, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2457, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2462, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2467, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2472, DMN_ETSIC, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ \ { 2412, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2417, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2422, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2427, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2432, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2442, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2447, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2452, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2457, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2462, DMN_FCCA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ \ { 2412, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2417, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2422, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2427, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2432, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2437, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2442, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2447, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2452, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2457, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2462, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2467, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2472, DMN_MKKA, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2484, DMN_MKKA, IEEE80211_CHAN_CCK }, \ \ { 2412, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2417, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2422, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2427, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2432, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2442, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2447, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2452, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2457, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2462, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2467, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ { 2472, DMN_WORLD, IEEE80211_CHAN_CCK|IEEE80211_CHAN_OFDM }, \ } #define IEEE80211_CHANNELS_5GHZ_MIN 5005 /* 5GHz channel 1 */ #define IEEE80211_CHANNELS_5GHZ_MAX 6100 /* 5GHz channel 220 */ #define IEEE80211_CHANNELS_5GHZ { \ { 5745, DMN_APL1, IEEE80211_CHAN_OFDM }, \ { 5765, DMN_APL1, IEEE80211_CHAN_OFDM }, \ { 5785, DMN_APL1, IEEE80211_CHAN_OFDM }, \ { 5805, DMN_APL1, IEEE80211_CHAN_OFDM }, \ { 5825, DMN_APL1, IEEE80211_CHAN_OFDM }, \ \ { 5745, DMN_APL2, IEEE80211_CHAN_OFDM }, \ { 5765, DMN_APL2, IEEE80211_CHAN_OFDM }, \ { 5785, DMN_APL2, IEEE80211_CHAN_OFDM }, \ { 5805, DMN_APL2, IEEE80211_CHAN_OFDM }, \ \ { 5280, DMN_APL3, IEEE80211_CHAN_OFDM }, \ { 5300, DMN_APL3, IEEE80211_CHAN_OFDM }, \ { 5320, DMN_APL3, IEEE80211_CHAN_OFDM }, \ { 5745, DMN_APL3, IEEE80211_CHAN_OFDM }, \ { 5765, DMN_APL3, IEEE80211_CHAN_OFDM }, \ { 5785, DMN_APL3, IEEE80211_CHAN_OFDM }, \ { 5805, DMN_APL3, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_APL4, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_APL4, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_APL4, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_APL4, IEEE80211_CHAN_OFDM }, \ { 5745, DMN_APL4, IEEE80211_CHAN_OFDM }, \ { 5765, DMN_APL4, IEEE80211_CHAN_OFDM }, \ { 5785, DMN_APL4, IEEE80211_CHAN_OFDM }, \ { 5805, DMN_APL4, IEEE80211_CHAN_OFDM }, \ { 5825, DMN_APL4, IEEE80211_CHAN_OFDM }, \ \ { 5745, DMN_APL5, IEEE80211_CHAN_OFDM }, \ { 5765, DMN_APL5, IEEE80211_CHAN_OFDM }, \ { 5785, DMN_APL5, IEEE80211_CHAN_OFDM }, \ { 5805, DMN_APL5, IEEE80211_CHAN_OFDM }, \ { 5825, DMN_APL5, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5260, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5280, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5300, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5320, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5500, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5520, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5540, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5560, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5580, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5600, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5620, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5640, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5660, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5680, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ { 5700, DMN_ETSI1, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_ETSI2, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_ETSI2, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_ETSI2, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_ETSI2, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_ETSI3, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_ETSI3, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_ETSI3, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_ETSI3, IEEE80211_CHAN_OFDM }, \ { 5260, DMN_ETSI3, IEEE80211_CHAN_OFDM }, \ { 5280, DMN_ETSI3, IEEE80211_CHAN_OFDM }, \ { 5300, DMN_ETSI3, IEEE80211_CHAN_OFDM }, \ { 5320, DMN_ETSI3, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_ETSI4, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_ETSI4, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_ETSI4, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_ETSI4, IEEE80211_CHAN_OFDM }, \ { 5260, DMN_ETSI4, IEEE80211_CHAN_OFDM }, \ { 5280, DMN_ETSI4, IEEE80211_CHAN_OFDM }, \ { 5300, DMN_ETSI4, IEEE80211_CHAN_OFDM }, \ { 5320, DMN_ETSI4, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_ETSI5, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_ETSI5, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_ETSI5, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_ETSI5, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5260, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5280, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5500, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5520, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5540, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5560, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5580, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5600, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5620, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5640, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5660, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5680, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ { 5700, DMN_ETSI6, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5260, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5280, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5300, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5320, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5745, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5765, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5785, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5805, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ { 5825, DMN_FCC1, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5260, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5280, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5300, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5320, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5745, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5765, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5785, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5805, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ { 5825, DMN_FCC2, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5260, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5280, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5300, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5320, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5500, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5520, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5540, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5560, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5580, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5600, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5620, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5640, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5660, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5680, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5700, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5745, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5765, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5785, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5805, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ { 5825, DMN_FCC3, IEEE80211_CHAN_OFDM }, \ \ { 5170, DMN_MKK1, IEEE80211_CHAN_OFDM }, \ { 5190, DMN_MKK1, IEEE80211_CHAN_OFDM }, \ { 5210, DMN_MKK1, IEEE80211_CHAN_OFDM }, \ { 5230, DMN_MKK1, IEEE80211_CHAN_OFDM }, \ \ { 5040, DMN_MKK2, IEEE80211_CHAN_OFDM }, \ { 5060, DMN_MKK2, IEEE80211_CHAN_OFDM }, \ { 5080, DMN_MKK2, IEEE80211_CHAN_OFDM }, \ { 5170, DMN_MKK2, IEEE80211_CHAN_OFDM }, \ { 5190, DMN_MKK2, IEEE80211_CHAN_OFDM }, \ { 5210, DMN_MKK2, IEEE80211_CHAN_OFDM }, \ { 5230, DMN_MKK2, IEEE80211_CHAN_OFDM }, \ \ { 5180, DMN_WORLD, IEEE80211_CHAN_OFDM }, \ { 5200, DMN_WORLD, IEEE80211_CHAN_OFDM }, \ { 5220, DMN_WORLD, IEEE80211_CHAN_OFDM }, \ { 5240, DMN_WORLD, IEEE80211_CHAN_OFDM }, \ } //__BEGIN_DECLS extern u_int16_t ieee80211_name2countrycode(const char *); extern u_int32_t ieee80211_name2regdomain(const char *); extern const char *ieee80211_countrycode2name(u_int16_t); extern const char *ieee80211_regdomain2name(u_int32_t); extern u_int32_t ieee80211_regdomain2flag(u_int16_t, u_int16_t); extern u_int32_t ieee80211_countrycode2regdomain(u_int16_t); //__END_DECLS #endif /* _NET80211_IEEE80211_REGDOMAIN_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_rssadapt.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. */ /* $OpenBSD: ieee80211_rssadapt.c,v 1.11 2014/12/23 03:24:08 tedu Exp $ */ /* $NetBSD: ieee80211_rssadapt.c,v 1.7 2004/05/25 04:33:59 dyoung Exp $ */ /*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #ifdef interpolate #undef interpolate #endif #define interpolate(parm, old, new) \ ((parm##_old * (old) + \ (parm##_denom - parm##_old) * (new)) / parm##_denom) #ifdef IEEE80211_DEBUG static struct timeval lastrateadapt; /* time of last rate adaptation msg */ static int currssadaptps = 0; /* rate-adaptation msgs this second */ static int ieee80211_adaptrate = 4; /* rate-adaptation max msgs/sec */ #define RSSADAPT_DO_PRINT() \ ((ieee80211_rssadapt_debug > 0) && \ ppsratecheck(&lastrateadapt, &currssadaptps, ieee80211_adaptrate)) #define RSSADAPT_PRINTF(X) \ if (RSSADAPT_DO_PRINT()) \ XYLog X int ieee80211_rssadapt_debug = 0; #else #define RSSADAPT_DO_PRINT() (0) #define RSSADAPT_PRINTF(X) #endif static const struct ieee80211_rssadapt_expavgctl master_expavgctl = { .rc_decay_denom = 16, .rc_decay_old = 15, .rc_thresh_denom = 8, .rc_thresh_old = 4, .rc_avgrssi_denom = 8, .rc_avgrssi_old = 4 }; int ieee80211_rssadapt_choose(struct ieee80211_rssadapt *ra, const struct ieee80211_rateset *rs, const struct ieee80211_frame *wh, u_int len, int fixed_rate, const char *dvname, int do_not_adapt) { u_int16_t (*thrs)[IEEE80211_RATE_SIZE]; int flags = 0, i, rateidx = 0, thridx, top; if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) flags |= IEEE80211_RATE_BASIC; for (i = 0, top = IEEE80211_RSSADAPT_BKT0; i < IEEE80211_RSSADAPT_BKTS; i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { thridx = i; if (len <= top) break; } thrs = &ra->ra_rate_thresh[thridx]; if (fixed_rate != -1) { if ((rs->rs_rates[fixed_rate] & flags) == flags) { rateidx = fixed_rate; goto out; } flags |= IEEE80211_RATE_BASIC; i = fixed_rate; } else i = rs->rs_nrates; while (--i >= 0) { rateidx = i; if ((rs->rs_rates[i] & flags) != flags) continue; if (do_not_adapt) break; if ((*thrs)[i] < ra->ra_avg_rssi) break; } out: #ifdef IEEE80211_DEBUG if (ieee80211_rssadapt_debug && dvname != NULL) { XYLog("%s: dst %s threshold[%d, %d.%d] %d < %d\n", dvname, ether_sprintf((u_int8_t *)wh->i_addr1), len, (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) / 2, (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) * 5 % 10, (*thrs)[rateidx], ra->ra_avg_rssi); } #endif /* IEEE80211_DEBUG */ return rateidx; } void ieee80211_rssadapt_updatestats(struct ieee80211_rssadapt *ra) { long interval; ra->ra_pktrate = (ra->ra_pktrate + 10 * (ra->ra_nfail + ra->ra_nok)) / 2; ra->ra_nfail = ra->ra_nok = 0; /* a node is eligible for its rate to be raised every 1/10 to 10 * seconds, more eligible in proportion to recent packet rates. */ interval = MAX(100000, 10000000 / MAX(1, 10 * ra->ra_pktrate)); ra->ra_raise_interval.tv_sec = interval / (1000 * 1000); ra->ra_raise_interval.tv_usec = interval % (1000 * 1000); } void ieee80211_rssadapt_input(struct ieee80211com *ic, const struct ieee80211_node *ni, struct ieee80211_rssadapt *ra, int rssi) { #ifdef IEEE80211_DEBUG int last_avg_rssi = ra->ra_avg_rssi; #endif ra->ra_avg_rssi = interpolate(master_expavgctl.rc_avgrssi, ra->ra_avg_rssi, (rssi << 8)); RSSADAPT_PRINTF(("%s: src %s rssi %d avg %d -> %d\n", ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr), rssi, last_avg_rssi, ra->ra_avg_rssi)); } /* * Adapt the data rate to suit the conditions. When a transmitted * packet is dropped after IEEE80211_RSSADAPT_RETRY_LIMIT retransmissions, * raise the RSS threshold for transmitting packets of similar length at * the same data rate. */ void ieee80211_rssadapt_lower_rate(struct ieee80211com *ic, const struct ieee80211_node *ni, struct ieee80211_rssadapt *ra, const struct ieee80211_rssdesc *id) { const struct ieee80211_rateset *rs = &ni->ni_rates; u_int16_t last_thr; u_int i, thridx, top; ra->ra_nfail++; if (id->id_rateidx >= rs->rs_nrates) { RSSADAPT_PRINTF(("ieee80211_rssadapt_lower_rate: " "%s rate #%d > #%d out of bounds\n", ether_sprintf((u_int8_t *)ni->ni_macaddr), id->id_rateidx, rs->rs_nrates - 1)); return; } for (i = 0, top = IEEE80211_RSSADAPT_BKT0; i < IEEE80211_RSSADAPT_BKTS; i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { thridx = i; if (id->id_len <= top) break; } last_thr = ra->ra_rate_thresh[thridx][id->id_rateidx]; ra->ra_rate_thresh[thridx][id->id_rateidx] = interpolate(master_expavgctl.rc_thresh, last_thr, (id->id_rssi << 8)); RSSADAPT_PRINTF(("%s: dst %s rssi %d threshold[%d, %d.%d] %d -> %d\n", ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr), id->id_rssi, id->id_len, (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) / 2, (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) * 5 % 10, last_thr, ra->ra_rate_thresh[thridx][id->id_rateidx])); } void ieee80211_rssadapt_raise_rate(struct ieee80211com *ic, struct ieee80211_rssadapt *ra, const struct ieee80211_rssdesc *id) { u_int16_t (*thrs)[IEEE80211_RATE_SIZE], newthr, oldthr; const struct ieee80211_node *ni = id->id_node; const struct ieee80211_rateset *rs = &ni->ni_rates; int i, rate, top; #ifdef IEEE80211_DEBUG int j; #endif ra->ra_nok++; if (!ratecheck(&ra->ra_last_raise, &ra->ra_raise_interval)) return; for (i = 0, top = IEEE80211_RSSADAPT_BKT0; i < IEEE80211_RSSADAPT_BKTS; i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) { thrs = &ra->ra_rate_thresh[i]; if (id->id_len <= top) break; } if (id->id_rateidx + 1 < rs->rs_nrates && (*thrs)[id->id_rateidx + 1] > (*thrs)[id->id_rateidx]) { rate = (rs->rs_rates[id->id_rateidx + 1] & IEEE80211_RATE_VAL); RSSADAPT_PRINTF(("%s: threshold[%d, %d.%d] decay %d ", ic->ic_if.if_xname, IEEE80211_RSSADAPT_BKT0 << (IEEE80211_RSSADAPT_BKTPOWER * i), rate / 2, rate * 5 % 10, (*thrs)[id->id_rateidx + 1])); oldthr = (*thrs)[id->id_rateidx + 1]; if ((*thrs)[id->id_rateidx] == 0) newthr = ra->ra_avg_rssi; else newthr = (*thrs)[id->id_rateidx]; (*thrs)[id->id_rateidx + 1] = interpolate(master_expavgctl.rc_decay, oldthr, newthr); RSSADAPT_PRINTF(("-> %d\n", (*thrs)[id->id_rateidx + 1])); } #ifdef IEEE80211_DEBUG if (RSSADAPT_DO_PRINT()) { XYLog("%s: dst %s thresholds\n", ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr)); for (i = 0; i < IEEE80211_RSSADAPT_BKTS; i++) { XYLog("%d-byte", IEEE80211_RSSADAPT_BKT0 << (IEEE80211_RSSADAPT_BKTPOWER * i)); for (j = 0; j < rs->rs_nrates; j++) { rate = (rs->rs_rates[j] & IEEE80211_RATE_VAL); XYLog(", T[%d.%d] = %d", rate / 2, rate * 5 % 10, ra->ra_rate_thresh[i][j]); } XYLog("\n"); } } #endif /* IEEE80211_DEBUG */ } ================================================ FILE: itl80211/openbsd/net80211/ieee80211_rssadapt.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_rssadapt.h,v 1.5 2010/07/17 16:25:09 damien Exp $ */ /* $NetBSD: ieee80211_rssadapt.h,v 1.3 2004/05/06 03:03:20 dyoung Exp $ */ /*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #ifndef _NET80211_IEEE80211_RSSADAPT_H_ #define _NET80211_IEEE80211_RSSADAPT_H_ /* Data-rate adaptation loosely based on "Link Adaptation Strategy * for IEEE 802.11 WLAN via Received Signal Strength Measurement" * by Javier del Prado Pavon and Sunghyun Choi. */ /* Buckets for frames 0-128 bytes long, 129-1024, 1025-maximum. */ #define IEEE80211_RSSADAPT_BKTS 3 #define IEEE80211_RSSADAPT_BKT0 128 #define IEEE80211_RSSADAPT_BKTPOWER 3 /* 2**_BKTPOWER */ #define ieee80211_rssadapt_thresh_new \ (ieee80211_rssadapt_thresh_denom - ieee80211_rssadapt_thresh_old) #define ieee80211_rssadapt_decay_new \ (ieee80211_rssadapt_decay_denom - ieee80211_rssadapt_decay_old) #define ieee80211_rssadapt_avgrssi_new \ (ieee80211_rssadapt_avgrssi_denom - ieee80211_rssadapt_avgrssi_old) struct ieee80211_rssadapt_expavgctl { /* RSS threshold decay. */ u_int rc_decay_denom; u_int rc_decay_old; /* RSS threshold update. */ u_int rc_thresh_denom; u_int rc_thresh_old; /* RSS average update. */ u_int rc_avgrssi_denom; u_int rc_avgrssi_old; }; struct ieee80211_rssadapt { /* exponential average RSSI << 8 */ u_int16_t ra_avg_rssi; /* Tx failures in this update interval */ u_int32_t ra_nfail; /* Tx successes in this update interval */ u_int32_t ra_nok; /* exponential average packets/second */ u_int32_t ra_pktrate; /* RSSI threshold for each Tx rate */ u_int16_t ra_rate_thresh[IEEE80211_RSSADAPT_BKTS] [IEEE80211_RATE_SIZE]; struct timeval ra_last_raise; struct timeval ra_raise_interval; }; /* Properties of a Tx packet, for link adaptation. */ struct ieee80211_rssdesc { u_int id_len; /* Tx packet length */ u_int id_rateidx; /* index into ni->ni_rates */ struct ieee80211_node *id_node; /* destination STA MAC */ u_int8_t id_rssi; /* destination STA avg RSS @ * Tx time */ }; void ieee80211_rssadapt_updatestats(struct ieee80211_rssadapt *); void ieee80211_rssadapt_input(struct ieee80211com *, const struct ieee80211_node *, struct ieee80211_rssadapt *, int); void ieee80211_rssadapt_lower_rate(struct ieee80211com *, const struct ieee80211_node *, struct ieee80211_rssadapt *, const struct ieee80211_rssdesc *); void ieee80211_rssadapt_raise_rate(struct ieee80211com *, struct ieee80211_rssadapt *, const struct ieee80211_rssdesc *); int ieee80211_rssadapt_choose(struct ieee80211_rssadapt *, const struct ieee80211_rateset *, const struct ieee80211_frame *, u_int, int, const char *, int); #ifdef IEEE80211_DEBUG extern int ieee80211_rssadapt_debug; #endif /* IEEE80211_DEBUG */ #endif /* _NET80211_IEEE80211_RSSADAPT_H_ */ ================================================ FILE: itl80211/openbsd/net80211/ieee80211_var.h ================================================ /* * 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. */ /* $OpenBSD: ieee80211_var.h,v 1.97 2019/07/29 10:50:09 stsp Exp $ */ /* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/net80211/ieee80211_var.h,v 1.15 2004/04/05 22:10:26 sam Exp $ */ #ifndef _NET80211_IEEE80211_VAR_H_ #define _NET80211_IEEE80211_VAR_H_ /* * Definitions for IEEE 802.11 drivers. */ #define explicit_bzero bzero #define nitems(arr) (sizeof(arr) / sizeof((arr)[0])) #ifdef SMALL_KERNEL #define IEEE80211_STA_ONLY 1 #endif #include #include #include #include #include #include #include #include #include #include #include #include /* for ieee80211_stats */ #include #include #include #define IEEE80211_DEBUG #define _KASSERT(exp) KASSERT(exp, "") #define CLUSTER_SIZE 4096 #define ALIGNED_POINTER(p,t) 1 extern int TX_TYPE_MGMT; extern int TX_TYPE_FRAME; extern int _stop(struct kmod_info*, void*); extern int _start(struct kmod_info*, void*); extern int timingsafe_bcmp(const void *b1, const void *b2, size_t n); /* * ppsratecheck(): packets (or events) per second limitation. */ static int ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) { struct timeval tv, delta; int rv; microuptime(&tv); timersub(&tv, lasttime, &delta); /* * check for 0,0 is so that the message will be seen at least once. * if more than one second have passed since the last update of * lasttime, reset the counter. * * we do increment *curpps even in *curpps < maxpps case, as some may * try to use *curpps for stat purposes as well. */ if (maxpps == 0) rv = 0; else if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || delta.tv_sec >= 1) { *lasttime = tv; *curpps = 0; rv = 1; } else if (maxpps < 0) rv = 1; else if (*curpps < maxpps) rv = 1; else rv = 0; #if 1 /*DIAGNOSTIC?*/ /* be careful about wrap-around */ if (*curpps + 1 > *curpps) *curpps = *curpps + 1; #else /* * assume that there's not too many calls to this function. * not sure if the assumption holds, as it depends on *caller's* * behavior, not the behavior of this function. * IMHO it is wrong to make assumption on the caller's behavior, * so the above #if is #if 1, not #ifdef DIAGNOSTIC. */ *curpps = *curpps + 1; #endif return (rv); } /* * ratecheck(): simple time-based rate-limit checking. see ratecheck(9) * for usage and rationale. */ static int ratecheck(struct timeval *lasttime, const struct timeval *mininterval) { struct timeval tv, delta; int rv = 0; getmicrouptime(&tv); timersub(&tv, lasttime, &delta); /* * check for 0,0 is so that the message will be seen at least once, * even if interval is huge. */ if (timercmp(&delta, mininterval, >=) || (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { *lasttime = tv; rv = 1; } return (rv); } static u_int32_t ether_crc32_le_update(u_int32_t crc, const u_int8_t *buf, size_t len) { static const u_int32_t crctab[] = { 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; size_t i; for (i = 0; i < len; i++) { crc ^= buf[i]; crc = (crc >> 4) ^ crctab[crc & 0xf]; crc = (crc >> 4) ^ crctab[crc & 0xf]; } return (crc); } static char* ether_sprintf(const uint8_t *ap) { static char etherbuf[18]; snprintf(etherbuf, sizeof (etherbuf), "%6D", ap, ":"); return (etherbuf); } static void array_sprintf(char *output, uint8_t output_size, const uint8_t *array, const uint8_t len) { uint8_t index = 0; for (index = 0; index < len; index++) { snprintf(output, output_size, "0x%02x ", array++); } } #define IEEE80211_CHAN_MAX 255 #define IEEE80211_CHAN_ANY 0xffff /* token for ``any channel'' */ #define IEEE80211_CHAN_ANYC \ ((struct ieee80211_channel *) NULL) #define IEEE80211_TXPOWER_MAX 100 /* max power */ #define IEEE80211_TXPOWER_MIN -50 /* kill radio (if possible) */ #define IEEE80211_RSSI_THRES_2GHZ (-60) /* in dBm */ #define IEEE80211_RSSI_THRES_5GHZ (-70) /* in dBm */ #define IEEE80211_RSSI_THRES_RATIO_2GHZ 50 /* in percent */ #define IEEE80211_RSSI_THRES_RATIO_5GHZ 40 /* in percent */ #define IEEE80211_BGSCAN_FAIL_MAX 360 /* units of 500 msec */ /* * Missed beacon threshold: An access point has disappeared if this amount * of consecutive beacons have been missed. * This value needs to be high enough to avoid frequent re-connects to APs * which suffer from occasional packet loss, and low enough to avoid a long * delay before we start scanning when an AP has actually disappeared. * * The beacon interval is variable, but generally in the order of 100ms. * So 30 beacons implies a grace period of about 3 seconds before we start * searching for a new AP. */ #define IEEE80211_BEACON_MISS_THRES 30 /* units of beacons */ enum ieee80211_phytype { IEEE80211_T_DS, /* direct sequence spread spectrum */ IEEE80211_T_OFDM, /* frequency division multiplexing */ IEEE80211_T_XR /* extended range mode */ }; #define IEEE80211_T_CCK IEEE80211_T_DS /* more common nomenclature */ /* XXX not really a mode; there are really multiple PHY's */ enum ieee80211_phymode { IEEE80211_MODE_AUTO = 0, /* autoselect */ IEEE80211_MODE_11A = 1, /* 5GHz, OFDM */ IEEE80211_MODE_11B = 2, /* 2GHz, CCK */ IEEE80211_MODE_11G = 3, /* 2GHz, OFDM */ IEEE80211_MODE_11N = 4, /* 2GHz/5GHz, OFDM/HT */ IEEE80211_MODE_11AC = 5, /* 5GHz, OFDM/VHT */ IEEE80211_MODE_11AX = 6, /* 5GHz, 6GHz, HE */ }; #define IEEE80211_MODE_MAX (IEEE80211_MODE_11AX+1) enum ieee80211_opmode { IEEE80211_M_STA = 1, /* infrastructure station */ #ifndef IEEE80211_STA_ONLY IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */ IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */ IEEE80211_M_HOSTAP = 6, /* Software Access Point */ #endif IEEE80211_M_MONITOR = 8 /* Monitor mode */ }; /* * 802.11g protection mode. */ enum ieee80211_protmode { IEEE80211_PROT_NONE = 0, /* no protection */ IEEE80211_PROT_CTSONLY = 1, /* CTS to self */ IEEE80211_PROT_RTSCTS = 2 /* RTS-CTS */ }; /* * Channels are specified by frequency and attributes. */ struct ieee80211_channel { u_int16_t ic_freq; /* setting in MHz */ u_int32_t ic_flags; /* see below */ u_int16_t ic_center_freq1; u_int16_t ic_center_freq2; }; /* * Channel attributes (XXX must keep in sync with radiotap flags). */ #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel */ #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_XR 0x1000 /* Extended range OFDM channel */ #define IEEE80211_CHAN_HT20 0x00010000 /* HT 20 channel */ #define IEEE80211_CHAN_HT40U 0x00020000 /* HT 40 channel w/ ext above */ #define IEEE80211_CHAN_HT40D 0x00040000 /* HT 40 channel w/ ext below */ #define IEEE80211_CHAN_DFS 0x00080000 /* DFS required */ #define IEEE80211_CHAN_4MSXMIT 0x00100000 /* 4ms limit on frame length */ #define IEEE80211_CHAN_NOADHOC 0x00200000 /* adhoc mode not allowed */ #define IEEE80211_CHAN_NOHOSTAP 0x00400000 /* hostap mode not allowed */ #define IEEE80211_CHAN_11D 0x00800000 /* 802.11d required */ #define IEEE80211_CHAN_VHT20 0x01000000 /* VHT20 channel */ #define IEEE80211_CHAN_VHT40U 0x02000000 /* VHT40 channel, ext above */ #define IEEE80211_CHAN_VHT40D 0x04000000 /* VHT40 channel, ext below */ #define IEEE80211_CHAN_VHT80 0x08000000 /* VHT80 channel */ #define IEEE80211_CHAN_VHT160 0x10000000 /* VHT160 channel */ #define IEEE80211_CHAN_VHT80_80 0x20000000 /* VHT80+80 channel */ #define IEEE80211_CHAN_HT40 (IEEE80211_CHAN_HT40U | IEEE80211_CHAN_HT40D) #define IEEE80211_CHAN_HT (IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40) #define IEEE80211_CHAN_VHT40 (IEEE80211_CHAN_VHT40U | IEEE80211_CHAN_VHT40D) #define IEEE80211_CHAN_VHT (IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_VHT40 \ | IEEE80211_CHAN_VHT80 | IEEE80211_CHAN_VHT80_80 \ | IEEE80211_CHAN_VHT160) #define IEEE80211_CHAN_ALL \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ | \ IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_PASSIVE | IEEE80211_CHAN_DYN | IEEE80211_CHAN_XR | \ IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT) /* * Useful combinations of channel characteristics. */ #define IEEE80211_CHAN_A \ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) #define IEEE80211_CHAN_B \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) #define IEEE80211_CHAN_PUREG \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) #define IEEE80211_CHAN_G \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) #define IEEE80211_IS_CHAN_A(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) #define IEEE80211_IS_CHAN_B(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) #define IEEE80211_IS_CHAN_PUREG(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG) #define IEEE80211_IS_CHAN_G(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) #define IEEE80211_IS_CHAN_N(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_HT) != 0) #define IEEE80211_IS_CHAN_AC(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_VHT) != 0) #define IEEE80211_IS_CHAN_2GHZ(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0) #define IEEE80211_IS_CHAN_5GHZ(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_5GHZ) != 0) #define IEEE80211_IS_CHAN_OFDM(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_OFDM) != 0) #define IEEE80211_IS_CHAN_CCK(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_CCK) != 0) #define IEEE80211_IS_CHAN_XR(_c) \ (((_c)->ic_flags & IEEE80211_CHAN_XR) != 0) /* * EDCA AC parameters. */ struct ieee80211_edca_ac_params { u_int8_t ac_ecwmin; /* CWmin = 2^ECWmin - 1 */ u_int8_t ac_ecwmax; /* CWmax = 2^ECWmax - 1 */ u_int8_t ac_aifsn; u_int16_t ac_txoplimit; /* 32TU */ #define IEEE80211_TXOP_TO_US(txop) ((txop) * 32) u_int8_t ac_acm; }; extern const struct ieee80211_edca_ac_params ieee80211_edca_table[IEEE80211_MODE_MAX][EDCA_NUM_AC]; extern const struct ieee80211_edca_ac_params ieee80211_qap_edca_table[IEEE80211_MODE_MAX][EDCA_NUM_AC]; #define IEEE80211_DEFRAG_SIZE 3 /* must be >= 3 according to spec */ /* * Entry in the fragment cache. */ struct ieee80211_defrag { CTimeout* df_to; mbuf_t df_m; u_int16_t df_seq; u_int8_t df_frag; }; #define IEEE80211_PROTO_NONE 0 #define IEEE80211_PROTO_RSN (1 << 0) #define IEEE80211_PROTO_WPA (1 << 1) #define IEEE80211_SCAN_UNLOCKED 0x0 #define IEEE80211_SCAN_LOCKED 0x1 #define IEEE80211_SCAN_REQUEST 0x2 #define IEEE80211_SCAN_RESUME 0x4 #define IEEE80211_GROUP_NKID 6 struct ieee80211com { struct arpcom ic_ac; LIST_ENTRY(ieee80211com) ic_list; /* chain of all ieee80211com */ void (*ic_recv_mgmt)(struct ieee80211com *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *, int); int (*ic_send_mgmt)(struct ieee80211com *, struct ieee80211_node *, int, int, int); int (*ic_newstate)(struct ieee80211com *, enum ieee80211_state, int); int (*ic_newauth)(struct ieee80211com *, struct ieee80211_node *, int, uint16_t); void (*ic_newassoc)(struct ieee80211com *, struct ieee80211_node *, int); void (*ic_node_leave)(struct ieee80211com *, struct ieee80211_node *); void (*ic_updateslot)(struct ieee80211com *); void (*ic_updateedca)(struct ieee80211com *); void (*ic_updatedtim)(struct ieee80211com *); void (*ic_set_tim)(struct ieee80211com *, int, int); int (*ic_set_key)(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); void (*ic_delete_key)(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); int (*ic_ampdu_tx_start)(struct ieee80211com *, struct ieee80211_node *, u_int8_t); void (*ic_ampdu_tx_stop)(struct ieee80211com *, struct ieee80211_node *, u_int8_t); int (*ic_ampdu_rx_start)(struct ieee80211com *, struct ieee80211_node *, u_int8_t); void (*ic_ampdu_rx_stop)(struct ieee80211com *, struct ieee80211_node *, u_int8_t); void (*ic_updateprot)(struct ieee80211com *); int (*ic_bgscan_start)(struct ieee80211com *); /* The channel width has changed (20<->2040) */ void (*ic_update_chw)(struct ieee80211com *); void (*ic_event_handler)(struct ieee80211com *, int, void *); CTimeout* ic_bgscan_timeout; uint32_t ic_bgscan_fail; u_int8_t ic_myaddr[IEEE80211_ADDR_LEN]; struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX]; struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1]; u_char ic_chan_avail[howmany(IEEE80211_CHAN_MAX,NBBY)]; u_char ic_chan_active[howmany(IEEE80211_CHAN_MAX, NBBY)]; u_char ic_chan_scan[howmany(IEEE80211_CHAN_MAX,NBBY)]; struct mbuf_queue ic_mgtq; struct mbuf_queue ic_pwrsaveq; u_int8_t ic_scan_count; /* count scans */ u_int32_t ic_flags; /* state flags */ u_int32_t ic_xflags; /* more flags */ u_int32_t ic_userflags; /* yet more flags */ u_int32_t ic_caps; /* capabilities */ u_int16_t ic_modecaps; /* set of mode capabilities */ u_int16_t ic_curmode; /* current mode */ enum ieee80211_phytype ic_phytype; /* XXX wrong for multi-mode */ enum ieee80211_opmode ic_opmode; /* operation mode */ enum ieee80211_state ic_state; /* 802.11 state */ u_int32_t *ic_aid_bitmap; u_int16_t ic_max_aid; enum ieee80211_protmode ic_protmode; /* 802.11g/n protection mode */ struct ifmedia ic_media; /* interface media config */ caddr_t ic_rawbpf; /* packet filter structure */ struct ieee80211_node *ic_bss; /* information for this node */ struct ieee80211_channel *ic_ibss_chan; int ic_fixed_rate; /* index to ic_sup_rates[] */ u_int16_t ic_rtsthreshold; u_int16_t ic_fragthreshold; u_int ic_scangen; /* gen# for timeout scan */ struct ieee80211_node *(*ic_node_alloc)(struct ieee80211com *); void (*ic_node_free)(struct ieee80211com *, struct ieee80211_node *); void (*ic_node_copy)(struct ieee80211com *, struct ieee80211_node *, const struct ieee80211_node *); u_int8_t (*ic_node_getrssi)(struct ieee80211com *, const struct ieee80211_node *); int (*ic_node_checkrssi)(struct ieee80211com *, const struct ieee80211_node *); u_int8_t ic_max_rssi; struct ieee80211_tree ic_tree; int ic_nnodes; /* length of ic_nnodes */ int ic_max_nnodes; /* max length of ic_nnodes */ u_int16_t ic_lintval; /* listen interval */ int16_t ic_txpower; /* tx power setting (dBm) */ int ic_bmissthres; /* beacon miss threshold */ int ic_mgt_timer; /* mgmt timeout */ #ifndef IEEE80211_STA_ONLY CTimeout* ic_inact_timeout; /* node inactivity timeout */ CTimeout* ic_node_cache_timeout; #endif int ic_des_esslen; u_int8_t ic_des_essid[IEEE80211_NWID_LEN]; struct ieee80211_channel *ic_des_chan; /* desired channel */ u_int8_t ic_des_bssid[IEEE80211_ADDR_LEN]; #ifdef USE_APPLE_SUPPLICANT u_int8_t ic_rsn_ie_override[257]; #endif u_int16_t ic_deauth_reason; u_int16_t ic_assoc_status; struct ieee80211_key ic_nw_keys[IEEE80211_GROUP_NKID]; int ic_def_txkey; /* group data key index */ #define ic_wep_txkey ic_def_txkey int ic_igtk_kid; /* IGTK key index */ u_int32_t ic_iv; /* initial vector for wep */ struct ieee80211_stats ic_stats; /* statistics */ struct timeval ic_last_merge_print; /* for rate-limiting * IBSS merge print-outs */ struct ieee80211_edca_ac_params ic_edca_ac[EDCA_NUM_AC]; u_int ic_edca_updtcount; u_int16_t ic_tid_noack; u_int8_t ic_globalcnt[EAPOL_KEY_NONCE_LEN]; u_int8_t ic_nonce[EAPOL_KEY_NONCE_LEN]; u_int8_t ic_psk[IEEE80211_PMK_LEN]; CTimeout* ic_rsn_timeout; int ic_tkip_micfail; u_int64_t ic_tkip_micfail_last_tsc; #ifndef IEEE80211_STA_ONLY CTimeout* ic_tkip_micfail_timeout; #endif TAILQ_HEAD(, ieee80211_pmk) ic_pmksa; /* PMKSA cache */ u_int ic_rsnprotos; u_int ic_rsnakms; u_int ic_rsnciphers; enum ieee80211_cipher ic_rsngroupcipher; enum ieee80211_cipher ic_rsngroupmgmtcipher; #ifdef notyet struct ieee80211_defrag ic_defrag[IEEE80211_DEFRAG_SIZE]; int ic_defrag_cur; #endif u_int8_t *ic_tim_bitmap; u_int ic_tim_len; u_int ic_tim_mcast_pending; u_int ic_dtim_period; u_int ic_dtim_count; u_int32_t ic_txbfcaps; u_int16_t ic_htcaps; uint32_t ic_vhtcaps; uint32_t ic_hecaps; u_int8_t ic_ampdu_params; u_int8_t ic_sup_mcs[howmany(80, NBBY)]; u_int16_t ic_max_rxrate; /* in Mb/s, 0 <= rate <= 1023 */ u_int8_t ic_tx_mcs_set; u_int16_t ic_htxcaps; u_int8_t ic_aselcaps; u_int8_t ic_dialog_token; int ic_fixed_mcs; uint64_t ic_last_cache_scan_ts; uint16_t ic_vht_tx_mcs_map; uint16_t ic_vht_rx_mcs_map; uint16_t ic_vht_tx_highest; uint16_t ic_vht_rx_highest; uint16_t ic_vht_sup_mcs[howmany(80, NBBY)]; /* HE state */ struct ieee80211_he_cap_elem ic_he_cap_elem; /* Fixed portion of the HE capabilities element. */ struct ieee80211_he_mcs_nss_supp ic_he_mcs_nss_supp; /* The supported NSS/MCS combinations. */ uint8_t ic_ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN]; /* Holds the PPE Thresholds data. */ TAILQ_HEAD(, ieee80211_ess) ic_ess; }; #define ic_if ic_ac.ac_if #define ic_softc ic_if.if_softc /* list of APs we want to automatically use */ /* all data is copied from struct ieee80211com */ struct ieee80211_ess { /* nwid */ int esslen; u_int8_t essid[IEEE80211_NWID_LEN]; /* clear/wep/wpa */ u_int32_t flags; /* nwkey */ struct ieee80211_key nw_keys[IEEE80211_GROUP_NKID]; int def_txkey; /* wpakey */ u_int8_t psk[IEEE80211_PMK_LEN]; u_int rsnprotos; u_int rsnakms; u_int rsnciphers; enum ieee80211_cipher rsngroupcipher; TAILQ_ENTRY(ieee80211_ess) ess_next; }; #define IEEE80211_ADDR_EQ(a1,a2) (memcmp(a1,a2,IEEE80211_ADDR_LEN) == 0) #define IEEE80211_ADDR_COPY(dst,src) memcpy(dst,src,IEEE80211_ADDR_LEN) /* ic_flags */ #define IEEE80211_F_ASCAN 0x00000001 /* STATUS: active scan */ #define IEEE80211_F_SIBSS 0x00000002 /* STATUS: start IBSS */ #define IEEE80211_F_WEPON 0x00000100 /* CONF: WEP enabled */ #define IEEE80211_F_IBSSON 0x00000200 /* CONF: IBSS creation enable */ #define IEEE80211_F_PMGTON 0x00000400 /* CONF: Power mgmt enable */ #define IEEE80211_F_DESBSSID 0x00000800 /* CONF: des_bssid is set */ #define IEEE80211_F_ROAMING 0x00002000 /* CONF: roaming enabled */ #define IEEE80211_F_TXPMGT 0x00018000 /* STATUS: tx power */ #define IEEE80211_F_TXPOW_OFF 0x00000000 /* TX Power: radio disabled */ #define IEEE80211_F_TXPOW_FIXED 0x00008000 /* TX Power: fixed rate */ #define IEEE80211_F_TXPOW_AUTO 0x00010000 /* TX Power: undefined */ #define IEEE80211_F_SHSLOT 0x00020000 /* STATUS: short slot time */ #define IEEE80211_F_SHPREAMBLE 0x00040000 /* STATUS: short preamble */ #define IEEE80211_F_QOS 0x00080000 /* CONF: QoS enabled */ #define IEEE80211_F_USEPROT 0x00100000 /* STATUS: protection enabled */ #define IEEE80211_F_RSNON 0x00200000 /* CONF: RSN enabled */ #define IEEE80211_F_PSK 0x00400000 /* CONF: pre-shared key set */ #define IEEE80211_F_COUNTERM 0x00800000 /* STATUS: countermeasures */ #define IEEE80211_F_MFPR 0x01000000 /* CONF: MFP required */ #define IEEE80211_F_HTON 0x02000000 /* CONF: HT enabled */ #define IEEE80211_F_PBAR 0x04000000 /* CONF: PBAC required */ #define IEEE80211_F_BGSCAN 0x08000000 /* STATUS: background scan */ #define IEEE80211_F_AUTO_JOIN 0x10000000 /* CONF: auto-join active */ #define IEEE80211_F_VHTON 0x20000000 /* CONF: VHT enabled */ #define IEEE80211_F_DISABLE_BG_AUTO_CONNECT 0x40000000 /* CONF: disable auto connect to wifi when doing backgound scan */ #define IEEE80211_F_HEON 0x80000000 /* CONF: HE enabled */ /* ic_xflags */ #define IEEE80211_F_TX_MGMT_ONLY 0x00000001 /* leave data frames on ifq */ /* ic_caps */ #define IEEE80211_C_WEP 0x00000001 /* CAPABILITY: WEP available */ #define IEEE80211_C_IBSS 0x00000002 /* CAPABILITY: IBSS available */ #define IEEE80211_C_PMGT 0x00000004 /* CAPABILITY: Power mgmt */ #define IEEE80211_C_HOSTAP 0x00000008 /* CAPABILITY: HOSTAP avail */ #define IEEE80211_C_AHDEMO 0x00000010 /* CAPABILITY: Old Adhoc Demo */ #define IEEE80211_C_APPMGT 0x00000020 /* CAPABILITY: AP power mgmt */ #define IEEE80211_C_TXPMGT 0x00000040 /* CAPABILITY: tx power mgmt */ #define IEEE80211_C_SHSLOT 0x00000080 /* CAPABILITY: short slottime */ #define IEEE80211_C_SHPREAMBLE 0x00000100 /* CAPABILITY: short preamble */ #define IEEE80211_C_MONITOR 0x00000200 /* CAPABILITY: monitor mode */ #define IEEE80211_C_SCANALL 0x00000400 /* CAPABILITY: scan all chan */ #define IEEE80211_C_QOS 0x00000800 /* CAPABILITY: QoS avail */ #define IEEE80211_C_RSN 0x00001000 /* CAPABILITY: RSN avail */ #define IEEE80211_C_MFP 0x00002000 /* CAPABILITY: MFP avail */ #define IEEE80211_C_RAWCTL 0x00004000 /* CAPABILITY: raw ctl */ #define IEEE80211_C_SCANALLBAND 0x00008000 /* CAPABILITY: scan all bands */ #define IEEE80211_C_TX_AMPDU 0x00010000 /* CAPABILITY: send A-MPDU */ #define IEEE80211_C_AMSDU_IN_AMPDU 0x00020000 /* CAPABILITY: Rx AMSDU inside AMPDU */ #define IEEE80211_C_TX_AMPDU_SETUP_IN_HW 0x00040000 /* CAPABILITY: BA negotiation in HW */ #define IEEE80211_C_SUPPORTS_VHT_EXT_NSS_BW 0x00080000 /* CAPABILITY: for 160mhz */ #define IEEE80211_C_TX_AMPDU_SETUP_IN_RS 0x00100000 /* flags for ieee80211_fix_rate() */ #define IEEE80211_F_DOSORT 0x00000001 /* sort rate list */ #define IEEE80211_F_DOFRATE 0x00000002 /* use fixed rate */ #define IEEE80211_F_DONEGO 0x00000004 /* calc negotiated rate */ #define IEEE80211_F_DODEL 0x00000008 /* delete ignore rate */ #define IEEE80211_EVT_STA_ASSOC_DONE 1 #define IEEE80211_EVT_STA_DEAUTH 2 #define IEEE80211_EVT_COUNTRY_CODE_UPDATE 3 #define IEEE80211_EVT_SCAN_DONE 4 void ieee80211_ifattach(struct _ifnet *, IOEthernetController *controller); void ieee80211_ifdetach(struct _ifnet *); void ieee80211_channel_init(struct _ifnet *); void ieee80211_media_init(struct _ifnet *); int ieee80211_media_change(struct _ifnet *); void ieee80211_media_status(struct _ifnet *, struct ifmediareq *); int ieee80211_ioctl(struct _ifnet *, u_long, caddr_t); int ieee80211_get_rate(struct ieee80211com *); void ieee80211_watchdog(struct _ifnet *); int ieee80211_fix_rate(struct ieee80211com *, struct ieee80211_node *, int); uint64_t ieee80211_rate2media(struct ieee80211com *, int, enum ieee80211_phymode); int ieee80211_media2rate(uint64_t); uint64_t ieee80211_mcs2media(struct ieee80211com *, int, enum ieee80211_phymode); int ieee80211_media2mcs(uint64_t); u_int8_t ieee80211_rate2plcp(u_int8_t, enum ieee80211_phymode); u_int8_t ieee80211_plcp2rate(u_int8_t, enum ieee80211_phymode); u_int ieee80211_mhz2ieee(u_int, u_int); u_int ieee80211_chan2ieee(struct ieee80211com *, const struct ieee80211_channel *); u_int ieee80211_ieee2mhz(u_int, u_int); int ieee80211_min_basic_rate(struct ieee80211com *); int ieee80211_max_basic_rate(struct ieee80211com *); int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); enum ieee80211_phymode ieee80211_next_mode(struct _ifnet *); enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *, const struct ieee80211_channel *); void ieee80211_disable_wep(struct ieee80211com *); void ieee80211_disable_rsn(struct ieee80211com *); int ieee80211_add_ess(struct ieee80211com *, struct ieee80211_join *); void ieee80211_del_ess(struct ieee80211com *, char *, int, int); void ieee80211_set_ess(struct ieee80211com *, struct ieee80211_ess *, struct ieee80211_node *); void ieee80211_deselect_ess(struct ieee80211com *); struct ieee80211_ess *ieee80211_get_ess(struct ieee80211com *, const char *, int); void ieee80211_begin_cache_bgscan(struct _ifnet *); extern int ieee80211_cache_size; #endif /* _NET80211_IEEE80211_VAR_H_ */ ================================================ FILE: itl80211/openbsd/net80211/timeout.c ================================================ // // timeout.cpp // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/30. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef timeout_cpp #define timeout_cpp #include #include extern IOWorkLoop *_fWorkloop; extern IOCommandGate *_fCommandGate; int splnet() { return 1; } void splx(int s) { } void timeout_set(CTimeout **t, void (*fn)(void *), void *arg) { _fCommandGate->runAction(&CTimeout::timeout_set, t, (void*)fn, arg); } int timeout_add_msec(CTimeout **to, int msecs) { return _fCommandGate->runAction(&CTimeout::timeout_add_msec, to, _fWorkloop, &msecs) == kIOReturnSuccess ? 1 : 0; } int timeout_add_sec(CTimeout **to, int secs) { return timeout_add_msec(to, secs * 1000); } int timeout_add_usec(CTimeout **to, int usecs) { return timeout_add_msec(to, (int) usecs / 1000); } int timeout_del(CTimeout **to) { // IOLog("timeout_del\n"); return _fCommandGate->runAction(&CTimeout::timeout_del, to, _fWorkloop) == kIOReturnSuccess ? 1 : 0; } int timeout_free(CTimeout **to) { return _fCommandGate->runAction(&CTimeout::timeout_free, to, _fWorkloop) == kIOReturnSuccess ? 1 : 0; } int timeout_pending(CTimeout **to) { return _fCommandGate->runAction(&CTimeout::timeout_pending, to) == kIOReturnSuccess ? 1 : 0; } int timeout_initialized(CTimeout **to) { return (*to) != NULL; } #endif /* timeout_cpp */ ================================================ FILE: itl80211/openbsd/sys/CTimeout.hpp ================================================ // // CTimeout.h // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/30. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef CTimeout_h #define CTimeout_h #include #include class CTimeout : public OSObject { OSDeclareDefaultStructors(CTimeout) public: static void timeoutOccurred(OSObject* owner, IOTimerEventSource* timer); static IOReturn timeout_add_msec(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); static IOReturn timeout_del(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); static IOReturn timeout_free(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); static IOReturn timeout_set(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); static IOReturn timeout_pending(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); public: IOTimerEventSource* tm; void (*to_func)(void *); /* function to call */ void *to_arg; /* function argument */ bool isPending; }; #endif /* CTimeout_h */ ================================================ FILE: itl80211/openbsd/sys/_arc4random.h ================================================ // // _arc4random.h // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/22. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef _arc4random_h #define _arc4random_h #include #include #include #include #include /* Add platform entropy 32 bytes (256 bits) at a time. */ #define ADD_ENTROPY 32 /* Re-seed from the platform RNG after generating this many bytes. */ #define BYTES_BEFORE_RESEED 1600000 static inline u_int32_t arc4random() { u_int32_t r; read_random(&r, sizeof(r)); return r; } static inline void arc4random_buf(void *buf, size_t n) { read_random(buf, (u_int)n); } static inline u_int32_t arc4random_uniform(u_int32_t upper_bound) { u_int32_t r, min; if (upper_bound < 2) return 0; /* 2**32 % x == (2**32 - x) % x */ min = -upper_bound % upper_bound; /* * This could theoretically loop forever but each retry has * p > 0.5 (worst case, usually far better) of selecting a * number inside the range we need, so it should rarely need * to re-roll. */ for (;;) { r = arc4random(); if (r >= min) break; } return r % upper_bound; } #endif ================================================ FILE: itl80211/openbsd/sys/_buf.h ================================================ // // _buf.h // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/25. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef _buf_h #define _buf_h /* Macros to clear/set/test flags. */ #define SET(t, f) (t) |= (f) #define CLR(t, f) (t) &= ~(f) #define ISSET(t, f) ((t) & (f)) #endif /* _buf_h */ ================================================ FILE: itl80211/openbsd/sys/_clock.h ================================================ /* * Copyright (C) 2021 钟先耀 * * 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. */ #ifndef _clock_h #define _clock_h #include #define hz 100 #define ticks \ ({ \ uint64_t t; \ uint64_t k; \ clock_get_uptime(&t); \ absolutetime_to_nanoseconds(t, &k); \ (int)((k * hz) / 1000000000); \ }) #endif /* _clock_h */ ================================================ FILE: itl80211/openbsd/sys/_if_ether.h ================================================ // // _if_ether.h // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/22. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ /* $OpenBSD: if_ether.h,v 1.76 2019/07/17 16:46:18 mpi Exp $ */ /* $NetBSD: if_ether.h,v 1.22 1996/05/11 13:00:00 mycroft Exp $ */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if_ether.h 8.1 (Berkeley) 6/10/93 */ #ifndef _if_ether_h #define _if_ether_h #include #include #include #include #include #include #include #include #include #define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ #define ETHER_IS_BROADCAST(addr) \ (((addr)[0] & (addr)[1] & (addr)[2] & \ (addr)[3] & (addr)[4] & (addr)[5]) == 0xff) #define ETHER_IS_ANYADDR(addr) \ (((addr)[0] | (addr)[1] | (addr)[2] | \ (addr)[3] | (addr)[4] | (addr)[5]) == 0x00) #define ETHER_IS_EQ(a1, a2) (memcmp((a1), (a2), ETHER_ADDR_LEN) == 0) #define ETHER_ADDR_LEN 6 /* * Ethernet CRC32 polynomials (big- and little-endian verions). */ #define ETHER_CRC_POLY_LE 0xedb88320 #define ETHER_CRC_POLY_BE 0x04c11db6 /* * Values for if_link_state. */ #define LINK_STATE_UNKNOWN 0 /* link unknown */ #define LINK_STATE_INVALID 1 /* link invalid */ #define LINK_STATE_DOWN 2 /* link is down */ #define LINK_STATE_KALIVE_DOWN 3 /* keepalive reports down */ #define LINK_STATE_UP 4 /* link is up */ #define LINK_STATE_HALF_DUPLEX 5 /* link is up and half duplex */ #define LINK_STATE_FULL_DUPLEX 6 /* link is up and full duplex */ #define LINK_STATE_IS_UP(_s) \ ((_s) >= LINK_STATE_UP || (_s) == LINK_STATE_UNKNOWN) #define splassert(x) (x) /* * Status bit descriptions for the various interface types. */ struct if_status_description { u_char ifs_type; u_char ifs_state; const char *ifs_string; }; #define LINK_STATE_DESC_MATCH(_ifs, _t, _s) \ (((_ifs)->ifs_type == (_t) || (_ifs)->ifs_type == 0) && \ (_ifs)->ifs_state == (_s)) #define LINK_STATE_DESCRIPTIONS { \ { IFT_ETHER, LINK_STATE_DOWN, "no carrier" }, \ \ { IFT_IEEE80211, LINK_STATE_DOWN, "no network" }, \ \ { IFT_PPP, LINK_STATE_DOWN, "no carrier" }, \ \ { IFT_CARP, LINK_STATE_DOWN, "backup" }, \ { IFT_CARP, LINK_STATE_UP, "master" }, \ { IFT_CARP, LINK_STATE_HALF_DUPLEX, "master" }, \ { IFT_CARP, LINK_STATE_FULL_DUPLEX, "master" }, \ \ { 0, LINK_STATE_UP, "active" }, \ { 0, LINK_STATE_HALF_DUPLEX, "active" }, \ { 0, LINK_STATE_FULL_DUPLEX, "active" }, \ \ { 0, LINK_STATE_UNKNOWN, "unknown" }, \ { 0, LINK_STATE_INVALID, "invalid" }, \ { 0, LINK_STATE_DOWN, "down" }, \ { 0, LINK_STATE_KALIVE_DOWN, "keepalive down" }, \ { 0, 0, NULL } \ } /* * Length of interface description, including terminating '\0'. */ #define IFDESCRSIZE 64 /* * Ethernet multicast address structure. There is one of these for each * multicast address or range of multicast addresses that we are supposed * to listen to on a particular interface. They are kept in a linked list, * rooted in the interface's arpcom structure. (This really has nothing to * do with ARP, or with the Internet address family, but this appears to be * the minimally-disrupting place to put it.) */ struct ether_multi { u_int8_t enm_addrlo[ETHER_ADDR_LEN]; /* low or only address of range */ u_int8_t enm_addrhi[ETHER_ADDR_LEN]; /* high or only address of range */ u_int enm_refcount; /* no. claims to this addr/range */ LIST_ENTRY(ether_multi) enm_list; }; struct _ifnet { /* and the entries */ IOEthernetInterface *iface; IOEthernetController* controller; int if_link_state; void *if_softc; // struct refcnt if_refcnt; int if_hdrlen; TAILQ_ENTRY(_ifnet) if_list; /* [k] all struct ifnets are chained */ TAILQ_HEAD(, ifaddr) if_addrlist; /* [N] list of addresses per if */ TAILQ_HEAD(, ifmaddr) if_maddrlist; /* [N] list of multicast records */ TAILQ_HEAD(, ifg_list) if_groups; /* [N] list of groups per if */ // struct hook_desc_head *if_addrhooks; /* [I] address change callbacks */ // struct hook_desc_head *if_linkstatehooks; /* [I] link change callbacks*/ // struct hook_desc_head *if_detachhooks; /* [I] detach callbacks */ /* [I] check or clean routes (+ or -)'d */ void (*if_rtrequest)(struct _ifnet *, int, struct rtentry *); char if_xname[IFNAMSIZ]; /* [I] external name (name + unit) */ int if_pcount; /* [k] # of promiscuous listeners */ unsigned int if_bridgeidx; /* [k] used by bridge ports */ caddr_t if_bpf; /* packet filter structure */ caddr_t if_switchport; /* used by switch ports */ caddr_t if_mcast; /* used by multicast code */ caddr_t if_mcast6; /* used by IPv6 multicast code */ caddr_t if_pf_kif; /* pf interface abstraction */ IONetworkStats *netStat; ///extra uint32_t if_ierrors; uint32_t if_oerrors; uint32_t if_ipackets; uint32_t if_imcasts; int if_ibytes; // union { // struct srpl carp_s; /* carp if list (used by !carp ifs) */ // struct _ifnet *carp_d; /* ptr to carpdev (used by carp ifs) */ // } if_carp_ptr; #define if_carp if_carp_ptr.carp_s #define if_carpdev if_carp_ptr.carp_d unsigned int if_index; /* [I] unique index for this if */ short if_timer; /* time 'til if_watchdog called */ unsigned short if_flags; /* [N] up/down, broadcast, etc. */ int if_xflags; /* [N] extra softnet flags */ struct if_data if_data; /* stats and other data about if */ struct cpumem *if_counters; /* per cpu stats */ uint32_t if_hardmtu; /* [d] maximum MTU device supports */ char if_description[IFDESCRSIZE]; /* [c] interface description */ u_short if_rtlabelid; /* [c] next route label */ uint8_t if_priority; /* [c] route priority offset */ uint8_t if_llprio; /* [N] link layer priority */ CTimeout* if_slowtimo; /* [I] watchdog timeout */ // struct task if_watchdogtask; /* [I] watchdog task */ // struct task if_linkstatetask; /* [I] task to do route updates */ // // /* procedure handles */ // SRPL_HEAD(, ifih) if_inputs; /* [k] input routines (dequeue) */ int (*if_output)(struct _ifnet *, mbuf_t, struct sockaddr *, struct rtentry *); /* output routine (enqueue) */ /* link level output function */ int (*if_ll_output)(struct _ifnet *, mbuf_t, struct sockaddr *, struct rtentry *); int (*if_enqueue)(struct _ifnet *, mbuf_t); void (*if_start)(struct _ifnet *); /* initiate output */ int (*if_ioctl)(struct _ifnet *, u_long, caddr_t); /* ioctl hook */ void (*if_watchdog)(struct _ifnet *); /* timer routine */ int (*if_wol)(struct _ifnet *, int); /* WoL routine **/ /* queues */ struct _ifqueue if_snd; /* transmit queue */ struct _ifqueue **if_ifqs; /* [I] pointer to an array of sndqs */ void (*if_qstart)(struct _ifqueue *); unsigned int if_nifqs; /* [I] number of output queues */ unsigned int if_txmit; /* [c] txmitigation amount */ // struct ifiqueue if_rcv; /* rx/input queue */ // struct ifiqueue **if_iqs; /* [I] pointer to the array of iqs */ unsigned int if_niqs; /* [I] number of input queues */ struct sockaddr_dl *if_sadl; /* [N] pointer to our sockaddr_dl */ void *if_afdata[AF_MAX]; }; /* * Structure shared between the ethernet driver modules and * the address resolution code. For example, each ec_softc or il_softc * begins with this structure. */ struct arpcom { struct _ifnet ac_if; /* network-visible interface */ u_int8_t ac_enaddr[ETHER_ADDR_LEN]; /* ethernet hardware address */ char ac__pad[2]; /* pad for some machines */ LIST_HEAD(, ether_multi) ac_multiaddrs; /* list of multicast addrs */ int ac_multicnt; /* length of ac_multiaddrs */ int ac_multirangecnt; /* number of mcast ranges */ void *ac_trunkport; }; static inline u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static inline u_int8_t etheranyaddr[ETHER_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define senderr(e) { error = (e); goto bad;} static inline int if_setlladdr(struct _ifnet *ifp, const uint8_t *lladdr) { memcpy(((struct arpcom *)ifp)->ac_enaddr, lladdr, ETHER_ADDR_LEN); return (0); } static inline int if_attach(struct _ifnet *ifp) { ifp->if_link_state = -1; return 0; } static inline int if_detach(struct _ifnet *ifp) { ifp->if_link_state = -1; return 0; } static inline int ether_ifattach(struct _ifnet *ifp, IOEthernetInterface *iface) { ifp->iface = iface; } static inline void ether_ifdetach(struct _ifnet *ifp) { ifp->iface = NULL; } #endif /* _if_ether_h */ ================================================ FILE: itl80211/openbsd/sys/_if_media.h ================================================ /* $OpenBSD: if_media.h,v 1.41 2018/02/04 10:06:51 stsp Exp $ */ /* $NetBSD: if_media.h,v 1.22 2000/02/17 21:53:16 sommerfeld Exp $ */ /*- * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1997 * Jonathan Stone and Jason R. Thorpe. All rights reserved. * * This software is derived from information provided by Matt Thomas. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Jonathan Stone * and Jason R. Thorpe for the NetBSD Project. * 4. The names of the authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _NET2_IF_MEDIA_H_ #define _NET2_IF_MEDIA_H_ #include #include #include #define _KERNEL #ifdef _KERNEL struct ifmediareq { char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ uint64_t ifm_current; /* get/set current media options */ uint64_t ifm_mask; /* don't care mask */ uint64_t ifm_status; /* media status */ uint64_t ifm_active; /* active options */ int ifm_count; /* # entries in ifm_ulist array */ uint64_t *ifm_ulist; /* media words */ }; /* * Driver callbacks for media status and change requests. */ typedef int (*ifm_change_cb_t)(struct _ifnet *); typedef void (*ifm_stat_cb_t)(struct _ifnet *, struct ifmediareq *); /* * In-kernel representation of a single supported media type. */ struct ifmedia_entry { TAILQ_ENTRY(ifmedia_entry) ifm_list; uint64_t ifm_media; /* description of this media attachment */ u_int ifm_data; /* for driver-specific use */ void *ifm_aux; /* for driver-specific use */ }; /* * One of these goes into a network interface's softc structure. * It is used to keep general media state. */ struct ifmedia { uint64_t ifm_mask; /* mask of changes we don't care about */ uint64_t ifm_media; /* current user-set media word */ struct ifmedia_entry *ifm_cur; /* currently selected media */ TAILQ_HEAD(, ifmedia_entry) ifm_list; /* list of all supported media */ ifm_change_cb_t ifm_change; /* media change driver callback */ ifm_stat_cb_t ifm_status; /* media status driver callback */ }; // /* Initialize an interface's struct if_media field. */ static inline void ifmedia_init(struct ifmedia *ifm, uint64_t dontcare_mask) { TAILQ_INIT(&ifm->ifm_list); ifm->ifm_cur = NULL; ifm->ifm_media = 0; ifm->ifm_mask = dontcare_mask; /* IF don't-care bits */ } // ///* Add one supported medium to a struct ifmedia. */ //void ifmedia_add(struct ifmedia *, uint64_t, int, void *); // ///* Add an array (of ifmedia_entry) media to a struct ifmedia. */ //void ifmedia_list_add(struct ifmedia *, struct ifmedia_entry *, // int); // ///* Common ioctl function for getting/setting media, called by driver. */ //int ifmedia_ioctl(struct _ifnet *, struct ifreq *, struct ifmedia *, // u_long); // ///* Locate a media entry */ //struct ifmedia_entry *ifmedia_match(struct ifmedia *, uint64_t, uint64_t); // ///* Compute baudrate for a given media. */ //uint64_t ifmedia_baudrate(uint64_t); #endif /*_KERNEL */ /* * if_media Options word: * Bits Use * ---- ------- * 0-7 Media subtype MAX SUBTYPE == 255! * 8-15 Media type * 16-31 Type specific options * 32-39 Mode (for multi-mode devices) * 40-55 Shared (global) options * 56-63 Instance */ /* * Ethernet */ #define IFM_ETHER 0x0000000000000100ULL #define IFM_10_T 3 /* 10BaseT - RJ45 */ #define IFM_10_2 4 /* 10Base2 - Thinnet */ #define IFM_10_5 5 /* 10Base5 - AUI */ #define IFM_100_TX 6 /* 100BaseTX - RJ45 */ #define IFM_100_FX 7 /* 100BaseFX - Fiber */ #define IFM_100_T4 8 /* 100BaseT4 - 4 pair cat 3 */ #define IFM_100_VG 9 /* 100VG-AnyLAN */ #define IFM_100_T2 10 /* 100BaseT2 */ #define IFM_1000_SX 11 /* 1000BaseSX - multi-mode fiber */ #define IFM_10_STP 12 /* 10BaseT over shielded TP */ #define IFM_10_FL 13 /* 10BaseFL - Fiber */ #define IFM_1000_LX 14 /* 1000baseLX - single-mode fiber */ #define IFM_1000_CX 15 /* 1000baseCX - 150ohm STP */ #define IFM_1000_T 16 /* 1000baseT - 4 pair cat 5 */ #define IFM_1000_TX IFM_1000_T /* for backwards compatibility */ #define IFM_HPNA_1 17 /* HomePNA 1.0 (1Mb/s) */ #define IFM_10G_LR 18 /* 10GBase-LR - single-mode fiber */ #define IFM_10G_SR 19 /* 10GBase-SR - multi-mode fiber */ #define IFM_10G_CX4 20 /* 10GBase-CX4 - copper */ #define IFM_2500_SX 21 /* 2500baseSX - multi-mode fiber */ #define IFM_10G_T 22 /* 10GbaseT cat 6 */ #define IFM_10G_SFP_CU 23 /* 10G SFP+ direct attached cable */ #define IFM_10G_LRM 24 /* 10GBase-LRM 850nm Multi-mode */ #define IFM_40G_CR4 25 /* 40GBase-CR4 */ #define IFM_40G_SR4 26 /* 40GBase-SR4 */ #define IFM_40G_LR4 27 /* 40GBase-LR4 */ #define IFM_1000_KX 28 /* 1000Base-KX backplane */ #define IFM_10G_KX4 29 /* 10GBase-KX4 backplane */ #define IFM_10G_KR 30 /* 10GBase-KR backplane */ #define IFM_10G_CR1 31 /* 10GBase-CR1 Twinax splitter */ #define IFM_20G_KR2 32 /* 20GBase-KR2 backplane */ #define IFM_2500_KX 33 /* 2500Base-KX backplane */ #define IFM_2500_T 34 /* 2500Base-T - RJ45 (NBaseT) */ #define IFM_5000_T 35 /* 5000Base-T - RJ45 (NBaseT) */ #define IFM_1000_SGMII 36 /* 1G media interface */ #define IFM_10G_SFI 37 /* 10G media interface */ #define IFM_40G_XLPPI 38 /* 40G media interface */ #define IFM_1000_CX_SGMII 39 /* 1000Base-CX-SGMII */ #define IFM_40G_KR4 40 /* 40GBase-KR4 */ #define IFM_10G_ER 41 /* 10GBase-ER */ #define IFM_100G_CR4 42 /* 100GBase-CR4 */ #define IFM_100G_SR4 43 /* 100GBase-SR4 */ #define IFM_100G_KR4 44 /* 100GBase-KR4 */ #define IFM_100G_LR4 45 /* 100GBase-LR4 */ #define IFM_56G_R4 46 /* 56GBase-R4 */ #define IFM_25G_CR 47 /* 25GBase-CR */ #define IFM_25G_KR 48 /* 25GBase-KR */ #define IFM_25G_SR 49 /* 25GBase-SR */ #define IFM_50G_CR2 50 /* 50GBase-CR2 */ #define IFM_50G_KR2 51 /* 50GBase-KR2 */ #define IFM_25G_LR 52 /* 25GBase-LR */ #define IFM_25G_ER 53 /* 25GBase-ER */ #define IFM_10G_AOC 54 /* 10G Active Optical Cable */ #define IFM_25G_AOC 55 /* 25G Active Optical Cable */ #define IFM_40G_AOC 56 /* 40G Active Optical Cable */ #define IFM_100G_AOC 57 /* 100G Active Optical Cable */ #define IFM_ETH_MASTER 0x0000000000010000ULL /* master mode (1000baseT) */ #define IFM_ETH_RXPAUSE 0x0000000000020000ULL /* receive PAUSE frames */ #define IFM_ETH_TXPAUSE 0x0000000000040000ULL /* transmit PAUSE frames */ /* * FDDI */ #define IFM_FDDI 0x0000000000000300ULL #define IFM_FDDI_SMF 3 /* Single-mode fiber */ #define IFM_FDDI_MMF 4 /* Multi-mode fiber */ #define IFM_FDDI_UTP 5 /* CDDI / UTP */ #define IFM_FDDI_DA 0x00000100 /* Dual attach / single attach */ /* * IEEE 802.11 Wireless */ #define IFM_IEEE80211 0x0000000000000400ULL #define IFM_IEEE80211_FH1 3 /* Frequency Hopping 1Mbps */ #define IFM_IEEE80211_FH2 4 /* Frequency Hopping 2Mbps */ #define IFM_IEEE80211_DS2 5 /* Direct Sequence 2Mbps */ #define IFM_IEEE80211_DS5 6 /* Direct Sequence 5Mbps*/ #define IFM_IEEE80211_DS11 7 /* Direct Sequence 11Mbps*/ #define IFM_IEEE80211_DS1 8 /* Direct Sequence 1Mbps*/ #define IFM_IEEE80211_DS22 9 /* Direct Sequence 22Mbps */ #define IFM_IEEE80211_OFDM6 10 /* OFDM 6Mbps */ #define IFM_IEEE80211_OFDM9 11 /* OFDM 9Mbps */ #define IFM_IEEE80211_OFDM12 12 /* OFDM 12Mbps */ #define IFM_IEEE80211_OFDM18 13 /* OFDM 18Mbps */ #define IFM_IEEE80211_OFDM24 14 /* OFDM 24Mbps */ #define IFM_IEEE80211_OFDM36 15 /* OFDM 36Mbps */ #define IFM_IEEE80211_OFDM48 16 /* OFDM 48Mbps */ #define IFM_IEEE80211_OFDM54 17 /* OFDM 54Mbps */ #define IFM_IEEE80211_OFDM72 18 /* OFDM 72Mbps */ #define IFM_IEEE80211_HT_MCS0 19 /* 11n MCS 0 */ #define IFM_IEEE80211_HT_MCS1 20 /* 11n MCS 1 */ #define IFM_IEEE80211_HT_MCS2 21 /* 11n MCS 2 */ #define IFM_IEEE80211_HT_MCS3 22 /* 11n MCS 3 */ #define IFM_IEEE80211_HT_MCS4 23 /* 11n MCS 4 */ #define IFM_IEEE80211_HT_MCS5 24 /* 11n MCS 5 */ #define IFM_IEEE80211_HT_MCS6 25 /* 11n MCS 6 */ #define IFM_IEEE80211_HT_MCS7 26 /* 11n MCS 7 */ #define IFM_IEEE80211_HT_MCS8 27 /* 11n MCS 8 */ #define IFM_IEEE80211_HT_MCS9 28 /* 11n MCS 9 */ #define IFM_IEEE80211_HT_MCS10 29 /* 11n MCS 10 */ #define IFM_IEEE80211_HT_MCS11 30 /* 11n MCS 11 */ #define IFM_IEEE80211_HT_MCS12 31 /* 11n MCS 12 */ #define IFM_IEEE80211_HT_MCS13 32 /* 11n MCS 13 */ #define IFM_IEEE80211_HT_MCS14 33 /* 11n MCS 14 */ #define IFM_IEEE80211_HT_MCS15 34 /* 11n MCS 15 */ #define IFM_IEEE80211_HT_MCS16 35 /* 11n MCS 16 */ #define IFM_IEEE80211_HT_MCS17 36 /* 11n MCS 17 */ #define IFM_IEEE80211_HT_MCS18 37 /* 11n MCS 18 */ #define IFM_IEEE80211_HT_MCS19 38 /* 11n MCS 19 */ #define IFM_IEEE80211_HT_MCS20 39 /* 11n MCS 20 */ #define IFM_IEEE80211_HT_MCS21 40 /* 11n MCS 21 */ #define IFM_IEEE80211_HT_MCS22 41 /* 11n MCS 22 */ #define IFM_IEEE80211_HT_MCS23 42 /* 11n MCS 23 */ #define IFM_IEEE80211_HT_MCS24 43 /* 11n MCS 24 */ #define IFM_IEEE80211_HT_MCS25 44 /* 11n MCS 25 */ #define IFM_IEEE80211_HT_MCS26 45 /* 11n MCS 26 */ #define IFM_IEEE80211_HT_MCS27 46 /* 11n MCS 27 */ #define IFM_IEEE80211_HT_MCS28 47 /* 11n MCS 28 */ #define IFM_IEEE80211_HT_MCS29 48 /* 11n MCS 29 */ #define IFM_IEEE80211_HT_MCS30 49 /* 11n MCS 30 */ #define IFM_IEEE80211_HT_MCS31 50 /* 11n MCS 31 */ #define IFM_IEEE80211_HT_MCS32 51 /* 11n MCS 32 */ #define IFM_IEEE80211_HT_MCS33 52 /* 11n MCS 33 */ #define IFM_IEEE80211_HT_MCS34 53 /* 11n MCS 34 */ #define IFM_IEEE80211_HT_MCS35 54 /* 11n MCS 35 */ #define IFM_IEEE80211_HT_MCS36 55 /* 11n MCS 36 */ #define IFM_IEEE80211_HT_MCS37 56 /* 11n MCS 37 */ #define IFM_IEEE80211_HT_MCS38 57 /* 11n MCS 38 */ #define IFM_IEEE80211_HT_MCS39 58 /* 11n MCS 39 */ #define IFM_IEEE80211_HT_MCS40 59 /* 11n MCS 40 */ #define IFM_IEEE80211_HT_MCS41 60 /* 11n MCS 41 */ #define IFM_IEEE80211_HT_MCS42 61 /* 11n MCS 42 */ #define IFM_IEEE80211_HT_MCS43 62 /* 11n MCS 43 */ #define IFM_IEEE80211_HT_MCS44 63 /* 11n MCS 44 */ #define IFM_IEEE80211_HT_MCS45 64 /* 11n MCS 45 */ #define IFM_IEEE80211_HT_MCS46 65 /* 11n MCS 46 */ #define IFM_IEEE80211_HT_MCS47 66 /* 11n MCS 47 */ #define IFM_IEEE80211_HT_MCS48 67 /* 11n MCS 48 */ #define IFM_IEEE80211_HT_MCS49 68 /* 11n MCS 49 */ #define IFM_IEEE80211_HT_MCS50 69 /* 11n MCS 50 */ #define IFM_IEEE80211_HT_MCS51 70 /* 11n MCS 51 */ #define IFM_IEEE80211_HT_MCS52 71 /* 11n MCS 52 */ #define IFM_IEEE80211_HT_MCS53 72 /* 11n MCS 53 */ #define IFM_IEEE80211_HT_MCS54 73 /* 11n MCS 54 */ #define IFM_IEEE80211_HT_MCS55 74 /* 11n MCS 55 */ #define IFM_IEEE80211_HT_MCS56 75 /* 11n MCS 56 */ #define IFM_IEEE80211_HT_MCS57 76 /* 11n MCS 57 */ #define IFM_IEEE80211_HT_MCS58 77 /* 11n MCS 58 */ #define IFM_IEEE80211_HT_MCS59 78 /* 11n MCS 59 */ #define IFM_IEEE80211_HT_MCS60 79 /* 11n MCS 60 */ #define IFM_IEEE80211_HT_MCS61 80 /* 11n MCS 61 */ #define IFM_IEEE80211_HT_MCS62 81 /* 11n MCS 62 */ #define IFM_IEEE80211_HT_MCS63 82 /* 11n MCS 63 */ #define IFM_IEEE80211_HT_MCS64 83 /* 11n MCS 64 */ #define IFM_IEEE80211_HT_MCS65 84 /* 11n MCS 65 */ #define IFM_IEEE80211_HT_MCS66 85 /* 11n MCS 66 */ #define IFM_IEEE80211_HT_MCS67 86 /* 11n MCS 67 */ #define IFM_IEEE80211_HT_MCS68 87 /* 11n MCS 68 */ #define IFM_IEEE80211_HT_MCS69 88 /* 11n MCS 69 */ #define IFM_IEEE80211_HT_MCS70 89 /* 11n MCS 70 */ #define IFM_IEEE80211_HT_MCS71 90 /* 11n MCS 71 */ #define IFM_IEEE80211_HT_MCS72 91 /* 11n MCS 72 */ #define IFM_IEEE80211_HT_MCS73 92 /* 11n MCS 73 */ #define IFM_IEEE80211_HT_MCS74 93 /* 11n MCS 74 */ #define IFM_IEEE80211_HT_MCS75 94 /* 11n MCS 75 */ #define IFM_IEEE80211_HT_MCS76 95 /* 11n MCS 76 */ #define IFM_IEEE80211_VHT_MCS0 96 /* 11ac MCS 0 */ #define IFM_IEEE80211_VHT_MCS1 97 /* 11ac MCS 1 */ #define IFM_IEEE80211_VHT_MCS2 98 /* 11ac MCS 2 */ #define IFM_IEEE80211_VHT_MCS3 99 /* 11ac MCS 3 */ #define IFM_IEEE80211_VHT_MCS4 100 /* 11ac MCS 4 */ #define IFM_IEEE80211_VHT_MCS5 101 /* 11ac MCS 5 */ #define IFM_IEEE80211_VHT_MCS6 102 /* 11ac MCS 6 */ #define IFM_IEEE80211_VHT_MCS7 103 /* 11ac MCS 7 */ #define IFM_IEEE80211_VHT_MCS8 104 /* 11ac MCS 8 */ #define IFM_IEEE80211_VHT_MCS9 105 /* 11ac MCS 9 */ #define IFM_IEEE80211_ADHOC 0x0000000000010000ULL /* Operate in Adhoc mode */ #define IFM_IEEE80211_HOSTAP 0x0000000000020000ULL /* Operate in Host AP mode */ #define IFM_IEEE80211_IBSS 0x0000000000040000ULL /* Operate in IBSS mode */ #define IFM_IEEE80211_IBSSMASTER 0x0000000000080000ULL /* Operate as an IBSS master */ #define IFM_IEEE80211_MONITOR 0x0000000000100000ULL /* Operate in Monitor mode */ /* operating mode for multi-mode devices */ #define IFM_IEEE80211_11A 0x0000000100000000ULL /* 5GHz, OFDM mode */ #define IFM_IEEE80211_11B 0x0000000200000000ULL /* Direct Sequence mode */ #define IFM_IEEE80211_11G 0x0000000300000000ULL /* 2GHz, CCK mode */ #define IFM_IEEE80211_FH 0x0000000400000000ULL /* 2GHz, GFSK mode */ #define IFM_IEEE80211_11N 0x0000000800000000ULL /* 11n/HT 2GHz/5GHz */ #define IFM_IEEE80211_11AC 0x0000001000000000ULL /* 11ac/VHT 5GHz */ #define IFM_IEEE80211_11AX 0x0000002000000000ULL /* 11ax/HE 5GHz/6GHz */ /* * Digitally multiplexed "Carrier" Serial Interfaces */ #define IFM_TDM 0x0000000000000500ULL #define IFM_TDM_T1 3 /* T1 B8ZS+ESF 24 ts */ #define IFM_TDM_T1_AMI 4 /* T1 AMI+SF 24 ts */ #define IFM_TDM_E1 5 /* E1 HDB3+G.703 clearchannel 32 ts */ #define IFM_TDM_E1_G704 6 /* E1 HDB3+G.703+G.704 channelized 31 ts */ #define IFM_TDM_E1_AMI 7 /* E1 AMI+G.703 32 ts */ #define IFM_TDM_E1_AMI_G704 8 /* E1 AMI+G.703+G.704 31 ts */ #define IFM_TDM_T3 9 /* T3 B3ZS+C-bit 672 ts */ #define IFM_TDM_T3_M13 10 /* T3 B3ZS+M13 672 ts */ #define IFM_TDM_E3 11 /* E3 HDB3+G.751 512? ts */ #define IFM_TDM_E3_G751 12 /* E3 G.751 512 ts */ #define IFM_TDM_E3_G832 13 /* E3 G.832 512 ts */ #define IFM_TDM_E1_G704_CRC4 14 /* E1 HDB3+G.703+G.704 31 ts + CRC4 */ /* * 6 major ways that networks talk: Drivers enforce independent selection, * meaning, a driver will ensure that only one of these is set at a time. * Default is cisco hdlc mode with 32 bit CRC. */ #define IFM_TDM_HDLC_CRC16 0x0100 /* Use 16-bit CRC for HDLC instead */ #define IFM_TDM_PPP 0x0200 /* SPPP (dumb) */ #define IFM_TDM_FR_ANSI 0x0400 /* Frame Relay + LMI ANSI "Annex D" */ #define IFM_TDM_FR_CISCO 0x0800 /* Frame Relay + LMI Cisco */ #define IFM_TDM_FR_ITU 0x1000 /* Frame Relay + LMI ITU "Q933A" */ /* operating mode */ #define IFM_TDM_MASTER 0x0000000100000000ULL /* aka clock source internal */ /* * Common Access Redundancy Protocol */ #define IFM_CARP 0x0000000000000600ULL /* * Shared media sub-types */ #define IFM_AUTO 0ULL /* Autoselect best media */ #define IFM_MANUAL 1ULL /* Jumper/dipswitch selects media */ #define IFM_NONE 2ULL /* Deselect all media */ /* * Shared options */ #define IFM_FDX 0x0000010000000000ULL /* Force full duplex */ #define IFM_HDX 0x0000020000000000ULL /* Force half duplex */ #define IFM_FLOW 0x0000040000000000ULL /* enable hardware flow control */ #define IFM_FLAG0 0x0000100000000000ULL /* Driver defined flag */ #define IFM_FLAG1 0x0000200000000000ULL /* Driver defined flag */ #define IFM_FLAG2 0x0000400000000000ULL /* Driver defined flag */ #define IFM_LOOP 0x0000800000000000ULL /* Put hardware in loopback */ /* * Masks */ #define IFM_NMASK 0x000000000000ff00ULL /* Network type */ #define IFM_NSHIFT 8 /* Network type shift */ #define IFM_TMASK 0x00000000000000ffULL /* Media sub-type */ #define IFM_TSHIFT 0 /* Sub-type shift */ #define IFM_IMASK 0xff00000000000000ULL /* Instance */ #define IFM_ISHIFT 56 /* Instance shift */ #define IFM_OMASK 0x00000000ffff0000ULL /* Type specific options */ #define IFM_OSHIFT 16 /* Specific options shift */ #define IFM_MMASK 0x000000ff00000000ULL /* Mode */ #define IFM_MSHIFT 32 /* Mode shift */ #define IFM_GMASK 0x00ffff0000000000ULL /* Global options */ #define IFM_GSHIFT 40 /* Global options shift */ /* Ethernet flow control mask */ #define IFM_ETH_FMASK (IFM_FLOW|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE) #define IFM_NMIN IFM_ETHER /* lowest Network type */ #define IFM_NMAX IFM_NMASK /* highest Network type */ /* * Status bits */ #define IFM_AVALID 0x0000000000000001ULL /* Active bit valid */ #define IFM_ACTIVE 0x0000000000000002ULL /* Interface attached to working net */ /* Mask of "status valid" bits, for ifconfig(8). */ #define IFM_STATUS_VALID IFM_AVALID /* List of "status valid" bits, for ifconfig(8). */ #define IFM_STATUS_VALID_LIST { \ IFM_AVALID, \ 0 \ } /* * Macros to extract various bits of information from the media word. */ #define IFM_TYPE(x) ((x) & IFM_NMASK) #define IFM_SUBTYPE(x) ((x) & IFM_TMASK) #define IFM_INST(x) (((x) & IFM_IMASK) >> IFM_ISHIFT) #define IFM_OPTIONS(x) ((x) & (IFM_OMASK|IFM_GMASK)) #define IFM_MODE(x) ((x) & IFM_MMASK) #define IFM_INST_MAX IFM_INST(IFM_IMASK) #define IFM_INST_ANY ((uint64_t) -1) /* * Macro to create a media word. * All arguments are IFM_* macros, except 'instance' which is a 64-bit integer. * XXX 'operating mode' is not included here?!? */ #define IFM_MAKEWORD(type, subtype, options, instance) \ ((type) | (subtype) | (options) | \ ((uint64_t)(instance) << IFM_ISHIFT)) /* * Add a media configuration to the list of supported media * for a specific interface instance. */ static inline void ifmedia_add(struct ifmedia *ifm, uint64_t mword, int data, void *aux) { struct ifmedia_entry *entry; entry = (struct ifmedia_entry *)IOMalloc(sizeof(*entry)); if (entry == NULL) panic("ifmedia_add: can't malloc entry"); entry->ifm_media = mword; entry->ifm_data = data; entry->ifm_aux = aux; TAILQ_INSERT_TAIL(&ifm->ifm_list, entry, ifm_list); } ///* // * NetBSD extension not defined in the BSDI API. This is used in various // * places to get the canonical description for a given type/subtype. // * // * In the subtype and mediaopt descriptions, the valid TYPE bits are OR'd // * in to indicate which TYPE the subtype/option corresponds to. If no // * TYPE is present, it is a shared media/mediaopt. // * // * Note that these are parsed case-insensitive. // * // * Order is important. The first matching entry is the canonical name // * for a media type; subsequent matches are aliases. // */ //struct ifmedia_description { // uint64_t ifmt_word; /* word value; may be masked */ // const char *ifmt_string; /* description */ //}; #define IFM_TYPE_DESCRIPTIONS { \ { IFM_ETHER, "Ethernet" }, \ { IFM_ETHER, "ether" }, \ { IFM_FDDI, "FDDI" }, \ { IFM_IEEE80211, "IEEE802.11" }, \ { IFM_TDM, "TDM" }, \ { IFM_CARP, "CARP" }, \ { 0, NULL }, \ } #define IFM_TYPE_MATCH(dt, t) \ (IFM_TYPE((dt)) == 0 || IFM_TYPE((dt)) == IFM_TYPE((t))) #define IFM_SUBTYPE_DESCRIPTIONS { \ { IFM_AUTO, "autoselect" }, \ { IFM_AUTO, "auto" }, \ { IFM_MANUAL, "manual" }, \ { IFM_NONE, "none" }, \ \ { IFM_ETHER|IFM_10_T, "10baseT" }, \ { IFM_ETHER|IFM_10_T, "10baseT/UTP" }, \ { IFM_ETHER|IFM_10_T, "UTP" }, \ { IFM_ETHER|IFM_10_T, "10UTP" }, \ { IFM_ETHER|IFM_10_2, "10base2" }, \ { IFM_ETHER|IFM_10_2, "10base2/BNC" }, \ { IFM_ETHER|IFM_10_2, "BNC" }, \ { IFM_ETHER|IFM_10_2, "10BNC" }, \ { IFM_ETHER|IFM_10_5, "10base5" }, \ { IFM_ETHER|IFM_10_5, "10base5/AUI" }, \ { IFM_ETHER|IFM_10_5, "AUI" }, \ { IFM_ETHER|IFM_10_5, "10AUI" }, \ { IFM_ETHER|IFM_100_TX, "100baseTX" }, \ { IFM_ETHER|IFM_100_TX, "100TX" }, \ { IFM_ETHER|IFM_100_FX, "100baseFX" }, \ { IFM_ETHER|IFM_100_FX, "100FX" }, \ { IFM_ETHER|IFM_100_T4, "100baseT4" }, \ { IFM_ETHER|IFM_100_T4, "100T4" }, \ { IFM_ETHER|IFM_100_VG, "100baseVG" }, \ { IFM_ETHER|IFM_100_VG, "100VG" }, \ { IFM_ETHER|IFM_100_T2, "100baseT2" }, \ { IFM_ETHER|IFM_100_T2, "100T2" }, \ { IFM_ETHER|IFM_1000_SX, "1000baseSX" }, \ { IFM_ETHER|IFM_1000_SX, "1000SX" }, \ { IFM_ETHER|IFM_10_STP, "10baseSTP" }, \ { IFM_ETHER|IFM_10_STP, "STP" }, \ { IFM_ETHER|IFM_10_STP, "10STP" }, \ { IFM_ETHER|IFM_10_FL, "10baseFL" }, \ { IFM_ETHER|IFM_10_FL, "FL" }, \ { IFM_ETHER|IFM_10_FL, "10FL" }, \ { IFM_ETHER|IFM_1000_LX, "1000baseLX" }, \ { IFM_ETHER|IFM_1000_LX, "1000LX" }, \ { IFM_ETHER|IFM_1000_CX, "1000baseCX" }, \ { IFM_ETHER|IFM_1000_CX, "1000CX" }, \ { IFM_ETHER|IFM_1000_T, "1000baseT" }, \ { IFM_ETHER|IFM_1000_T, "1000T" }, \ { IFM_ETHER|IFM_1000_T, "1000baseTX" }, \ { IFM_ETHER|IFM_1000_T, "1000TX" }, \ { IFM_ETHER|IFM_HPNA_1, "HomePNA1" }, \ { IFM_ETHER|IFM_HPNA_1, "HPNA1" }, \ { IFM_ETHER|IFM_10G_LR, "10GbaseLR" }, \ { IFM_ETHER|IFM_10G_LR, "10GLR" }, \ { IFM_ETHER|IFM_10G_LR, "10GBASE-LR" }, \ { IFM_ETHER|IFM_10G_SR, "10GbaseSR" }, \ { IFM_ETHER|IFM_10G_SR, "10GSR" }, \ { IFM_ETHER|IFM_10G_SR, "10GBASE-SR" }, \ { IFM_ETHER|IFM_10G_CX4, "10GbaseCX4" }, \ { IFM_ETHER|IFM_10G_CX4, "10GCX4" }, \ { IFM_ETHER|IFM_10G_CX4, "10GBASE-CX4" }, \ { IFM_ETHER|IFM_2500_SX, "2500baseSX" }, \ { IFM_ETHER|IFM_2500_SX, "2500SX" }, \ { IFM_ETHER|IFM_10G_T, "10GbaseT" }, \ { IFM_ETHER|IFM_10G_T, "10GT" }, \ { IFM_ETHER|IFM_10G_T, "10GBASE-T" }, \ { IFM_ETHER|IFM_10G_SFP_CU, "10GSFP+Cu" }, \ { IFM_ETHER|IFM_10G_SFP_CU, "10GCu" }, \ { IFM_ETHER|IFM_10G_LRM, "10GbaseLRM" }, \ { IFM_ETHER|IFM_10G_LRM, "10GBASE-LRM" }, \ { IFM_ETHER|IFM_40G_CR4, "40GbaseCR4" }, \ { IFM_ETHER|IFM_40G_CR4, "40GBASE-CR4" }, \ { IFM_ETHER|IFM_40G_SR4, "40GbaseSR4" }, \ { IFM_ETHER|IFM_40G_SR4, "40GBASE-SR4" }, \ { IFM_ETHER|IFM_40G_LR4, "40GbaseLR4" }, \ { IFM_ETHER|IFM_40G_LR4, "40GBASE-LR4" }, \ { IFM_ETHER|IFM_1000_KX, "1000base-KX" }, \ { IFM_ETHER|IFM_1000_KX, "1000BASE-KX" }, \ { IFM_ETHER|IFM_10G_KX4, "10GbaseKX4" }, \ { IFM_ETHER|IFM_10G_KX4, "10GBASE-KX4" }, \ { IFM_ETHER|IFM_10G_KR, "10GbaseKR" }, \ { IFM_ETHER|IFM_10G_KR, "10GBASE-KR" }, \ { IFM_ETHER|IFM_10G_CR1, "10GbaseCR1" }, \ { IFM_ETHER|IFM_10G_CR1, "10GBASE-CR1" }, \ { IFM_ETHER|IFM_10G_AOC, "10G-AOC" }, \ { IFM_ETHER|IFM_20G_KR2, "20GbaseKR2" }, \ { IFM_ETHER|IFM_20G_KR2, "20GBASE-KR2" }, \ { IFM_ETHER|IFM_2500_KX, "2500baseKX" }, \ { IFM_ETHER|IFM_2500_KX, "2500BASE-KX" }, \ { IFM_ETHER|IFM_2500_T, "2500baseT" }, \ { IFM_ETHER|IFM_2500_T, "2500BASE-T" }, \ { IFM_ETHER|IFM_5000_T, "5000baseT" }, \ { IFM_ETHER|IFM_5000_T, "5000BASE-T" }, \ { IFM_ETHER|IFM_1000_SGMII, "1000base-SGMII" }, \ { IFM_ETHER|IFM_1000_SGMII, "1000BASE-SGMII" }, \ { IFM_ETHER|IFM_10G_SFI, "10GbaseSFI" }, \ { IFM_ETHER|IFM_10G_SFI, "10GBASE-SFI" }, \ { IFM_ETHER|IFM_40G_XLPPI, "40GbaseXLPPI" }, \ { IFM_ETHER|IFM_40G_XLPPI, "40GBASE-XLPPI" }, \ { IFM_ETHER|IFM_1000_CX_SGMII, "1000baseCX-SGMII" }, \ { IFM_ETHER|IFM_1000_CX_SGMII, "1000BASE-CX-SGMII" }, \ { IFM_ETHER|IFM_40G_KR4, "40GbaseKR4" }, \ { IFM_ETHER|IFM_40G_KR4, "40GBASE-KR4" }, \ { IFM_ETHER|IFM_40G_AOC, "40G-AOC" }, \ { IFM_ETHER|IFM_10G_ER, "10GbaseER" }, \ { IFM_ETHER|IFM_10G_ER, "10GBASE-ER" }, \ { IFM_ETHER|IFM_100G_CR4, "100GbaseCR4" }, \ { IFM_ETHER|IFM_100G_CR4, "100GBASE-CR4" }, \ { IFM_ETHER|IFM_100G_SR4, "100GbaseSR4" }, \ { IFM_ETHER|IFM_100G_SR4, "100GBASE-SR4" }, \ { IFM_ETHER|IFM_100G_KR4, "100GbaseKR4" }, \ { IFM_ETHER|IFM_100G_KR4, "100GBASE-KR4" }, \ { IFM_ETHER|IFM_100G_LR4, "100GbaseLR4" }, \ { IFM_ETHER|IFM_100G_LR4, "100GBASE-LR4" }, \ { IFM_ETHER|IFM_100G_AOC, "100G-AOC" }, \ { IFM_ETHER|IFM_56G_R4, "56GbaseR4" }, \ { IFM_ETHER|IFM_56G_R4, "56GBASE-R4" }, \ { IFM_ETHER|IFM_25G_CR, "25GbaseCR" }, \ { IFM_ETHER|IFM_25G_CR, "25GBASE-CR" }, \ { IFM_ETHER|IFM_25G_KR, "25GbaseKR" }, \ { IFM_ETHER|IFM_25G_KR, "25GBASE-KR" }, \ { IFM_ETHER|IFM_25G_SR, "25GbaseSR" }, \ { IFM_ETHER|IFM_25G_SR, "25GBASE-SR" }, \ { IFM_ETHER|IFM_25G_LR, "25GbaseLR" }, \ { IFM_ETHER|IFM_25G_LR, "25GBASE-LR" }, \ { IFM_ETHER|IFM_25G_ER, "25GbaseER" }, \ { IFM_ETHER|IFM_25G_ER, "25GBASE-ER" }, \ { IFM_ETHER|IFM_25G_AOC, "25G-AOC" }, \ { IFM_ETHER|IFM_50G_CR2, "50GbaseCR2" }, \ { IFM_ETHER|IFM_50G_CR2, "50GBASE-CR2" }, \ { IFM_ETHER|IFM_50G_KR2, "50GbaseKR2" }, \ { IFM_ETHER|IFM_50G_KR2, "50GBASE-KR2" }, \ \ { IFM_FDDI|IFM_FDDI_SMF, "Single-mode" }, \ { IFM_FDDI|IFM_FDDI_SMF, "SMF" }, \ { IFM_FDDI|IFM_FDDI_MMF, "Multi-mode" }, \ { IFM_FDDI|IFM_FDDI_MMF, "MMF" }, \ { IFM_FDDI|IFM_FDDI_UTP, "UTP" }, \ { IFM_FDDI|IFM_FDDI_UTP, "CDDI" }, \ \ { IFM_IEEE80211|IFM_IEEE80211_FH1, "FH1" }, \ { IFM_IEEE80211|IFM_IEEE80211_FH2, "FH2" }, \ { IFM_IEEE80211|IFM_IEEE80211_DS2, "DS2" }, \ { IFM_IEEE80211|IFM_IEEE80211_DS5, "DS5" }, \ { IFM_IEEE80211|IFM_IEEE80211_DS11, "DS11" }, \ { IFM_IEEE80211|IFM_IEEE80211_DS1, "DS1" }, \ { IFM_IEEE80211|IFM_IEEE80211_DS22, "DS22" }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM6, "OFDM6" }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM9, "OFDM9" }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM12, "OFDM12" }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM18, "OFDM18" }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM24, "OFDM24" }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM36, "OFDM36" }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM48, "OFDM48" }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM54, "OFDM54" }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM72, "OFDM72" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS0, "HT-MCS0" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS1, "HT-MCS1" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS2, "HT-MCS2" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS3, "HT-MCS3" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS4, "HT-MCS4" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS5, "HT-MCS5" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS6, "HT-MCS6" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS7, "HT-MCS7" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS8, "HT-MCS8" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS9, "HT-MCS9" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS10, "HT-MCS10" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS11, "HT-MCS11" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS12, "HT-MCS12" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS13, "HT-MCS13" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS14, "HT-MCS14" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS15, "HT-MCS15" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS16, "HT-MCS16" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS17, "HT-MCS17" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS18, "HT-MCS18" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS19, "HT-MCS19" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS20, "HT-MCS20" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS21, "HT-MCS21" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS22, "HT-MCS22" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS23, "HT-MCS23" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS24, "HT-MCS24" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS25, "HT-MCS25" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS26, "HT-MCS26" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS27, "HT-MCS27" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS28, "HT-MCS28" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS29, "HT-MCS29" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS30, "HT-MCS30" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS31, "HT-MCS31" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS32, "HT-MCS32" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS33, "HT-MCS33" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS34, "HT-MCS34" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS35, "HT-MCS35" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS36, "HT-MCS36" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS37, "HT-MCS37" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS38, "HT-MCS38" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS39, "HT-MCS39" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS40, "HT-MCS40" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS41, "HT-MCS41" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS42, "HT-MCS42" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS43, "HT-MCS43" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS44, "HT-MCS44" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS45, "HT-MCS45" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS46, "HT-MCS46" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS47, "HT-MCS47" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS48, "HT-MCS48" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS49, "HT-MCS49" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS50, "HT-MCS50" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS51, "HT-MCS51" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS52, "HT-MCS52" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS53, "HT-MCS53" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS54, "HT-MCS54" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS55, "HT-MCS55" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS56, "HT-MCS56" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS57, "HT-MCS57" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS58, "HT-MCS58" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS59, "HT-MCS59" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS60, "HT-MCS60" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS61, "HT-MCS61" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS62, "HT-MCS62" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS63, "HT-MCS63" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS64, "HT-MCS64" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS65, "HT-MCS65" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS66, "HT-MCS66" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS67, "HT-MCS67" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS68, "HT-MCS68" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS69, "HT-MCS69" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS70, "HT-MCS70" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS71, "HT-MCS71" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS72, "HT-MCS72" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS73, "HT-MCS73" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS74, "HT-MCS74" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS75, "HT-MCS75" }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS76, "HT-MCS76" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS0, "VHT-MCS0" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS1, "VHT-MCS1" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS2, "VHT-MCS2" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS3, "VHT-MCS3" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS4, "VHT-MCS4" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS5, "VHT-MCS5" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS6, "VHT-MCS6" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS7, "VHT-MCS7" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS8, "VHT-MCS8" }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS9, "VHT-MCS9" }, \ \ { IFM_TDM|IFM_TDM_T1, "t1" }, \ { IFM_TDM|IFM_TDM_T1_AMI, "t1-ami" }, \ { IFM_TDM|IFM_TDM_E1, "e1" }, \ { IFM_TDM|IFM_TDM_E1_G704, "e1-g.704" }, \ { IFM_TDM|IFM_TDM_E1_AMI, "e1-ami" }, \ { IFM_TDM|IFM_TDM_E1_AMI_G704, "e1-ami-g.704" }, \ { IFM_TDM|IFM_TDM_T3, "t3" }, \ { IFM_TDM|IFM_TDM_T3_M13, "t3-m13" }, \ { IFM_TDM|IFM_TDM_E3, "e3" }, \ { IFM_TDM|IFM_TDM_E3_G751, "e3-g.751" }, \ { IFM_TDM|IFM_TDM_E3_G832, "e3-g.832" }, \ { IFM_TDM|IFM_TDM_E1_G704_CRC4, "e1-g.704-crc4" }, \ \ { 0, NULL }, \ } #define IFM_MODE_DESCRIPTIONS { \ { IFM_AUTO, "autoselect" }, \ { IFM_AUTO, "auto" }, \ { IFM_IEEE80211|IFM_IEEE80211_11A, "11a" }, \ { IFM_IEEE80211|IFM_IEEE80211_11B, "11b" }, \ { IFM_IEEE80211|IFM_IEEE80211_11G, "11g" }, \ { IFM_IEEE80211|IFM_IEEE80211_FH, "fh" }, \ { IFM_IEEE80211|IFM_IEEE80211_11N, "11n" }, \ { IFM_IEEE80211|IFM_IEEE80211_11AC, "11ac" }, \ { IFM_TDM|IFM_TDM_MASTER, "master" }, \ { 0, NULL }, \ } #define IFM_OPTION_DESCRIPTIONS { \ { IFM_FDX, "full-duplex" }, \ { IFM_FDX, "fdx" }, \ { IFM_HDX, "half-duplex" }, \ { IFM_HDX, "hdx" }, \ { IFM_FLAG0, "flag0" }, \ { IFM_FLAG1, "flag1" }, \ { IFM_FLAG2, "flag2" }, \ { IFM_LOOP, "loopback" }, \ { IFM_LOOP, "hw-loopback"}, \ { IFM_LOOP, "loop" }, \ \ { IFM_ETHER|IFM_ETH_MASTER, "master" }, \ { IFM_ETHER|IFM_ETH_RXPAUSE, "rxpause" }, \ { IFM_ETHER|IFM_ETH_TXPAUSE, "txpause" }, \ \ { IFM_FDDI|IFM_FDDI_DA, "dual-attach" }, \ { IFM_FDDI|IFM_FDDI_DA, "das" }, \ \ { IFM_IEEE80211|IFM_IEEE80211_ADHOC, "adhoc" }, \ { IFM_IEEE80211|IFM_IEEE80211_HOSTAP, "hostap" }, \ { IFM_IEEE80211|IFM_IEEE80211_IBSS, "ibss" }, \ { IFM_IEEE80211|IFM_IEEE80211_IBSSMASTER, "ibss-master" }, \ { IFM_IEEE80211|IFM_IEEE80211_MONITOR, "monitor" }, \ \ { IFM_TDM|IFM_TDM_HDLC_CRC16, "hdlc-crc16" }, \ { IFM_TDM|IFM_TDM_PPP, "ppp" }, \ { IFM_TDM|IFM_TDM_FR_ANSI, "framerelay-ansi" }, \ { IFM_TDM|IFM_TDM_FR_CISCO, "framerelay-cisco" }, \ { IFM_TDM|IFM_TDM_FR_ANSI, "framerelay-itu" }, \ \ { 0, NULL }, \ } /* * Baudrate descriptions for the various media types. */ struct ifmedia_baudrate { uint64_t ifmb_word; /* media word */ uint64_t ifmb_baudrate; /* corresponding baudrate */ }; #define IFM_BAUDRATE_DESCRIPTIONS { \ { IFM_ETHER|IFM_10_T, IF_Mbps(10) }, \ { IFM_ETHER|IFM_10_2, IF_Mbps(10) }, \ { IFM_ETHER|IFM_10_5, IF_Mbps(10) }, \ { IFM_ETHER|IFM_100_TX, IF_Mbps(100) }, \ { IFM_ETHER|IFM_100_FX, IF_Mbps(100) }, \ { IFM_ETHER|IFM_100_T4, IF_Mbps(100) }, \ { IFM_ETHER|IFM_100_VG, IF_Mbps(100) }, \ { IFM_ETHER|IFM_100_T2, IF_Mbps(100) }, \ { IFM_ETHER|IFM_1000_SX, IF_Mbps(1000) }, \ { IFM_ETHER|IFM_10_STP, IF_Mbps(10) }, \ { IFM_ETHER|IFM_10_FL, IF_Mbps(10) }, \ { IFM_ETHER|IFM_1000_LX, IF_Mbps(1000) }, \ { IFM_ETHER|IFM_1000_CX, IF_Mbps(1000) }, \ { IFM_ETHER|IFM_1000_T, IF_Mbps(1000) }, \ { IFM_ETHER|IFM_HPNA_1, IF_Mbps(1) }, \ { IFM_ETHER|IFM_10G_LR, IF_Gbps(10) }, \ { IFM_ETHER|IFM_10G_SR, IF_Gbps(10) }, \ { IFM_ETHER|IFM_10G_CX4, IF_Gbps(10) }, \ { IFM_ETHER|IFM_2500_SX, IF_Mbps(2500) }, \ { IFM_ETHER|IFM_10G_T, IF_Gbps(10) }, \ { IFM_ETHER|IFM_10G_SFP_CU, IF_Gbps(10) }, \ \ { IFM_FDDI|IFM_FDDI_SMF, IF_Mbps(100) }, \ { IFM_FDDI|IFM_FDDI_MMF, IF_Mbps(100) }, \ { IFM_FDDI|IFM_FDDI_UTP, IF_Mbps(100) }, \ \ { IFM_IEEE80211|IFM_IEEE80211_FH1, IF_Mbps(1) }, \ { IFM_IEEE80211|IFM_IEEE80211_FH2, IF_Mbps(2) }, \ { IFM_IEEE80211|IFM_IEEE80211_DS1, IF_Mbps(1) }, \ { IFM_IEEE80211|IFM_IEEE80211_DS2, IF_Mbps(2) }, \ { IFM_IEEE80211|IFM_IEEE80211_DS5, IF_Mbps(5) }, \ { IFM_IEEE80211|IFM_IEEE80211_DS11, IF_Mbps(11) }, \ { IFM_IEEE80211|IFM_IEEE80211_DS22, IF_Mbps(22) }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM6, IF_Mbps(6) }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM9, IF_Mbps(9) }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM12, IF_Mbps(12) }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM18, IF_Mbps(18) }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM24, IF_Mbps(24) }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM36, IF_Mbps(36) }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM48, IF_Mbps(48) }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM54, IF_Mbps(54) }, \ { IFM_IEEE80211|IFM_IEEE80211_OFDM72, IF_Mbps(72) }, \ /* These HT rates correspond to 20 MHz channel with no SGI. */ \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS0, IF_Kbps(6500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS1, IF_Mbps(13) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS2, IF_Kbps(19500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS3, IF_Mbps(26) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS4, IF_Mbps(39) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS5, IF_Mbps(52) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS6, IF_Kbps(58500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS7, IF_Mbps(65) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS8, IF_Mbps(13) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS9, IF_Mbps(26) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS10, IF_Mbps(39) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS11, IF_Mbps(52) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS12, IF_Mbps(78) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS13, IF_Mbps(104) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS14, IF_Mbps(117) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS15, IF_Mbps(130) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS16, IF_Kbps(19500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS17, IF_Mbps(39) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS18, IF_Kbps(58500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS19, IF_Mbps(78) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS20, IF_Mbps(117) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS21, IF_Mbps(156) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS22, IF_Kbps(175500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS23, IF_Mbps(195) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS24, IF_Mbps(26) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS25, IF_Mbps(52) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS26, IF_Mbps(78) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS27, IF_Mbps(104) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS28, IF_Mbps(156) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS29, IF_Mbps(208) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS30, IF_Mbps(234) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS31, IF_Mbps(260) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS32, IF_Mbps(0) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS33, IF_Mbps(39) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS34, IF_Mbps(52) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS35, IF_Mbps(65) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS36, IF_Kbps(58500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS37, IF_Mbps(78) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS38, IF_Kbps(97500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS39, IF_Mbps(52) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS40, IF_Mbps(65) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS41, IF_Mbps(65) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS42, IF_Mbps(78) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS43, IF_Mbps(91) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS44, IF_Mbps(91) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS45, IF_Mbps(104) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS46, IF_Mbps(78) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS47, IF_Kbps(97500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS48, IF_Kbps(97500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS49, IF_Mbps(117) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS50, IF_Kbps(136500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS51, IF_Kbps(136500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS52, IF_Mbps(156) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS53, IF_Mbps(65) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS54, IF_Mbps(78) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS55, IF_Mbps(91) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS56, IF_Mbps(78) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS57, IF_Mbps(91) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS58, IF_Mbps(104) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS59, IF_Mbps(117) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS60, IF_Mbps(104) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS61, IF_Mbps(117) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS62, IF_Mbps(130) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS63, IF_Mbps(130) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS64, IF_Mbps(143) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS65, IF_Kbps(97500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS66, IF_Mbps(117) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS67, IF_Kbps(136500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS68, IF_Mbps(117) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS69, IF_Kbps(136500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS70, IF_Mbps(156) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS71, IF_Kbps(175500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS72, IF_Mbps(156) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS73, IF_Kbps(175500) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS74, IF_Mbps(195) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS75, IF_Mbps(195) }, \ { IFM_IEEE80211|IFM_IEEE80211_HT_MCS76, IF_Kbps(214500) }, \ /* These VHT rates correspond to 1 SS, no SGI, 40 MHz channel.*/\ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS0, IF_Kbps(13500) }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS1, IF_Mbps(27) }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS2, IF_Kbps(40500) }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS3, IF_Mbps(54) }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS4, IF_Mbps(81) }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS5, IF_Mbps(108) }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS6, IF_Kbps(121500) }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS7, IF_Mbps(135) }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS8, IF_Mbps(162) }, \ { IFM_IEEE80211|IFM_IEEE80211_VHT_MCS9, IF_Mbps(180) }, \ \ { IFM_TDM|IFM_TDM_T1, IF_Kbps(1536) }, \ { IFM_TDM|IFM_TDM_T1_AMI, IF_Kbps(1536) }, \ { IFM_TDM|IFM_TDM_E1, IF_Kbps(2048) }, \ { IFM_TDM|IFM_TDM_E1_G704, IF_Kbps(2048) }, \ { IFM_TDM|IFM_TDM_E1_AMI, IF_Kbps(2048) }, \ { IFM_TDM|IFM_TDM_E1_AMI_G704, IF_Kbps(2048) }, \ { IFM_TDM|IFM_TDM_T3, IF_Kbps(44736) }, \ { IFM_TDM|IFM_TDM_T3_M13, IF_Kbps(44736) }, \ { IFM_TDM|IFM_TDM_E3, IF_Kbps(34368) }, \ { IFM_TDM|IFM_TDM_E3_G751, IF_Kbps(34368) }, \ { IFM_TDM|IFM_TDM_E3_G832, IF_Kbps(34368) }, \ { IFM_TDM|IFM_TDM_E1_G704_CRC4, IF_Kbps(2048) }, \ \ { 0, 0 }, \ } /* * Status bit descriptions for the various media types. */ struct ifmedia_status_description { uint64_t ifms_type; uint64_t ifms_valid; uint64_t ifms_bit; const char *ifms_string[2]; }; #define IFM_STATUS_DESC(ifms, bit) \ (ifms)->ifms_string[((ifms)->ifms_bit & (bit)) ? 1 : 0] #define IFM_STATUS_DESCRIPTIONS { \ { IFM_ETHER, IFM_AVALID, IFM_ACTIVE, \ { "no carrier", "active" } }, \ { IFM_FDDI, IFM_AVALID, IFM_ACTIVE, \ { "no ring", "inserted" } }, \ { IFM_IEEE80211, IFM_AVALID, IFM_ACTIVE, \ { "no network", "active" } }, \ { IFM_TDM, IFM_AVALID, IFM_ACTIVE, \ { "no carrier", "active" } }, \ { IFM_CARP, IFM_AVALID, IFM_ACTIVE, \ { "backup", "master" } }, \ { 0, 0, 0, \ { NULL, NULL } } \ } /* Delete all media for a given media instance */ static inline void ifmedia_delete_instance(struct ifmedia *ifm, uint64_t inst) { XYLog("%s\n", __FUNCTION__); struct ifmedia_entry *ife, *nife; TAILQ_FOREACH_SAFE(ife, &ifm->ifm_list, ifm_list, nife) { if (inst == IFM_INST_ANY || inst == IFM_INST(ife->ifm_media)) { TAILQ_REMOVE(&ifm->ifm_list, ife, ifm_list); IOFree(ife, sizeof *ife); } } } /* * Find media entry matching a given ifm word. */ static inline struct ifmedia_entry * ifmedia_match(struct ifmedia *ifm, uint64_t target, uint64_t mask) { struct ifmedia_entry *match, *next; match = NULL; mask = ~mask; TAILQ_FOREACH(next, &ifm->ifm_list, ifm_list) { if ((next->ifm_media & mask) == (target & mask)) { if (match) { #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC) XYLog("ifmedia_match: multiple match for " "0x%llx/0x%llx, selected instance %lld\n", target, mask, IFM_INST(match->ifm_media)); #endif break; } match = next; } } return (match); } /* Set default media type on initialization. */ static inline void ifmedia_set(struct ifmedia *ifm, uint64_t target) { struct ifmedia_entry *match; match = ifmedia_match(ifm, target, ifm->ifm_mask); /* * If we didn't find the requested media, then we try to fall * back to target-type (IFM_ETHER, e.g.) | IFM_NONE. If that's * not on the list, then we add it and set the media to it. * * Since ifmedia_set is almost always called with IFM_AUTO or * with a known-good media, this really should only occur if we: * * a) didn't find any PHYs, or * b) didn't find an autoselect option on the PHY when the * parent ethernet driver expected to. * * In either case, it makes sense to select no media. */ if (match == NULL) { XYLog("ifmedia_set: no match for 0x%llx/0x%llx\n", target, ~ifm->ifm_mask); target = (target & IFM_NMASK) | IFM_NONE; match = ifmedia_match(ifm, target, ifm->ifm_mask); if (match == NULL) { ifmedia_add(ifm, target, 0, NULL); match = ifmedia_match(ifm, target, ifm->ifm_mask); if (match == NULL) panic("ifmedia_set failed"); } } ifm->ifm_cur = match; } #endif /* _NET_IF_MEDIA_H_ */ ================================================ FILE: itl80211/openbsd/sys/_ifq.cpp ================================================ // // _ifq.cpp // itlwm // // Created by zxystd on 2022/8/13. // Copyright © 2022 钟先耀. All rights reserved. // #include void ifq_init(struct _ifqueue *ifq, struct _ifnet *ifp, unsigned int maxLen) { if (!ifq->queue) ifq->queue = IOPacketQueue::withCapacity(maxLen); else ifq->queue->setCapacity(maxLen); ifq->ifq_oactive = 0; } void ifq_destroy(struct _ifqueue *ifq) { if (ifq->queue) { ifq->queue->release(); ifq->queue = nullptr; } } void ifq_flush(struct _ifqueue *ifq) { if (ifq->queue) ifq->queue->lockFlush(); } bool ifq_empty(struct _ifqueue *ifq) { return ifq->queue->getSize() == 0; } uint32_t ifq_len(struct _ifqueue *ifq) { return ifq->queue->getSize(); } void ifq_set_maxlen(struct _ifqueue *ifq, uint32_t maxLen) { ifq->queue->setCapacity(maxLen); } void ifq_set_oactive(struct _ifqueue *ifq) { ifq->ifq_oactive = 1; } unsigned int ifq_is_oactive(struct _ifqueue *ifq) { return ifq->ifq_oactive; } void ifq_clr_oactive(struct _ifqueue *ifq) { ifq->ifq_oactive = 0; } mbuf_t ifq_dequeue(struct _ifqueue *ifq) { return ifq->queue->lockDequeue(); } int ifq_enqueue(struct _ifqueue *ifq, mbuf_t m) { ifq->queue->lockEnqueueWithDrop(m); return 0; } ================================================ FILE: itl80211/openbsd/sys/_ifq.h ================================================ // // _ifq.h // itlwm // // Created by qcwap on 2020/3/1. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef _ifq_h #define _ifq_h #include #include struct _ifqueue { unsigned int ifq_oactive; IOPacketQueue *queue; }; void ifq_init(struct _ifqueue *ifq, struct _ifnet *ifp, unsigned int maxLen); void ifq_destroy(struct _ifqueue *ifq); void ifq_flush(struct _ifqueue *ifq); bool ifq_empty(struct _ifqueue *ifq); uint32_t ifq_len(struct _ifqueue *ifq); void ifq_set_maxlen(struct _ifqueue *ifq, uint32_t maxLen); void ifq_set_oactive(struct _ifqueue *ifq); unsigned int ifq_is_oactive(struct _ifqueue *ifq); void ifq_clr_oactive(struct _ifqueue *ifq); mbuf_t ifq_dequeue(struct _ifqueue *ifq); int ifq_enqueue(struct _ifqueue *ifq, mbuf_t m); #endif /* _ifq_h */ ================================================ FILE: itl80211/openbsd/sys/_malloc.h ================================================ // // _malloc.h // itlwm // // Created by qcwap on 2020/7/24. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef _malloc_h #define _malloc_h #include static inline void* malloc(vm_size_t len, int type, int how) { void* addr = IOMalloc(len + sizeof(vm_size_t)); if (addr == NULL) { return NULL; } *((vm_size_t*) addr) = len; void *buf = (void*)((uint8_t*)addr + sizeof(vm_size_t)); bzero(buf, len); return buf; } static inline void free(void* addr) { if (addr == NULL) { return; } void* actual_addr = (void*)((uint8_t*)addr - sizeof(vm_size_t)); vm_size_t len = *((vm_size_t*) actual_addr); IOFree(actual_addr, len + sizeof(vm_size_t)); } #endif /* _malloc_h */ ================================================ FILE: itl80211/openbsd/sys/_mbuf.cpp ================================================ // // _mbuf.cpp // itlwm // // Created by qcwap on 2020/6/14. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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 extern "C" { #include } #include extern IOCommandGate *_fCommandGate; struct network_header { char pad[0x48]; }; static IOReturn _if_input(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) { mbuf_t m; bool isEmpty = true; struct _ifnet *ifq = (struct _ifnet *)arg0; struct mbuf_list *ml = (struct mbuf_list *)arg1; MBUF_LIST_FOREACH(ml, m) { if (ifq->iface == NULL) { panic("%s ifq->iface == NULL!!!\n", __FUNCTION__); break; } if (m == NULL) { XYLog("%s m == NULL!!!\n", __FUNCTION__); continue; } // XYLog("%s %d 啊啊啊啊 ifq->iface->inputPacket(m) hdr_len=%d len=%d\n", __FUNCTION__, __LINE__, mbuf_pkthdr_len(m), mbuf_len(m)); isEmpty = false; ifq->iface->inputPacket(m, 0, IONetworkInterface::kInputOptionQueuePacket); if (ifq->netStat != NULL) { ifq->netStat->inputPackets++; } } if (!isEmpty) { ifq->iface->flushInputQueue(); } return kIOReturnSuccess; } int if_input(struct _ifnet *ifq, struct mbuf_list *ml) { return _fCommandGate->runAction((IOCommandGate::Action)_if_input, ifq, ml); } ================================================ FILE: itl80211/openbsd/sys/_mbuf.h ================================================ // // mbuf.h // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/22. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ /* $OpenBSD: mbuf.h,v 1.245 2019/07/16 17:39:02 bluhm Exp $ */ /* $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)mbuf.h 8.5 (Berkeley) 2/19/95 */ #ifndef _mbuf_h #define _mbuf_h #include #include #include #include #include #include #include #include #include #define PACKET_TAG_DLT 0x0100 /* data link layer type */ #define IPL_NET 6 #define mtod(x,t) ((t) mbuf_data(x)) #define ml_len(_ml) ((_ml)->ml_len) #define ml_empty(_ml) ((_ml)->ml_len == 0) #define MBUF_LIST_FIRST(_ml) ((_ml)->ml_head) #define MBUF_LIST_NEXT(_m) (mbuf_nextpkt((_m))) #define MBUF_LIST_FOREACH(_ml, _m) \ for ((_m) = MBUF_LIST_FIRST(_ml); \ (_m) != NULL; \ (_m) = MBUF_LIST_NEXT(_m)) #define mq_len(_mq) ml_len(&(_mq)->mq_list) #define mq_empty(_mq) ml_empty(&(_mq)->mq_list) #define mq_full(_mq) (mq_len((_mq)) >= (_mq)->mq_maxlen) #define mq_drops(_mq) ((_mq)->mq_drops) #define mq_set_maxlen(_mq, _l) ((_mq)->mq_maxlen = (_l)) //uipc_mbuf.c struct mbuf_list { mbuf_t ml_head; mbuf_t ml_tail; u_int ml_len; }; struct mbuf_queue { IORecursiveLock* mq_mtx; struct mbuf_list mq_list; u_int mq_maxlen; u_int mq_drops; }; /* * mbuf lists */ #define MBUF_LIST_INITIALIZER() { NULL, NULL, 0 } #define MBUF_QUEUE_INITIALIZER(_maxlen, _ipl) \ { MUTEX_INITIALIZER(_ipl), MBUF_LIST_INITIALIZER(), (_maxlen), 0 } static inline void ml_init(struct mbuf_list *ml) { ml->ml_head = ml->ml_tail = NULL; ml->ml_len = 0; } static inline void ml_enqueue(struct mbuf_list *ml, mbuf_t m) { if (ml->ml_tail == NULL) ml->ml_head = ml->ml_tail = m; else { mbuf_setnextpkt(ml->ml_tail, m); ml->ml_tail = m; } mbuf_setnextpkt(m, NULL); ml->ml_len++; } static inline void ml_enlist(struct mbuf_list *mla, struct mbuf_list *mlb) { if (!ml_empty(mlb)) { if (ml_empty(mla)) mla->ml_head = mlb->ml_head; else mbuf_setnextpkt(mla->ml_tail, mlb->ml_head); mla->ml_tail = mlb->ml_tail; mla->ml_len += mlb->ml_len; ml_init(mlb); } } static inline mbuf_t ml_dequeue(struct mbuf_list *ml) { mbuf_t m; m = ml->ml_head; if (m != NULL) { ml->ml_head = mbuf_nextpkt(m); if (ml->ml_head == NULL) ml->ml_tail = NULL; mbuf_setnextpkt(m, NULL); ml->ml_len--; } return (m); } static inline mbuf_t ml_dechain(struct mbuf_list *ml) { mbuf_t m0; m0 = ml->ml_head; ml_init(ml); return (m0); } static inline unsigned int ml_purge(struct mbuf_list *ml) { mbuf_t m, n; unsigned int len; for (m = ml->ml_head; m != NULL; m = n) { n = mbuf_nextpkt(m); mbuf_freem(m); } len = ml->ml_len; ml_init(ml); return (len); } /* * mbuf queues */ static inline void mq_init(struct mbuf_queue *mq, u_int maxlen, int ipl) { mq->mq_mtx = IORecursiveLockAlloc(); ml_init(&mq->mq_list); mq->mq_maxlen = maxlen; } static inline int mq_enqueue(struct mbuf_queue *mq, mbuf_t m) { int dropped = 0; IORecursiveLockLock(mq->mq_mtx); if (mq_len(mq) < mq->mq_maxlen) ml_enqueue(&mq->mq_list, m); else { mq->mq_drops++; dropped = 1; } if (dropped) { mbuf_freem(m); } IORecursiveLockUnlock(mq->mq_mtx); return (dropped); } static inline mbuf_t mq_dequeue(struct mbuf_queue *mq) { mbuf_t m; IORecursiveLockLock(mq->mq_mtx); m = ml_dequeue(&mq->mq_list); IORecursiveLockUnlock(mq->mq_mtx); return (m); } static inline int mq_enlist(struct mbuf_queue *mq, struct mbuf_list *ml) { mbuf_t m; int dropped = 0; IORecursiveLockLock(mq->mq_mtx); if (mq_len(mq) < mq->mq_maxlen) ml_enlist(&mq->mq_list, ml); else { dropped = ml_len(ml); mq->mq_drops += dropped; } IORecursiveLockUnlock(mq->mq_mtx); if (dropped) { while ((m = ml_dequeue(ml)) != NULL) { mbuf_freem(m); } } return (dropped); } static inline void mq_delist(struct mbuf_queue *mq, struct mbuf_list *ml) { IORecursiveLockLock(mq->mq_mtx); *ml = mq->mq_list; ml_init(&mq->mq_list); IORecursiveLockUnlock(mq->mq_mtx); } static inline mbuf_t mq_dechain(struct mbuf_queue *mq) { mbuf_t m0; IORecursiveLockLock(mq->mq_mtx); m0 = ml_dechain(&mq->mq_list); IORecursiveLockUnlock(mq->mq_mtx); return (m0); } static inline unsigned int mq_purge(struct mbuf_queue *mq) { struct mbuf_list ml; if (!mq->mq_mtx) { return 0; } mq_delist(mq, &ml); return (ml_purge(&ml)); } /* * Concatenate mbuf chain n to m. * n might be copied into m (when n->m_len is small), therefore data portion of * n could be copied into an mbuf of different mbuf type. * Therefore both chains should be of the same type (e.g. MT_DATA). * Any m_pkthdr is not updated. */ static inline void m_cat(mbuf_t m, mbuf_t n) { while (mbuf_next(m)) m = mbuf_next(m); while (n) { if (mbuf_len(n) > mbuf_trailingspace(m)) { /* just join the two chains */ mbuf_setnext(m, n); return; } /* splat the data from one into the other */ memcpy(mtod(m, caddr_t) + mbuf_len(m), mtod(n, caddr_t), mbuf_len(n)); mbuf_setlen(m, mbuf_len(m) + mbuf_len(n)); n = mbuf_free(n); } } #define M_EXTWR 0x0008 /* external storage is writable */ #define MAXMCLBYTES (64 * 1024) /* largest cluster from the stack */ /* * mbuf chain defragmenter. This function uses some evil tricks to defragment * an mbuf chain into a single buffer without changing the mbuf pointer. * This needs to know a lot of the mbuf internals to make this work. */ static inline int m_defrag(mbuf_t m, int how) { mbuf_t m0; if (mbuf_next(m) == NULL) return (0); // KASSERT(m->m_flags & M_PKTHDR); mbuf_gethdr(how, mbuf_type(m), &m0); if (m0 == NULL) return (ENOBUFS); if (mbuf_pkthdr_len(m) > mbuf_get_mhlen()) { mbuf_getcluster(how, mbuf_type(m), mbuf_pkthdr_len(m), &m0); // if (!(m0->m_flags & M_EXT)) { // m_free(m0); // return (ENOBUFS); // } } mbuf_copydata(m, 0, mbuf_pkthdr_len(m), mtod(m0, void*)); mbuf_pkthdr_setlen(m0, mbuf_pkthdr_len(m)); mbuf_setlen(m0, mbuf_pkthdr_len(m)); /* free chain behind and possible ext buf on the first mbuf */ mbuf_freem(mbuf_next(m)); mbuf_setnext(m, NULL); // if (m->m_flags & M_EXT) // m_extfree(m); /* * Bounce copy mbuf over to the original mbuf and set everything up. * This needs to reset or clear all pointers that may go into the * original mbuf chain. */ if (mbuf_flags(m0) & MBUF_EXT) { // memcpy(&m->m_ext, &m0->m_ext, sizeof(struct mbuf_ext)); // MCLINITREFERENCE(m); // m->m_flags |= m0->m_flags & (M_EXT|M_EXTWR); // m->m_data = m->m_ext.ext_buf; } else { mbuf_setdata(m, mbuf_pkthdr_header(m), mbuf_pkthdr_len(m)); memcpy(mbuf_data(m), mbuf_data(m0), mbuf_len(m0)); } mbuf_pkthdr_setlen(m, mbuf_len(m0)); mbuf_setlen(m, mbuf_len(m0)); mbuf_setflags(m0, mbuf_flags(m0) & ~(MBUF_EXT | M_EXTWR)); /* cluster is gone */ mbuf_free(m0); return (0); } /* * Duplicate mbuf pkthdr from from to to. * from must have M_PKTHDR set, and to must be empty. */ static inline int m_dup_pkthdr(mbuf_t to, mbuf_t from, int wait) { return mbuf_copy_pkthdr(to, from); } static inline mbuf_t m_dup_pkt(mbuf_t m0, unsigned int adj, int wait) { mbuf_t m; mbuf_dup(m0, wait, &m); return m; // mbuf_t m; // int len; // // len = mbuf_pkthdr_len(m0) + adj; // // IOLog("itlwm: m_dup_pkt start, len=%lu\n", len); // // if (len > MAXMCLBYTES) /* XXX */ // return (NULL); // // mbuf_get((mbuf_how_t)wait, mbuf_type(m0), &m); // if (m == NULL) // return (NULL); // // if (m_dup_pkthdr(m, m0, wait) != 0) // goto fail; // // if (len > mbuf_get_mhlen()) { //// MCLGETI(m, wait, NULL, len); // mbuf_mclget(wait, MBUF_TYPE_DATA, &m); // if (!ISSET(mbuf_flags(m), MBUF_EXT)) // goto fail; // } // // mbuf_setlen(m, len); // mbuf_pkthdr_setlen(m, len); //// m->m_len = m->m_pkthdr.len = len; // mbuf_adj(m, adj); // mbuf_copydata(m0, 0, mbuf_pkthdr_len(m0), mtod(m, caddr_t)); return (m); fail: IOLog("itlwm: m_dup_pkt fail!!!!\n"); mbuf_freem(m); return (NULL); } int if_input(struct _ifnet *ifq, struct mbuf_list *ml); static inline int if_enqueue(struct _ifnet *ifq, mbuf_t m) { if (ifq_enqueue(&ifq->if_snd, m)) { XYLog("%s if_enqueue fail!!\n", __FUNCTION__); return -ENOSPC; } return 0; } #endif /* _mbuf_h */ ================================================ FILE: itl80211/openbsd/sys/_netstat.h ================================================ // // _netstat.h // itlwm // // Created by qcwap on 2021/4/22. // Copyright © 2021 钟先耀. All rights reserved. // #ifndef _netstat_h #define _netstat_h #include static inline const char * openbsd_plural(u_int64_t n) { return (n != 1 ? "s" : ""); } /* * Dump IEEE802.11 per-interface statistics */ static inline void net80211_ifstats(struct ieee80211com *ic) { struct ieee80211_stats *stats = &ic->ic_stats; #define p(f, m) XYLog(m, (unsigned long)stats->f, openbsd_plural(stats->f)) p(is_rx_badversion, "\t%lu input packet%s with bad version\n"); p(is_rx_tooshort, "\t%lu input packet%s too short\n"); p(is_rx_wrongbss, "\t%lu input packet%s from wrong bssid\n"); p(is_rx_dup, "\t%lu input packet duplicate%s discarded\n"); p(is_rx_wrongdir, "\t%lu input packet%s with wrong direction\n"); p(is_rx_mcastecho, "\t%lu input multicast echo packet%s discarded\n"); p(is_rx_notassoc, "\t%lu input packet%s from unassociated station discarded\n"); p(is_rx_nowep, "\t%lu input encrypted packet%s without wep/wpa config discarded\n"); p(is_rx_unencrypted, "\t%lu input unencrypted packet%s with wep/wpa config discarded\n"); p(is_rx_wepfail, "\t%lu input wep/wpa packet%s processing failed\n"); p(is_rx_decap, "\t%lu input packet decapsulation%s failed\n"); p(is_rx_mgtdiscard, "\t%lu input management packet%s discarded\n"); p(is_rx_ctl, "\t%lu input control packet%s discarded\n"); p(is_rx_rstoobig, "\t%lu input packet%s with truncated rate set\n"); p(is_rx_elem_missing, "\t%lu input packet%s with missing elements\n"); p(is_rx_elem_toobig, "\t%lu input packet%s with elements too big\n"); p(is_rx_elem_toosmall, "\t%lu input packet%s with elements too small\n"); p(is_rx_badchan, "\t%lu input packet%s with invalid channel\n"); p(is_rx_chanmismatch, "\t%lu input packet%s with mismatched channel\n"); p(is_rx_nodealloc, "\t%lu node allocation%s failed\n"); p(is_rx_ssidmismatch, "\t%lu input packet%s with mismatched ssid\n"); p(is_rx_auth_unsupported, "\t%lu input packet%s with unsupported auth algorithm\n"); p(is_rx_auth_fail, "\t%lu input authentication%s failed\n"); p(is_rx_assoc_bss, "\t%lu input association%s from wrong bssid\n"); p(is_rx_assoc_notauth, "\t%lu input association%s without authentication\n"); p(is_rx_assoc_capmismatch, "\t%lu input association%s with mismatched capabilities\n"); p(is_rx_assoc_norate, "\t%lu input association%s without matching rates\n"); p(is_rx_assoc_badrsnie, "\t%lu input association%s with bad rsn ie\n"); p(is_rx_deauth, "\t%lu input deauthentication packet%s\n"); p(is_rx_disassoc, "\t%lu input disassociation packet%s\n"); p(is_rx_badsubtype, "\t%lu input packet%s with unknown subtype\n"); p(is_rx_nombuf, "\t%lu input packet%s failed for lack of mbufs\n"); p(is_rx_decryptcrc, "\t%lu input decryption%s failed on crc\n"); p(is_rx_ahdemo_mgt, "\t%lu input ahdemo management packet%s discarded\n"); p(is_rx_bad_auth, "\t%lu input packet%s with bad auth request\n"); p(is_rx_eapol_key, "\t%lu input eapol-key packet%s\n"); p(is_rx_eapol_badmic, "\t%lu input eapol-key packet%s with bad mic\n"); p(is_rx_eapol_replay, "\t%lu input eapol-key packet%s replayed\n"); p(is_rx_locmicfail, "\t%lu input packet%s with bad tkip mic\n"); p(is_rx_remmicfail, "\t%lu input tkip mic failure notification%s\n"); p(is_rx_unauth, "\t%lu input packet%s on unauthenticated port\n"); p(is_tx_nombuf, "\t%lu output packet%s failed for lack of mbufs\n"); p(is_tx_nonode, "\t%lu output packet%s failed for no nodes\n"); p(is_tx_unknownmgt, "\t%lu output packet%s of unknown management type\n"); p(is_tx_noauth, "\t%lu output packet%s on unauthenticated port\n"); p(is_scan_active, "\t%lu active scan%s started\n"); p(is_scan_passive, "\t%lu passive scan%s started\n"); p(is_node_timeout, "\t%lu node%s timed out\n"); p(is_crypto_nomem, "\t%lu failure%s with no memory for crypto ctx\n"); p(is_ccmp_dec_errs, "\t%lu ccmp decryption error%s\n"); p(is_ccmp_replays, "\t%lu ccmp replayed frame%s \n"); p(is_cmac_icv_errs, "\t%lu cmac icv error%s\n"); p(is_cmac_replays, "\t%lu cmac replayed frame%s\n"); p(is_tkip_icv_errs, "\t%lu tkip icv error%s\n"); p(is_tkip_replays, "\t%lu tkip replay%s\n"); p(is_pbac_errs, "\t%lu pbac error%s\n"); p(is_ht_nego_no_mandatory_mcs, "\t%lu HT negotiation failure%s because " "peer does not support MCS 0-7\n"); p(is_ht_nego_no_basic_mcs, "\t%lu HT negotiation failure%s because " "we do not support basic MCS set\n"); p(is_ht_nego_bad_crypto, "\t%lu HT negotiation failure%s because peer uses bad crypto\n"); p(is_ht_prot_change, "\t%lu HT protection change%s\n"); p(is_ht_rx_ba_agreements, "\t%lu new input block ack agreement%s\n"); p(is_ht_tx_ba_agreements, "\t%lu new output block ack agreement%s\n"); p(is_ht_rx_frame_below_ba_winstart, "\t%lu input frame%s below block ack window start\n"); p(is_ht_rx_frame_above_ba_winend, "\t%lu input frame%s above block ack window end\n"); p(is_ht_rx_ba_window_slide, "\t%lu input block ack window slide%s\n"); p(is_ht_rx_ba_window_jump, "\t%lu input block ack window jump%s\n"); p(is_ht_rx_ba_no_buf, "\t%lu duplicate input block ack frame%s\n"); p(is_ht_rx_ba_frame_lost, "\t%lu expected input block ack frame%s never arrived\n"); p(is_ht_rx_ba_window_gap_timeout, "\t%lu input block ack window gap%s timed out\n"); p(is_ht_rx_ba_timeout, "\t%lu input block ack agreement%s timed out\n"); p(is_ht_tx_ba_timeout, "\t%lu output block ack agreement%s timed out\n"); p(is_vht_nego_no_mandatory_mcs, "\t%lu VHT negotiation failure%s because " "peer does not support MCS 0-9\n"); p(is_vht_nego_bad_crypto, "\t%lu VHT negotiation failure%s because peer uses bad crypto\n"); #undef p } #endif /* _netstat_h */ ================================================ FILE: itl80211/openbsd/sys/_null.h ================================================ /* $OpenBSD: _null.h,v 1.2 2016/09/09 22:07:58 millert Exp $ */ /* * Written by Todd C. Miller, September 9, 2016 * Public domain. */ #ifndef NULL #if !defined(__cplusplus) #define NULL ((void *)0) #elif __cplusplus >= 201103L #define NULL nullptr #elif defined(__GNUG__) #define NULL __null #else #define NULL 0L #endif #endif ================================================ FILE: itl80211/openbsd/sys/_task.cpp ================================================ // // _task.cpp // itlwm // // Created by qcwap on 2020/3/1. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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 #include #include #include enum ETQ_STATE { TQ_S_CREATED, TQ_S_RUNNING, TQ_S_DESTROYED }; struct taskq { enum ETQ_STATE tq_state; unsigned int tq_running; unsigned int tq_waiting; unsigned int tq_nthreads; unsigned int tq_flags; const char *tq_name; IORecursiveLock *tq_mtx; struct task_list tq_worklist; }; static const char taskq_sys_name[] = "systq"; struct taskq taskq_sys = { TQ_S_CREATED, 0, 0, 1, 0, taskq_sys_name, }; struct taskq *const systq = &taskq_sys; int taskq_next_work(struct taskq *tq, struct task *work) { struct task *next; // IOLog("itlwm: taskq %s lock\n", __FUNCTION__); IORecursiveLockLock(tq->tq_mtx); while ((next = TAILQ_FIRST(&tq->tq_worklist)) == NULL) { if (tq->tq_state != TQ_S_RUNNING) { IORecursiveLockUnlock(tq->tq_mtx); return (0); } IORecursiveLockSleep(tq->tq_mtx, tq, THREAD_INTERRUPTIBLE); } TAILQ_REMOVE(&tq->tq_worklist, next, t_entry); CLR(next->t_flags, TASK_ONQUEUE); *work = *next; /* copy to caller to avoid races */ next = TAILQ_FIRST(&tq->tq_worklist); IORecursiveLockUnlock(tq->tq_mtx); // IOLog("itlwm: taskq %s unlock\n", __FUNCTION__); if (next != NULL && tq->tq_nthreads > 1) IORecursiveLockWakeup(tq->tq_mtx, tq, true); return (1); } void taskq_thread(void *xtq) { struct taskq *tq = (struct taskq *)xtq; struct task work; int last; // if (ISSET(tq->tq_flags, TASKQ_MPSAFE)) // KERNEL_UNLOCK(); // WITNESS_CHECKORDER(&tq->tq_lock_object, LOP_NEWORDER, NULL); IOLog("itlwm: taskq %s schedule task\n", __FUNCTION__); while (taskq_next_work(tq, &work)) { // WITNESS_LOCK(&tq->tq_lock_object, 0); // IOLog("itlwm: taskq worker thread=%lld work=%s\n", thread_tid(current_thread()), work.name); (*work.t_func)(work.t_arg); // IOLog("itlwm: taskq worker thread=%lld work=%s done", thread_tid(current_thread()), work.name); // WITNESS_UNLOCK(&tq->tq_lock_object, 0); // sched_pause(yield); IOSleep(1); } IOLog("itlwm: taskq %s schedule task done\n", __FUNCTION__); IORecursiveLockLock(tq->tq_mtx); last = (--tq->tq_running == 0); IORecursiveLockUnlock(tq->tq_mtx); // if (ISSET(tq->tq_flags, TASKQ_MPSAFE)) // KERNEL_LOCK(); if (last) { IOLog("itlwm: taskq %s schedule task wakeup\n", __FUNCTION__); IORecursiveLockWakeup(tq->tq_mtx, tq, false); } // kthread_exit(0); thread_terminate(current_thread()); } void taskq_create_thread(void *arg) { struct taskq *tq = (struct taskq *)arg; int rv; IOLog("itlwm: taskq %s lock\n", __FUNCTION__); IORecursiveLockLock(tq->tq_mtx); switch (tq->tq_state) { case TQ_S_DESTROYED: IOLog("itlwm: taskq %s unlock\n", __FUNCTION__); IORecursiveLockUnlock(tq->tq_mtx); if (tq != systq) { IORecursiveLockFree(tq->tq_mtx); IOFree(tq, sizeof(*tq)); } return; case TQ_S_CREATED: tq->tq_state = TQ_S_RUNNING; break; default: IOLog("itlwm: unexpected %s tq state %u", tq->tq_name, tq->tq_state); IORecursiveLockUnlock(tq->tq_mtx); if (tq != systq) { IORecursiveLockFree(tq->tq_mtx); IOFree(tq, sizeof(*tq)); } return; } do { tq->tq_running++; IOLog("itlwm: taskq %s unlock\n", __FUNCTION__); IORecursiveLockUnlock(tq->tq_mtx); thread_t new_thread; rv = kernel_thread_start((thread_continue_t)taskq_thread, tq, &new_thread); thread_deallocate(new_thread); IOLog("itlwm: taskq %s lock\n", __FUNCTION__); IORecursiveLockLock(tq->tq_mtx); if (rv != KERN_SUCCESS) { IOLog("itlwm: tasq unable to create thread for \"%s\" taskq\n", tq->tq_name); tq->tq_running--; /* could have been destroyed during kthread_create */ if (tq->tq_state == TQ_S_DESTROYED && tq->tq_running == 0) IORecursiveLockWakeup(tq->tq_mtx, tq, false); break; } } while (tq->tq_running < tq->tq_nthreads); IOLog("itlwm: taskq %s unlock\n", __FUNCTION__); IORecursiveLockUnlock(tq->tq_mtx); } void taskq_init(void) { systq->tq_mtx = IORecursiveLockAlloc(); TAILQ_INIT(&systq->tq_worklist); thread_t new_thread; kernel_thread_start((thread_continue_t)taskq_create_thread, systq, &new_thread); thread_deallocate(new_thread); } struct taskq * taskq_create(const char *name, unsigned int nthreads, int ipl, unsigned int flags) { struct taskq *tq; tq = (struct taskq *)IOMalloc(sizeof(*tq)); if (tq == NULL) return (NULL); tq->tq_state = TQ_S_CREATED; tq->tq_running = 0; tq->tq_waiting = 0; tq->tq_nthreads = nthreads; tq->tq_name = name; tq->tq_flags = flags; tq->tq_mtx = IORecursiveLockAlloc(); // mtx_init_flags(&tq->tq_mtx, ipl, name, 0); TAILQ_INIT(&tq->tq_worklist); thread_t new_thread; /* try to create a thread to guarantee that tasks will be serviced */ kernel_thread_start((thread_continue_t)taskq_create_thread, tq, &new_thread); thread_deallocate(new_thread); return (tq); } void taskq_destroy(struct taskq *tq) { if (!tq || !tq->tq_mtx) { return; } IORecursiveLockLock(tq->tq_mtx); switch (tq->tq_state) { case TQ_S_CREATED: /* tq is still referenced by taskq_create_thread */ tq->tq_state = TQ_S_DESTROYED; IORecursiveLockUnlock(tq->tq_mtx); return; case TQ_S_RUNNING: tq->tq_state = TQ_S_DESTROYED; break; default: IOLog("itlwm: unexpected %s tq state %u", tq->tq_name, tq->tq_state); tq->tq_state = TQ_S_DESTROYED; IORecursiveLockUnlock(tq->tq_mtx); return; } while (tq->tq_running > 0) { IORecursiveLockWakeup(tq->tq_mtx, tq, false); IORecursiveLockSleep(tq->tq_mtx, tq, THREAD_INTERRUPTIBLE); } IORecursiveLockUnlock(tq->tq_mtx); IORecursiveLockFree(tq->tq_mtx); if (tq != systq) { IOFree(tq, sizeof(*tq)); } } void task_set(struct task *t, void (*fn)(void *), void *arg, const char *name) { t->t_func = fn; t->t_arg = arg; t->t_flags = 0; memcpy(t->name, name, sizeof(t->name)); } int task_add(struct taskq *tq, struct task *w) { int rv = 0; // IOLog("itlwm: taskq task_add %s thread: %lld\n", w->name, thread_tid(current_thread())); if (ISSET(w->t_flags, TASK_ONQUEUE)) return (0); IORecursiveLockLock(tq->tq_mtx); if (ISSET(w->t_flags, TASK_ONQUEUE)) { // IOLog("itlwm: taskq task_add %s is already on queue thread: %lld\n", w->name, thread_tid(current_thread())); IORecursiveLockUnlock(tq->tq_mtx); return (0); } if (!ISSET(w->t_flags, TASK_ONQUEUE)) { // IOLog("itlwm: taskq task_add %s add to queue thread: %lld\n", w->name, thread_tid(current_thread())); rv = 1; SET(w->t_flags, TASK_ONQUEUE); TAILQ_INSERT_TAIL(&tq->tq_worklist, w, t_entry); } IORecursiveLockUnlock(tq->tq_mtx); if (rv) IORecursiveLockWakeup(tq->tq_mtx, tq, true); return (rv); } int task_del(struct taskq *tq, struct task *w) { int rv = 0; // IOLog("itlwm: taskq task_del %s thread: %lld\n", w->name, thread_tid(current_thread())); if (!ISSET(w->t_flags, TASK_ONQUEUE)) return (0); IORecursiveLockLock(tq->tq_mtx); if (ISSET(w->t_flags, TASK_ONQUEUE)) { rv = 1; CLR(w->t_flags, TASK_ONQUEUE); TAILQ_REMOVE(&tq->tq_worklist, w, t_entry); } IORecursiveLockUnlock(tq->tq_mtx); return (rv); } ================================================ FILE: itl80211/openbsd/sys/_task.h ================================================ // // _task.h // itlwm // // Created by qcwap on 2020/3/1. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef _task_h #define _task_h #include #include #include struct task { TAILQ_ENTRY(task) t_entry; void (*t_func)(void *); void *t_arg; unsigned int t_flags; char name[256]; }; #define TASK_ONQUEUE 1 #define TASK_BARRIER 2 TAILQ_HEAD(task_list, task); #define TASKQ_MPSAFE (1 << 0) #define TASK_INITIALIZER(_f, _a) {{ NULL, NULL }, (_f), (_a), 0 } #define task_pending(_t) ((_t)->t_flags & TASK_ONQUEUE) extern struct taskq *const systq; void taskq_init(); struct taskq *taskq_create(const char *, unsigned int, int, unsigned int); void taskq_destroy(struct taskq *); void taskq_barrier(struct taskq *); void taskq_del_barrier(struct taskq *, struct task *); void task_set(struct task *, void (*)(void *), void *, const char *); int task_add(struct taskq *, struct task *); int task_del(struct taskq *, struct task *); #endif /* _task_h */ ================================================ FILE: itl80211/openbsd/sys/arp.c ================================================ // // arp.c // itlwm // // Created by zxystd on 2023/7/1. // Copyright © 2023 钟先耀. All rights reserved. // #include "arp.h" #include #include #include #define EXTRACT_16BITS(p) \ ((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | \ (u_int16_t)*((const u_int8_t *)(p) + 1)) #define EXTRACT_32BITS(p) \ ((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | \ (u_int32_t)*((const u_int8_t *)(p) + 1) << 16 | \ (u_int32_t)*((const u_int8_t *)(p) + 2) << 8 | \ (u_int32_t)*((const u_int8_t *)(p) + 3)) #define EXTRACT_24BITS(p) \ ((u_int32_t)*((const u_int8_t *)(p) + 0) << 16 | \ (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int32_t)*((const u_int8_t *)(p) + 2)) #define EXTRACT_LE_8BITS(p) (*(p)) #define EXTRACT_LE_16BITS(p) \ ((u_int16_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int16_t)*((const u_int8_t *)(p) + 0)) #define EXTRACT_LE_32BITS(p) \ ((u_int32_t)*((const u_int8_t *)(p) + 3) << 24 | \ (u_int32_t)*((const u_int8_t *)(p) + 2) << 16 | \ (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int32_t)*((const u_int8_t *)(p) + 0)) #define EXTRACT_LE_64BITS(p) \ ((u_int64_t)*((const u_int8_t *)(p) + 7) << 56 | \ (u_int64_t)*((const u_int8_t *)(p) + 6) << 48 | \ (u_int64_t)*((const u_int8_t *)(p) + 5) << 40 | \ (u_int64_t)*((const u_int8_t *)(p) + 4) << 32 | \ (u_int64_t)*((const u_int8_t *)(p) + 3) << 24 | \ (u_int64_t)*((const u_int8_t *)(p) + 2) << 16 | \ (u_int64_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int64_t)*((const u_int8_t *)(p) + 0)) #define ESRC(ep) ((ep)->ether_shost) #define EDST(ep) ((ep)->ether_dhost) #define SHA(ap) ((ap)->arp_sha) #define THA(ap) ((ap)->arp_tha) #define SPA(ap) ((ap)->arp_spa) #define TPA(ap) ((ap)->arp_tpa) #define HASHNAMESIZE 4096 struct hnamemem { u_int32_t addr; char *name; struct hnamemem *nxt; }; struct enamemem { u_short e_addr0; u_short e_addr1; u_short e_addr2; char *e_name; u_char *e_nsap; /* used only for nsaptable[] */ #define e_bs e_nsap /* for bytestringtable */ struct enamemem *e_nxt; }; struct hnamemem hnametable[HASHNAMESIZE]; struct enamemem enametable[HASHNAMESIZE]; struct hnamemem * newhnamemem(void) { struct hnamemem *p; static struct hnamemem *ptr = NULL; static u_int num = 0; if (num <= 0) { num = 64; ptr = (struct hnamemem *)malloc(num * sizeof (*ptr), 0, 0); } --num; p = ptr++; return (p); } char * intoa(u_int32_t addr) { char *cp; u_int byte; int n; static char buf[sizeof(".xxx.xxx.xxx.xxx")]; NTOHL(addr); cp = &buf[sizeof buf]; *--cp = '\0'; n = 4; do { byte = addr & 0xff; *--cp = byte % 10 + '0'; byte /= 10; if (byte > 0) { *--cp = byte % 10 + '0'; byte /= 10; if (byte > 0) *--cp = byte + '0'; } *--cp = '.'; addr >>= 8; } while (--n > 0); return cp + 1; } char * savestr(const char *str) { size_t size; char *p; static char *strptr = NULL; static size_t strsize = 0; size = strlen(str) + 1; if (size > strsize) { strsize = 1024; if (strsize < size) strsize = size; strptr = (char *)malloc(strsize, 0, 0); } (void)strlcpy(strptr, str, size); p = strptr; strptr += size; strsize -= size; return (p); } #define HOST_NAME_MAX 255 char * getname(const u_char *ap) { char host[HOST_NAME_MAX+1]; u_int32_t addr; struct hnamemem *p; /* * Extract 32 bits in network order, dealing with alignment. */ switch ((intptr_t)ap & (sizeof(u_int32_t)-1)) { case 0: addr = *(u_int32_t *)ap; break; case 2: #if BYTE_ORDER == BIG_ENDIAN addr = ((u_int32_t)*(u_short *)ap << 16) | (u_int32_t)*(u_short *)(ap + 2); #else addr = ((u_int32_t)*(u_short *)(ap + 2) << 16) | (u_int32_t)*(u_short *)ap; #endif break; default: #if BYTE_ORDER == BIG_ENDIAN addr = ((u_int32_t)ap[0] << 24) | ((u_int32_t)ap[1] << 16) | ((u_int32_t)ap[2] << 8) | (u_int32_t)ap[3]; #else addr = ((u_int32_t)ap[3] << 24) | ((u_int32_t)ap[2] << 16) | ((u_int32_t)ap[1] << 8) | (u_int32_t)ap[0]; #endif break; } p = &hnametable[addr & (HASHNAMESIZE-1)]; for (; p->nxt; p = p->nxt) { if (p->addr == addr) return (p->name); } p->addr = addr; p->nxt = newhnamemem(); p->name = savestr(intoa(addr)); return (p->name); } char * ether_ntoa(struct ether_addr *e) { static char a[] = "xx:xx:xx:xx:xx:xx"; (void)snprintf(a, sizeof a, "%02x:%02x:%02x:%02x:%02x:%02x", e->ether_addr_octet[0], e->ether_addr_octet[1], e->ether_addr_octet[2], e->ether_addr_octet[3], e->ether_addr_octet[4], e->ether_addr_octet[5]); return (a); } static inline struct enamemem * lookup_emem(const u_char *ep) { u_int i, j, k; struct enamemem *tp; k = (ep[0] << 8) | ep[1]; j = (ep[2] << 8) | ep[3]; i = (ep[4] << 8) | ep[5]; tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)]; while (tp->e_nxt) if (tp->e_addr0 == i && tp->e_addr1 == j && tp->e_addr2 == k) return tp; else tp = tp->e_nxt; tp->e_addr0 = i; tp->e_addr1 = j; tp->e_addr2 = k; tp->e_nxt = (struct enamemem *)malloc(1 * sizeof(*tp), 0, 0); return tp; } char * etheraddr_string(const u_char *ep) { struct enamemem *tp; struct ether_addr e; tp = lookup_emem(ep); if (tp->e_name) return (tp->e_name); memcpy(e.ether_addr_octet, ep, sizeof(e.ether_addr_octet)); tp->e_name = savestr(ether_ntoa(&e)); return (tp->e_name); } #define ipaddr_string(p) getname((const u_char *)(p)) void debug_print_arp(const char *tag, mbuf_t m) { size_t len = mbuf_len(m); ether_header_t *eh = (ether_header_t *)mbuf_data(m); if (len >= sizeof(ether_header_t) && (eh->ether_type == htons(ETHERTYPE_ARP) || eh->ether_type == htons(ETHERTYPE_REVARP))) { u_char *p = (u_char *)eh + sizeof(ether_header); len -= sizeof(ether_header); const struct ether_arp *ap = (const struct ether_arp *)p; u_short pro, hrd, op; pro = EXTRACT_16BITS(&ap->arp_pro); hrd = EXTRACT_16BITS(&ap->arp_hrd); op = EXTRACT_16BITS(&ap->arp_op); if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) || ap->arp_hln != sizeof(SHA(ap)) || ap->arp_pln != sizeof(SPA(ap))) { XYLog("%s arp-#%d for proto #%d (%d) hardware #%d (%d)\n", tag, op, pro, ap->arp_pln, hrd, ap->arp_hln); } if (pro == ETHERTYPE_TRAIL) XYLog("%s trailer-\n", tag); switch (op) { case ARPOP_REQUEST: XYLog("%s arp who-has %s tell %s\n", tag, ipaddr_string(TPA(ap)), ipaddr_string(SPA(ap))); break; case ARPOP_REPLY: XYLog("%s arp reply %s is-at %s\n", tag, ipaddr_string(SPA(ap)), etheraddr_string(SHA(ap))); break; case ARPOP_REVREQUEST: XYLog("%s rarp who-is %s tell %s\n", tag, etheraddr_string(THA(ap)), etheraddr_string(SHA(ap))); break; case ARPOP_REVREPLY: XYLog("%s rarp reply %s at %s\n", tag, etheraddr_string(THA(ap)), ipaddr_string(TPA(ap))); break; default: XYLog("%s arp-#%d\n", tag, op); break; } if (hrd != ARPHRD_ETHER) XYLog("%s hardware #%d\n", tag, hrd); } } ================================================ FILE: itl80211/openbsd/sys/arp.h ================================================ // // arp.h // itlwm // // Created by zxystd on 2023/7/1. // Copyright © 2023 钟先耀. All rights reserved. // #ifndef arp_h #define arp_h #include void debug_print_arp(const char *tag, mbuf_t m); #endif /* arp_h */ ================================================ FILE: itl80211/openbsd/sys/endian.h ================================================ // // endian.h // AppleIntelWifiAdapter // // Created by 钟先耀 on 2020/1/22. // Copyright © 2020 钟先耀. All rights reserved. // /* * 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. */ #ifndef _SYS_ENDIAN_H_ #define _SYS_ENDIAN_H_ #include #include #include #define __FROM_SYS__ENDIAN #include #undef __FROM_SYS__ENDIAN #define _KERNEL #define _LITTLE_ENDIAN 1234 #define _BIG_ENDIAN 4321 #define _PDP_ENDIAN 3412 #define INET6 //ZXY DEFINE #define _BYTE_ORDER _LITTLE_ENDIAN /* Note that these macros evaluate their arguments several times. */ #define __swap16gen(x) \ (__uint16_t)(((__uint16_t)(x) & 0xffU) << 8 | ((__uint16_t)(x) & 0xff00U) >> 8) #define __swap32gen(x) \ (__uint32_t)(((__uint32_t)(x) & 0xff) << 24 | \ ((__uint32_t)(x) & 0xff00) << 8 | ((__uint32_t)(x) & 0xff0000) >> 8 |\ ((__uint32_t)(x) & 0xff000000) >> 24) #define __swap64gen(x) \ (__uint64_t)((((__uint64_t)(x) & 0xff) << 56) | \ ((__uint64_t)(x) & 0xff00ULL) << 40 | \ ((__uint64_t)(x) & 0xff0000ULL) << 24 | \ ((__uint64_t)(x) & 0xff000000ULL) << 8 | \ ((__uint64_t)(x) & 0xff00000000ULL) >> 8 | \ ((__uint64_t)(x) & 0xff0000000000ULL) >> 24 | \ ((__uint64_t)(x) & 0xff000000000000ULL) >> 40 | \ ((__uint64_t)(x) & 0xff00000000000000ULL) >> 56) static __inline __uint16_t __swap16md(__uint16_t x) { return (__swap16gen(x)); } static __inline __uint32_t __swap32md(__uint32_t x) { return (__swap32gen(x)); } static __inline __uint64_t __swap64md(__uint64_t x) { return (__swap64gen(x)); } #define __swap16(x) \ (__uint16_t)(__builtin_constant_p(x) ? __swap16gen(x) : __swap16md(x)) #define __swap32(x) \ (__uint32_t)(__builtin_constant_p(x) ? __swap32gen(x) : __swap32md(x)) #define __swap64(x) \ (__uint64_t)(__builtin_constant_p(x) ? __swap64gen(x) : __swap64md(x)) #if _BYTE_ORDER == _LITTLE_ENDIAN #define _QUAD_HIGHWORD 1 #define _QUAD_LOWWORD 0 #define __htobe16 __swap16 #define __htobe32 __swap32 #define __htobe64 __swap64 #define __htole16(x) ((__uint16_t)(x)) #define __htole32(x) ((__uint32_t)(x)) #define __htole64(x) ((__uint64_t)(x)) #define __bemtoh16(_x) __mswap16(_x) #define __bemtoh32(_x) __mswap32(_x) #define __bemtoh64(_x) __mswap64(_x) #define __htobem16(_x, _v) __swapm16((_x), (_v)) #define __htobem32(_x, _v) __swapm32((_x), (_v)) #define __htobem64(_x, _v) __swapm64((_x), (_v)) #endif /* _BYTE_ORDER == _LITTLE_ENDIAN */ #if _BYTE_ORDER == _BIG_ENDIAN #define _QUAD_HIGHWORD 0 #define _QUAD_LOWWORD 1 #define __htobe16(x) ((__uint16_t)(x)) #define __htobe32(x) ((__uint32_t)(x)) #define __htobe64(x) ((__uint64_t)(x)) #define __htole16 __swap16 #define __htole32 __swap32 #define __htole64 __swap64 #define __lemtoh16(_x) __mswap16(_x) #define __lemtoh32(_x) __mswap32(_x) #define __lemtoh64(_x) __mswap64(_x) #define __htolem16(_x, _v) __swapm16((_x), (_v)) #define __htolem32(_x, _v) __swapm32((_x), (_v)) #define __htolem64(_x, _v) __swapm64((_x), (_v)) #endif /* _BYTE_ORDER == _BIG_ENDIAN */ #ifdef _KERNEL /* * Fill in the __hto[bl]em{16,32,64} and __[bl]emtoh{16,32,64} macros * that haven't been defined yet */ #ifndef __bemtoh16 #define __bemtoh16(_x) __htobe16(*(__uint16_t *)(_x)) #define __bemtoh32(_x) __htobe32(*(__uint32_t *)(_x)) #define __bemtoh64(_x) __htobe64(*(__uint64_t *)(_x)) #endif #ifndef __htobem16 #define __htobem16(_x, _v) (*(__uint16_t *)(_x) = __htobe16(_v)) #define __htobem32(_x, _v) (*(__uint32_t *)(_x) = __htobe32(_v)) #define __htobem64(_x, _v) (*(__uint64_t *)(_x) = __htobe64(_v)) #endif #ifndef __lemtoh16 #define __lemtoh16(_x) __htole16(*(__uint16_t *)(_x)) #define __lemtoh32(_x) __htole32(*(__uint32_t *)(_x)) #define __lemtoh64(_x) __htole64(*(__uint64_t *)(_x)) #endif #ifndef __htolem16 #define __htolem16(_x, _v) (*(__uint16_t *)(_x) = __htole16(_v)) #define __htolem32(_x, _v) (*(__uint32_t *)(_x) = __htole32(_v)) #define __htolem64(_x, _v) (*(__uint64_t *)(_x) = __htole64(_v)) #endif #endif /* _KERNEL */ /* Public names */ #define LITTLE_ENDIAN _LITTLE_ENDIAN #define BIG_ENDIAN _BIG_ENDIAN #define PDP_ENDIAN _PDP_ENDIAN #define BYTE_ORDER _BYTE_ORDER /* * These are specified to be function-like macros to match the spec */ #define htobe16(x) __htobe16(x) #define htobe32(x) __htobe32(x) #define htobe64(x) __htobe64(x) #define htole16(x) __htole16(x) #define htole32(x) __htole32(x) #define htole64(x) __htole64(x) /* POSIX names */ #define be16toh(x) __htobe16(x) #define be32toh(x) __htobe32(x) #define be64toh(x) __htobe64(x) #define le16toh(x) __htole16(x) #define le32toh(x) __htole32(x) #define le64toh(x) __htole64(x) #define swap16(x) __swap16(x) #define swap32(x) __swap32(x) #define swap64(x) __swap64(x) #define swap16_multi(v, n) do { \ __size_t __swap16_multi_n = (n); \ __uint16_t *__swap16_multi_v = (v); \ \ while (__swap16_multi_n) { \ *__swap16_multi_v = swap16(*__swap16_multi_v); \ __swap16_multi_v++; \ __swap16_multi_n--; \ } \ } while (0) /* original BSD names */ #define betoh16(x) __htobe16(x) #define betoh32(x) __htobe32(x) #define betoh64(x) __htobe64(x) #define letoh16(x) __htole16(x) #define letoh32(x) __htole32(x) #define letoh64(x) __htole64(x) #ifndef htons /* these were exposed here before */ #define htons(x) __htobe16(x) #define htonl(x) __htobe32(x) #define ntohs(x) __htobe16(x) #define ntohl(x) __htobe32(x) #endif /* ancient stuff */ #define NTOHL(x) (x) = ntohl((u_int32_t)(x)) #define NTOHS(x) (x) = ntohs((u_int16_t)(x)) #define HTONL(x) (x) = htonl((u_int32_t)(x)) #define HTONS(x) (x) = htons((u_int16_t)(x)) #ifdef _KERNEL /* to/from memory conversions */ #define bemtoh16 __bemtoh16 #define bemtoh32 __bemtoh32 #define bemtoh64 __bemtoh64 #define htobem16 __htobem16 #define htobem32 __htobem32 #define htobem64 __htobem64 #define lemtoh16 __lemtoh16 #define lemtoh32 __lemtoh32 #define lemtoh64 __lemtoh64 #define htolem16 __htolem16 #define htolem32 __htolem32 #define htolem64 __htolem64 #endif /* _KERNEL */ #include #define htobe16 OSSwapHostToBigInt16 #define htobe32 OSSwapHostToBigInt32 #define htobe64 OSSwapHostToBigInt64 #define betoh16 OSSwapBigToHostInt16 #define betoh32 OSSwapBigToHostInt32 #define betoh64 OSSwapBigToHostInt64 #define be32toh(x) OSSwapBigToHostInt32(x) #define le32toh(x) OSSwapLittleToHostInt32(x) #define htole16 OSSwapHostToLittleInt16 #define htole32 OSSwapHostToLittleInt32 #define htole64 OSSwapHostToLittleInt64 #define letoh16 OSSwapLittleToHostInt16 #define letoh32 OSSwapLittleToHostInt32 #define letoh64 OSSwapLittleToHostInt64 static __inline uint16_t be16dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return ((p[0] << 8) | p[1]); } static __inline uint32_t be32dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); } static __inline uint64_t be64dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4)); } static __inline uint16_t le16dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return ((p[1] << 8) | p[0]); } static __inline uint32_t le32dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); } static __inline uint64_t le64dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); } static __inline void be16enc(void *pp, uint16_t u) { uint8_t *p = (uint8_t *)pp; p[0] = (u >> 8) & 0xff; p[1] = u & 0xff; } static __inline void be32enc(void *pp, uint32_t u) { uint8_t *p = (uint8_t *)pp; p[0] = (u >> 24) & 0xff; p[1] = (u >> 16) & 0xff; p[2] = (u >> 8) & 0xff; p[3] = u & 0xff; } static __inline void be64enc(void *pp, uint64_t u) { uint8_t *p = (uint8_t *)pp; be32enc(p, (uint32_t)(u >> 32)); be32enc(p + 4, (uint32_t)(u & 0xffffffffU)); } static __inline void le16enc(void *pp, uint16_t u) { uint8_t *p = (uint8_t *)pp; p[0] = u & 0xff; p[1] = (u >> 8) & 0xff; } static __inline void le32enc(void *pp, uint32_t u) { uint8_t *p = (uint8_t *)pp; p[0] = u & 0xff; p[1] = (u >> 8) & 0xff; p[2] = (u >> 16) & 0xff; p[3] = (u >> 24) & 0xff; } static __inline void le64enc(void *pp, uint64_t u) { uint8_t *p = (uint8_t *)pp; le32enc(p, (uint32_t)(u & 0xffffffffU)); le32enc(p + 4, (uint32_t)(u >> 32)); } #endif /* _SYS_ENDIAN_H_ */ ================================================ FILE: itl80211/openbsd/sys/pcireg.h ================================================ /* $OpenBSD: pcireg.h,v 1.57 2019/05/30 21:44:21 kettenis Exp $ */ /* $NetBSD: pcireg.h,v 1.26 2000/05/10 16:58:42 thorpej Exp $ */ /* * Copyright (c) 1995, 1996 Christopher G. Demetriou. All rights reserved. * Copyright (c) 1994, 1996 Charles Hannum. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Charles Hannum. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _DEV_PCI_PCIREG_H_ #define _DEV_PCI_PCIREG_H_ #include /* * Standardized PCI configuration information * * XXX This is not complete. */ #define PCI_CONFIG_SPACE_SIZE 0x100 #define PCIE_CONFIG_SPACE_SIZE 0x1000 /* * Device identification register; contains a vendor ID and a device ID. */ #define PCI_ID_REG 0x00 typedef u_int16_t pci_vendor_id_t; typedef u_int16_t pci_product_id_t; #define PCI_VENDOR_SHIFT 0 #define PCI_VENDOR_MASK 0xffff #define PCI_VENDOR(id) \ (((id) >> PCI_VENDOR_SHIFT) & PCI_VENDOR_MASK) #define PCI_PRODUCT_SHIFT 16 #define PCI_PRODUCT_MASK 0xffff #define PCI_PRODUCT(id) \ (((id) >> PCI_PRODUCT_SHIFT) & PCI_PRODUCT_MASK) #define PCI_ID_CODE(vid,pid) \ ((((vid) & PCI_VENDOR_MASK) << PCI_VENDOR_SHIFT) | \ (((pid) & PCI_PRODUCT_MASK) << PCI_PRODUCT_SHIFT)) /* * Command and status register. */ #define PCI_COMMAND_STATUS_REG 0x04 #define PCI_COMMAND_IO_ENABLE 0x00000001 #define PCI_COMMAND_MEM_ENABLE 0x00000002 #define PCI_COMMAND_MASTER_ENABLE 0x00000004 #define PCI_COMMAND_SPECIAL_ENABLE 0x00000008 #define PCI_COMMAND_INVALIDATE_ENABLE 0x00000010 #define PCI_COMMAND_PALETTE_ENABLE 0x00000020 #define PCI_COMMAND_PARITY_ENABLE 0x00000040 #define PCI_COMMAND_STEPPING_ENABLE 0x00000080 #define PCI_COMMAND_SERR_ENABLE 0x00000100 #define PCI_COMMAND_BACKTOBACK_ENABLE 0x00000200 #define PCI_COMMAND_INTERRUPT_DISABLE 0x00000400 #define PCI_STATUS_CAPLIST_SUPPORT 0x00100000 #define PCI_STATUS_66MHZ_SUPPORT 0x00200000 #define PCI_STATUS_UDF_SUPPORT 0x00400000 #define PCI_STATUS_BACKTOBACK_SUPPORT 0x00800000 #define PCI_STATUS_PARITY_ERROR 0x01000000 #define PCI_STATUS_DEVSEL_FAST 0x00000000 #define PCI_STATUS_DEVSEL_MEDIUM 0x02000000 #define PCI_STATUS_DEVSEL_SLOW 0x04000000 #define PCI_STATUS_DEVSEL_MASK 0x06000000 #define PCI_STATUS_TARGET_TARGET_ABORT 0x08000000 #define PCI_STATUS_MASTER_TARGET_ABORT 0x10000000 #define PCI_STATUS_MASTER_ABORT 0x20000000 #define PCI_STATUS_SPECIAL_ERROR 0x40000000 #define PCI_STATUS_PARITY_DETECT 0x80000000 #define PCI_COMMAND_STATUS_BITS \ ("\020\01IO\02MEM\03MASTER\04SPECIAL\05INVALIDATE\06PALETTE\07PARITY"\ "\010STEPPING\011SERR\012BACKTOBACK\025CAPLIST\026CLK66\027UDF"\ "\030BACK2BACK_STAT\031PARITY_STAT\032DEVSEL_MEDIUM\033DEVSEL_SLOW"\ "\034TARGET_TARGET_ABORT\035MASTER_TARGET_ABORT\036MASTER_ABORT"\ "\037SPECIAL_ERROR\040PARITY_DETECT") /* * PCI Class and Revision Register; defines type and revision of device. */ #define PCI_CLASS_REG 0x08 typedef u_int8_t pci_class_t; typedef u_int8_t pci_subclass_t; typedef u_int8_t pci_interface_t; typedef u_int8_t pci_revision_t; #define PCI_CLASS_SHIFT 24 #define PCI_CLASS_MASK 0xff #define PCI_CLASS(cr) \ (((cr) >> PCI_CLASS_SHIFT) & PCI_CLASS_MASK) #define PCI_SUBCLASS_SHIFT 16 #define PCI_SUBCLASS_MASK 0xff #define PCI_SUBCLASS(cr) \ (((cr) >> PCI_SUBCLASS_SHIFT) & PCI_SUBCLASS_MASK) #define PCI_INTERFACE_SHIFT 8 #define PCI_INTERFACE_MASK 0xff #define PCI_INTERFACE(cr) \ (((cr) >> PCI_INTERFACE_SHIFT) & PCI_INTERFACE_MASK) #define PCI_REVISION_SHIFT 0 #define PCI_REVISION_MASK 0xff #define PCI_REVISION(cr) \ (((cr) >> PCI_REVISION_SHIFT) & PCI_REVISION_MASK) /* base classes */ #define PCI_CLASS_PREHISTORIC 0x00 #define PCI_CLASS_MASS_STORAGE 0x01 #define PCI_CLASS_NETWORK 0x02 #define PCI_CLASS_DISPLAY 0x03 #define PCI_CLASS_MULTIMEDIA 0x04 #define PCI_CLASS_MEMORY 0x05 #define PCI_CLASS_BRIDGE 0x06 #define PCI_CLASS_COMMUNICATIONS 0x07 #define PCI_CLASS_SYSTEM 0x08 #define PCI_CLASS_INPUT 0x09 #define PCI_CLASS_DOCK 0x0a #define PCI_CLASS_PROCESSOR 0x0b #define PCI_CLASS_SERIALBUS 0x0c #define PCI_CLASS_WIRELESS 0x0d #define PCI_CLASS_I2O 0x0e #define PCI_CLASS_SATCOM 0x0f #define PCI_CLASS_CRYPTO 0x10 #define PCI_CLASS_DASP 0x11 #define PCI_CLASS_ACCELERATOR 0x12 #define PCI_CLASS_INSTRUMENTATION 0x13 #define PCI_CLASS_UNDEFINED 0xff /* 0x00 prehistoric subclasses */ #define PCI_SUBCLASS_PREHISTORIC_MISC 0x00 #define PCI_SUBCLASS_PREHISTORIC_VGA 0x01 /* 0x01 mass storage subclasses */ #define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00 #define PCI_SUBCLASS_MASS_STORAGE_IDE 0x01 #define PCI_SUBCLASS_MASS_STORAGE_FLOPPY 0x02 #define PCI_SUBCLASS_MASS_STORAGE_IPI 0x03 #define PCI_SUBCLASS_MASS_STORAGE_RAID 0x04 #define PCI_SUBCLASS_MASS_STORAGE_ATA 0x05 #define PCI_SUBCLASS_MASS_STORAGE_SATA 0x06 #define PCI_INTERFACE_SATA_AHCI10 0x01 #define PCI_SUBCLASS_MASS_STORAGE_SAS 0x07 #define PCI_SUBCLASS_MASS_STORAGE_NVM 0x08 #define PCI_SUBCLASS_MASS_STORAGE_UFS 0x09 #define PCI_SUBCLASS_MASS_STORAGE_MISC 0x80 /* 0x02 network subclasses */ #define PCI_SUBCLASS_NETWORK_ETHERNET 0x00 #define PCI_SUBCLASS_NETWORK_TOKENRING 0x01 #define PCI_SUBCLASS_NETWORK_FDDI 0x02 #define PCI_SUBCLASS_NETWORK_ATM 0x03 #define PCI_SUBCLASS_NETWORK_ISDN 0x04 #define PCI_SUBCLASS_NETWORK_WORLDFIP 0x05 #define PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP 0x06 #define PCI_SUBCLASS_NETWORK_INFINIBAND 0x07 #define PCI_SUBCLASS_NETWORK_MISC 0x80 /* 0x03 display subclasses */ #define PCI_SUBCLASS_DISPLAY_VGA 0x00 #define PCI_SUBCLASS_DISPLAY_XGA 0x01 #define PCI_SUBCLASS_DISPLAY_3D 0x02 #define PCI_SUBCLASS_DISPLAY_MISC 0x80 /* 0x04 multimedia subclasses */ #define PCI_SUBCLASS_MULTIMEDIA_VIDEO 0x00 #define PCI_SUBCLASS_MULTIMEDIA_AUDIO 0x01 #define PCI_SUBCLASS_MULTIMEDIA_TELEPHONY 0x02 #define PCI_SUBCLASS_MULTIMEDIA_HDAUDIO 0x03 #define PCI_SUBCLASS_MULTIMEDIA_MISC 0x80 /* 0x05 memory subclasses */ #define PCI_SUBCLASS_MEMORY_RAM 0x00 #define PCI_SUBCLASS_MEMORY_FLASH 0x01 #define PCI_SUBCLASS_MEMORY_MISC 0x80 /* 0x06 bridge subclasses */ #define PCI_SUBCLASS_BRIDGE_HOST 0x00 #define PCI_SUBCLASS_BRIDGE_ISA 0x01 #define PCI_SUBCLASS_BRIDGE_EISA 0x02 #define PCI_SUBCLASS_BRIDGE_MC 0x03 #define PCI_SUBCLASS_BRIDGE_PCI 0x04 #define PCI_SUBCLASS_BRIDGE_PCMCIA 0x05 #define PCI_SUBCLASS_BRIDGE_NUBUS 0x06 #define PCI_SUBCLASS_BRIDGE_CARDBUS 0x07 #define PCI_SUBCLASS_BRIDGE_RACEWAY 0x08 #define PCI_SUBCLASS_BRIDGE_STPCI 0x09 #define PCI_SUBCLASS_BRIDGE_INFINIBAND 0x0a #define PCI_SUBCLASS_BRIDGE_AS 0x0b #define PCI_SUBCLASS_BRIDGE_MISC 0x80 /* 0x07 communications subclasses */ #define PCI_SUBCLASS_COMMUNICATIONS_SERIAL 0x00 #define PCI_SUBCLASS_COMMUNICATIONS_PARALLEL 0x01 #define PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL 0x02 #define PCI_SUBCLASS_COMMUNICATIONS_MODEM 0x03 #define PCI_SUBCLASS_COMMUNICATIONS_GPIB 0x04 #define PCI_SUBCLASS_COMMUNICATIONS_SMARTCARD 0x05 #define PCI_SUBCLASS_COMMUNICATIONS_MISC 0x80 /* 0x08 system subclasses */ #define PCI_SUBCLASS_SYSTEM_PIC 0x00 #define PCI_SUBCLASS_SYSTEM_DMA 0x01 #define PCI_SUBCLASS_SYSTEM_TIMER 0x02 #define PCI_SUBCLASS_SYSTEM_RTC 0x03 #define PCI_SUBCLASS_SYSTEM_PCIHOTPLUG 0x04 #define PCI_SUBCLASS_SYSTEM_SDHC 0x05 #define PCI_SUBCLASS_SYSTEM_IOMMU 0x06 #define PCI_SUBCLASS_SYSTEM_ROOTCOMPEVENT 0x07 #define PCI_SUBCLASS_SYSTEM_MISC 0x80 /* 0x09 input subclasses */ #define PCI_SUBCLASS_INPUT_KEYBOARD 0x00 #define PCI_SUBCLASS_INPUT_DIGITIZER 0x01 #define PCI_SUBCLASS_INPUT_MOUSE 0x02 #define PCI_SUBCLASS_INPUT_SCANNER 0x03 #define PCI_SUBCLASS_INPUT_GAMEPORT 0x04 #define PCI_SUBCLASS_INPUT_MISC 0x80 /* 0x0a dock subclasses */ #define PCI_SUBCLASS_DOCK_GENERIC 0x00 #define PCI_SUBCLASS_DOCK_MISC 0x80 /* 0x0b processor subclasses */ #define PCI_SUBCLASS_PROCESSOR_386 0x00 #define PCI_SUBCLASS_PROCESSOR_486 0x01 #define PCI_SUBCLASS_PROCESSOR_PENTIUM 0x02 #define PCI_SUBCLASS_PROCESSOR_ALPHA 0x10 #define PCI_SUBCLASS_PROCESSOR_POWERPC 0x20 #define PCI_SUBCLASS_PROCESSOR_MIPS 0x30 #define PCI_SUBCLASS_PROCESSOR_COPROC 0x40 /* 0x0c serial bus subclasses */ #define PCI_SUBCLASS_SERIALBUS_FIREWIRE 0x00 #define PCI_SUBCLASS_SERIALBUS_ACCESS 0x01 #define PCI_SUBCLASS_SERIALBUS_SSA 0x02 #define PCI_SUBCLASS_SERIALBUS_USB 0x03 #define PCI_SUBCLASS_SERIALBUS_FIBER 0x04 #define PCI_SUBCLASS_SERIALBUS_SMBUS 0x05 #define PCI_SUBCLASS_SERIALBUS_INFINIBAND 0x06 #define PCI_SUBCLASS_SERIALBUS_IPMI 0x07 #define PCI_SUBCLASS_SERIALBUS_SERCOS 0x08 #define PCI_SUBCLASS_SERIALBUS_CANBUS 0x09 /* 0x0d wireless subclasses */ #define PCI_SUBCLASS_WIRELESS_IRDA 0x00 #define PCI_SUBCLASS_WIRELESS_CONSUMERIR 0x01 #define PCI_SUBCLASS_WIRELESS_RF 0x10 #define PCI_SUBCLASS_WIRELESS_BLUETOOTH 0x11 #define PCI_SUBCLASS_WIRELESS_BROADBAND 0x12 #define PCI_SUBCLASS_WIRELESS_802_11A 0x20 #define PCI_SUBCLASS_WIRELESS_802_11B 0x21 #define PCI_SUBCLASS_WIRELESS_MISC 0x80 /* 0x0e I2O (Intelligent I/O) subclasses */ #define PCI_SUBCLASS_I2O_STANDARD 0x00 /* 0x0f satellite communication subclasses */ /* PCI_SUBCLASS_SATCOM_??? 0x00 / * XXX ??? */ #define PCI_SUBCLASS_SATCOM_TV 0x01 #define PCI_SUBCLASS_SATCOM_AUDIO 0x02 #define PCI_SUBCLASS_SATCOM_VOICE 0x03 #define PCI_SUBCLASS_SATCOM_DATA 0x04 /* 0x10 encryption/decryption subclasses */ #define PCI_SUBCLASS_CRYPTO_NETCOMP 0x00 #define PCI_SUBCLASS_CRYPTO_ENTERTAINMENT 0x10 #define PCI_SUBCLASS_CRYPTO_MISC 0x80 /* 0x11 data acquisition and signal processing subclasses */ #define PCI_SUBCLASS_DASP_DPIO 0x00 #define PCI_SUBCLASS_DASP_TIMEFREQ 0x01 #define PCI_SUBCLASS_DASP_SYNC 0x10 #define PCI_SUBCLASS_DASP_MGMT 0x20 #define PCI_SUBCLASS_DASP_MISC 0x80 /* * PCI BIST/Header Type/Latency Timer/Cache Line Size Register. */ #define PCI_BHLC_REG 0x0c #define PCI_BIST_SHIFT 24 #define PCI_BIST_MASK 0xff #define PCI_BIST(bhlcr) \ (((bhlcr) >> PCI_BIST_SHIFT) & PCI_BIST_MASK) #define PCI_HDRTYPE_SHIFT 16 #define PCI_HDRTYPE_MASK 0xff #define PCI_HDRTYPE(bhlcr) \ (((bhlcr) >> PCI_HDRTYPE_SHIFT) & PCI_HDRTYPE_MASK) #define PCI_HDRTYPE_TYPE(bhlcr) \ (PCI_HDRTYPE(bhlcr) & 0x7f) #define PCI_HDRTYPE_MULTIFN(bhlcr) \ ((PCI_HDRTYPE(bhlcr) & 0x80) != 0) #define PCI_LATTIMER_SHIFT 8 #define PCI_LATTIMER_MASK 0xff #define PCI_LATTIMER(bhlcr) \ (((bhlcr) >> PCI_LATTIMER_SHIFT) & PCI_LATTIMER_MASK) #define PCI_CACHELINE_SHIFT 0 #define PCI_CACHELINE_MASK 0xff #define PCI_CACHELINE(bhlcr) \ (((bhlcr) >> PCI_CACHELINE_SHIFT) & PCI_CACHELINE_MASK) /* config registers for header type 0 devices */ #define PCI_MAPS 0x10 #define PCI_CARDBUSCIS 0x28 #define PCI_SUBVEND_0 0x2c #define PCI_SUBDEV_0 0x2e #define PCI_EXROMADDR_0 0x30 #define PCI_INTLINE 0x3c #define PCI_INTPIN 0x3d #define PCI_MINGNT 0x3e #define PCI_MAXLAT 0x3f /* config registers for header type 1 devices */ #define PCI_SECSTAT_1 0 /**/ #define PCI_PRIBUS_1 0x18 #define PCI_SECBUS_1 0x19 #define PCI_SUBBUS_1 0x1a #define PCI_SECLAT_1 0x1b #define PCI_IOBASEL_1 0x1c #define PCI_IOLIMITL_1 0x1d #define PCI_IOBASEH_1 0 /**/ #define PCI_IOLIMITH_1 0 /**/ #define PCI_MEMBASE_1 0x20 #define PCI_MEMLIMIT_1 0x22 #define PCI_PMBASEL_1 0x24 #define PCI_PMLIMITL_1 0x26 #define PCI_PMBASEH_1 0 /**/ #define PCI_PMLIMITH_1 0 /**/ #define PCI_BRIDGECTL_1 0 /**/ #define PCI_SUBVEND_1 0x34 #define PCI_SUBDEV_1 0x36 #define PCI_EXROMADDR_1 0x38 /* config registers for header type 2 devices */ #define PCI_SECSTAT_2 0x16 #define PCI_PRIBUS_2 0x18 #define PCI_SECBUS_2 0x19 #define PCI_SUBBUS_2 0x1a #define PCI_SECLAT_2 0x1b #define PCI_MEMBASE0_2 0x1c #define PCI_MEMLIMIT0_2 0x20 #define PCI_MEMBASE1_2 0x24 #define PCI_MEMLIMIT1_2 0x28 #define PCI_IOBASE0_2 0x2c #define PCI_IOLIMIT0_2 0x30 #define PCI_IOBASE1_2 0x34 #define PCI_IOLIMIT1_2 0x38 #define PCI_BRIDGECTL_2 0x3e #define PCI_SUBVEND_2 0x40 #define PCI_SUBDEV_2 0x42 #define PCI_PCCARDIF_2 0x44 /* * Mapping registers */ #define PCI_MAPREG_START 0x10 #define PCI_MAPREG_END 0x28 #define PCI_MAPREG_PPB_END 0x18 #define PCI_MAPREG_PCB_END 0x14 #define PCI_MAPREG_TYPE(mr) \ ((mr) & PCI_MAPREG_TYPE_MASK) #define PCI_MAPREG_TYPE_MASK 0x00000001 #define PCI_MAPREG_TYPE_MEM 0x00000000 #define PCI_MAPREG_TYPE_IO 0x00000001 #define PCI_MAPREG_MEM_TYPE(mr) \ ((mr) & PCI_MAPREG_MEM_TYPE_MASK) #define PCI_MAPREG_MEM_TYPE_MASK 0x00000006 #define PCI_MAPREG_MEM_TYPE_32BIT 0x00000000 #define PCI_MAPREG_MEM_TYPE_32BIT_1M 0x00000002 #define PCI_MAPREG_MEM_TYPE_64BIT 0x00000004 #define _PCI_MAPREG_TYPEBITS(reg) \ (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO ? \ reg & PCI_MAPREG_TYPE_MASK : \ reg & (PCI_MAPREG_TYPE_MASK|PCI_MAPREG_MEM_TYPE_MASK)) #define PCI_MAPREG_MEM_PREFETCHABLE(mr) \ (((mr) & PCI_MAPREG_MEM_PREFETCHABLE_MASK) != 0) #define PCI_MAPREG_MEM_PREFETCHABLE_MASK 0x00000008 #define PCI_MAPREG_MEM_ADDR(mr) \ ((mr) & PCI_MAPREG_MEM_ADDR_MASK) #define PCI_MAPREG_MEM_SIZE(mr) \ (PCI_MAPREG_MEM_ADDR(mr) & -PCI_MAPREG_MEM_ADDR(mr)) #define PCI_MAPREG_MEM_ADDR_MASK 0xfffffff0 #define PCI_MAPREG_MEM64_ADDR(mr) \ ((mr) & PCI_MAPREG_MEM64_ADDR_MASK) #define PCI_MAPREG_MEM64_SIZE(mr) \ (PCI_MAPREG_MEM64_ADDR(mr) & -PCI_MAPREG_MEM64_ADDR(mr)) #define PCI_MAPREG_MEM64_ADDR_MASK 0xfffffffffffffff0ULL #define PCI_MAPREG_IO_ADDR(mr) \ ((mr) & PCI_MAPREG_IO_ADDR_MASK) #define PCI_MAPREG_IO_SIZE(mr) \ (PCI_MAPREG_IO_ADDR(mr) & -PCI_MAPREG_IO_ADDR(mr)) #define PCI_MAPREG_IO_ADDR_MASK 0xfffffffe /* * Cardbus CIS pointer (PCI rev. 2.1) */ #define PCI_CARDBUS_CIS_REG 0x28 /* * Subsystem identification register; contains a vendor ID and a device ID. * Types/macros for PCI_ID_REG apply. * (PCI rev. 2.1) */ #define PCI_SUBSYS_ID_REG 0x2c /* * Expansion ROM Base Address register * (PCI rev. 2.0) */ #define PCI_ROM_REG 0x30 #define PCI_ROM_ENABLE 0x00000001 #define PCI_ROM_ADDR_MASK 0xfffff800 #define PCI_ROM_ADDR(mr) \ ((mr) & PCI_ROM_ADDR_MASK) #define PCI_ROM_SIZE(mr) \ (PCI_ROM_ADDR(mr) & -PCI_ROM_ADDR(mr)) /* * capabilities link list (PCI rev. 2.2) */ #define PCI_CAPLISTPTR_REG 0x34 /* header type 0 */ #define PCI_CARDBUS_CAPLISTPTR_REG 0x14 /* header type 2 */ #define PCI_CAPLIST_PTR(cpr) ((cpr) & 0xff) #define PCI_CAPLIST_NEXT(cr) (((cr) >> 8) & 0xff) #define PCI_CAPLIST_CAP(cr) ((cr) & 0xff) #define PCI_CAP_RESERVED 0x00 #define PCI_CAP_PWRMGMT 0x01 #define PCI_CAP_AGP 0x02 #define PCI_CAP_VPD 0x03 #define PCI_CAP_SLOTID 0x04 #define PCI_CAP_MSI 0x05 #define PCI_CAP_CPCI_HOTSWAP 0x06 #define PCI_CAP_PCIX 0x07 #define PCI_CAP_HT 0x08 #define PCI_CAP_VENDSPEC 0x09 #define PCI_CAP_DEBUGPORT 0x0a #define PCI_CAP_CPCI_RSRCCTL 0x0b #define PCI_CAP_HOTPLUG 0x0c #define PCI_CAP_AGP8 0x0e #define PCI_CAP_SECURE 0x0f #define PCI_CAP_PCIEXPRESS 0x10 #define PCI_CAP_MSIX 0x11 #define PCI_CAP_SATA 0x12 /* * Vital Product Data; access via capability pointer (PCI rev 2.2). */ #define PCI_VPD_ADDRESS_MASK 0x7fff #define PCI_VPD_ADDRESS_SHIFT 16 #define PCI_VPD_ADDRESS(ofs) \ (((ofs) & PCI_VPD_ADDRESS_MASK) << PCI_VPD_ADDRESS_SHIFT) #define PCI_VPD_DATAREG(ofs) ((ofs) + 4) #define PCI_VPD_OPFLAG 0x80000000 /* * Message Signaled Interrups; access via capability pointer. */ #define PCI_MSI_MC 0x00 #define PCI_MSI_MC_C64 0x00800000 #define PCI_MSI_MC_MME 0x00700000 #define PCI_MSI_MC_MMC 0x000e0000 #define PCI_MSI_MC_MSIE 0x00010000 #define PCI_MSI_MA 0x04 #define PCI_MSI_MAU32 0x08 #define PCI_MSI_MD32 0x08 #define PCI_MSI_MD64 0x0c /* * Power Management Control Status Register; access via capability pointer. */ #define PCI_PMCSR 0x04 #define PCI_PMCSR_STATE_MASK 0x0003 #define PCI_PMCSR_STATE_D0 0x0000 #define PCI_PMCSR_STATE_D1 0x0001 #define PCI_PMCSR_STATE_D2 0x0002 #define PCI_PMCSR_STATE_D3 0x0003 #define PCI_PMCSR_PME_STATUS 0x8000 #define PCI_PMCSR_PME_EN 0x0100 /* * HyperTransport; access via capability pointer. */ #define PCI_HT_CAP(cr) ((((cr) >> 27) < 0x08) ? \ (((cr) >> 27) & 0x1c) : (((cr) >> 27) & 0x1f)) #define PCI_HT_CAP_SLAVE 0x00 #define PCI_HT_CAP_HOST 0x04 #define PCI_HT_CAP_INTR 0x10 #define PCI_HT_CAP_MSI 0x15 #define PCI_HT_MSI_ENABLED 0x00010000 #define PCI_HT_MSI_FIXED 0x00020000 #define PCI_HT_MSI_FIXED_ADDR 0xfee00000UL #define PCI_HT_MSI_ADDR 0x04 #define PCI_HT_MSI_ADDR_HI32 0x08 #define PCI_HT_INTR_DATA 0x04 /* * PCI Express; access via capability pointer. */ #define PCI_PCIE_XCAP 0x00 #define PCI_PCIE_XCAP_SI 0x01000000 #define PCI_PCIE_XCAP_VER(x) (((x) >> 16) & 0x0f) #define PCI_PCIE_DCAP 0x04 #define PCI_PCIE_DCSR 0x08 #define PCI_PCIE_DCSR_ERO 0x00000010 #define PCI_PCIE_DCSR_ENS 0x00000800 #define PCI_PCIE_DCSR_MPS 0x00007000 #define PCI_PCIE_DCSR_CEE 0x00010000 #define PCI_PCIE_DCSR_NFE 0x00020000 #define PCI_PCIE_DCSR_FEE 0x00040000 #define PCI_PCIE_DCSR_URE 0x00080000 #define PCI_PCIE_LCAP 0x0c #define PCI_PCIE_LCSR 0x10 #define PCI_PCIE_LCSR_ASPM_L0S 0x00000001 #define PCI_PCIE_LCSR_ASPM_L1 0x00000002 #define PCI_PCIE_LCSR_ES 0x00000080 #define PCI_PCIE_LCSR_ECPM 0x00000100 #define PCI_PCIE_SLCAP 0x14 #define PCI_PCIE_SLCAP_ABP 0x00000001 #define PCI_PCIE_SLCAP_PCP 0x00000002 #define PCI_PCIE_SLCAP_MSP 0x00000004 #define PCI_PCIE_SLCAP_AIP 0x00000008 #define PCI_PCIE_SLCAP_PIP 0x00000010 #define PCI_PCIE_SLCAP_HPS 0x00000020 #define PCI_PCIE_SLCAP_HPC 0x00000040 #define PCI_PCIE_SLCSR 0x18 #define PCI_PCIE_SLCSR_ABE 0x00000001 #define PCI_PCIE_SLCSR_PFE 0x00000002 #define PCI_PCIE_SLCSR_MSE 0x00000004 #define PCI_PCIE_SLCSR_PDE 0x00000008 #define PCI_PCIE_SLCSR_CCE 0x00000010 #define PCI_PCIE_SLCSR_HPE 0x00000020 #define PCI_PCIE_SLCSR_ABP 0x00010000 #define PCI_PCIE_SLCSR_PFD 0x00020000 #define PCI_PCIE_SLCSR_MSC 0x00040000 #define PCI_PCIE_SLCSR_PDC 0x00080000 #define PCI_PCIE_SLCSR_CC 0x00100000 #define PCI_PCIE_SLCSR_MS 0x00200000 #define PCI_PCIE_SLCSR_PDS 0x00400000 #define PCI_PCIE_SLCSR_LACS 0x01000000 #define PCI_PCIE_RCSR 0x1c #define PCI_PCIE_DCSR2 0x28 #define PCI_PCIE_DCSR2_LTREN 0x00000400 #define PCI_PCIE_LCAP2 0x2c #define PCI_PCIE_LCSR2 0x30 #define PCI_PCIE_LCSR2_TLS 0x0000000f #define PCI_PCIE_LCSR2_TLS_2_5 0x00000001 #define PCI_PCIE_LCSR2_TLS_5 0x00000002 #define PCI_PCIE_LCSR2_TLS_8 0x00000003 #define PCI_PCIE_LCSR2_TLS_16 0x00000004 #define PCI_PCIE_LCSR2_TLS_32 0x00000005 /* * PCI Express; enhanced capabilities */ #define PCI_PCIE_ECAP 0x100 #define PCI_PCIE_ECAP_ID(x) (((x) & 0x0000ffff)) #define PCI_PCIE_ECAP_VER(x) (((x) >> 16) & 0x0f) #define PCI_PCIE_ECAP_NEXT(x) (((x) >> 20) & 0xffc) #define PCI_PCIE_ECAP_LAST 0x0 /* * Extended Message Signaled Interrups; access via capability pointer. */ #define PCI_MSIX_MC_MSIXE 0x80000000 #define PCI_MSIX_MC_FM 0x40000000 #define PCI_MSIX_MC_TBLSZ_MASK 0x07ff0000 #define PCI_MSIX_MC_TBLSZ_SHIFT 16 #define PCI_MSIX_MC_TBLSZ(reg) \ (((reg) & PCI_MSIX_MC_TBLSZ_MASK) >> PCI_MSIX_MC_TBLSZ_SHIFT) #define PCI_MSIX_TABLE 0x04 #define PCI_MSIX_TABLE_BIR 0x00000007 #define PCI_MSIX_TABLE_OFF ~(PCI_MSIX_TABLE_BIR) #define PCI_MSIX_MA(i) ((i) * 16 + 0) #define PCI_MSIX_MAU32(i) ((i) * 16 + 4) #define PCI_MSIX_MD(i) ((i) * 16 + 8) #define PCI_MSIX_VC(i) ((i) * 16 + 12) #define PCI_MSIX_VC_MASK 0x00000001 /* * Interrupt Configuration Register; contains interrupt pin and line. */ #define PCI_INTERRUPT_REG 0x3c typedef u_int8_t pci_intr_pin_t; typedef u_int8_t pci_intr_line_t; #define PCI_INTERRUPT_PIN_SHIFT 8 #define PCI_INTERRUPT_PIN_MASK 0xff #define PCI_INTERRUPT_PIN(icr) \ (((icr) >> PCI_INTERRUPT_PIN_SHIFT) & PCI_INTERRUPT_PIN_MASK) #define PCI_INTERRUPT_LINE_SHIFT 0 #define PCI_INTERRUPT_LINE_MASK 0xff #define PCI_INTERRUPT_LINE(icr) \ (((icr) >> PCI_INTERRUPT_LINE_SHIFT) & PCI_INTERRUPT_LINE_MASK) #define PCI_MIN_GNT_SHIFT 16 #define PCI_MIN_GNT_MASK 0xff #define PCI_MIN_GNT(icr) \ (((icr) >> PCI_MIN_GNT_SHIFT) & PCI_MIN_GNT_MASK) #define PCI_MAX_LAT_SHIFT 24 #define PCI_MAX_LAT_MASK 0xff #define PCI_MAX_LAT(icr) \ (((icr) >> PCI_MAX_LAT_SHIFT) & PCI_MAX_LAT_MASK) #define PCI_INTERRUPT_PIN_NONE 0x00 #define PCI_INTERRUPT_PIN_A 0x01 #define PCI_INTERRUPT_PIN_B 0x02 #define PCI_INTERRUPT_PIN_C 0x03 #define PCI_INTERRUPT_PIN_D 0x04 #define PCI_INTERRUPT_PIN_MAX 0x04 /* * Vital Product Data resource tags. */ struct pci_vpd_smallres { uint8_t vpdres_byte0; /* length of data + tag */ /* Actual data. */ } __packed; struct pci_vpd_largeres { uint8_t vpdres_byte0; uint8_t vpdres_len_lsb; /* length of data only */ uint8_t vpdres_len_msb; /* Actual data. */ } __packed; #define PCI_VPDRES_ISLARGE(x) ((x) & 0x80) #define PCI_VPDRES_SMALL_LENGTH(x) ((x) & 0x7) #define PCI_VPDRES_SMALL_NAME(x) (((x) >> 3) & 0xf) #define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f) #define PCI_VPDRES_TYPE_COMPATIBLE_DEVICE_ID 0x3 /* small */ #define PCI_VPDRES_TYPE_VENDOR_DEFINED 0xe /* small */ #define PCI_VPDRES_TYPE_END_TAG 0xf /* small */ #define PCI_VPDRES_TYPE_IDENTIFIER_STRING 0x02 /* large */ #define PCI_VPDRES_TYPE_VPD 0x10 /* large */ struct pci_vpd { uint8_t vpd_key0; uint8_t vpd_key1; uint8_t vpd_len; /* length of data only */ /* Actual data. */ } __packed; /* * Recommended VPD fields: * * PN Part number of assembly * FN FRU part number * EC EC level of assembly * MN Manufacture ID * SN Serial Number * * Conditionally recommended VPD fields: * * LI Load ID * RL ROM Level * RM Alterable ROM Level * NA Network Address * DD Device Driver Level * DG Diagnostic Level * LL Loadable Microcode Level * VI Vendor ID/Device ID * FU Function Number * SI Subsystem Vendor ID/Subsystem ID * * Additional VPD fields: * * Z0-ZZ User/Product Specific */ #endif /* _DEV_PCI_PCIREG_H_ */ ================================================ FILE: itl80211/openbsd/sys/timeout.h ================================================ /* * 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. */ /* $OpenBSD: timeout.h,v 1.29 2019/07/12 00:04:59 cheloha Exp $ */ /* * Copyright (c) 2000-2001 Artur Grabowski * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_TIMEOUT_H_ #define _SYS_TIMEOUT_H_ #include #include #include /* _Q_INVALIDATE */ #include #include #include #define _KERNEL #include #include #include #include #include void initTimeout(IOWorkLoop *workloop); void releaseTimeout(); int splnet(); void splx(int s); void timeout_set(CTimeout **t, void (*fn)(void *), void *arg); int timeout_add_msec(CTimeout **to, int msecs); int timeout_add_sec(CTimeout **to, int secs); int timeout_add_usec(CTimeout **to, int usecs); int timeout_del(CTimeout **to); int timeout_pending(CTimeout **to); int timeout_free(CTimeout **to); int timeout_initialized(CTimeout **to); #endif /* _SYS_TIMEOUT_H_ */ ================================================ FILE: itl80211/openbsd/sys/tree.h ================================================ /* $OpenBSD: tree.h,v 1.29 2017/07/30 19:27:20 deraadt Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ #include /* * This file defines data structures for different types of trees: * splay trees and red-black trees. * * A splay tree is a self-organizing data structure. Every operation * on the tree causes a splay to happen. The splay moves the requested * node to the root of the tree and partly rebalances it. * * This has the benefit that request locality causes faster lookups as * the requested nodes move to the top of the tree. On the other hand, * every lookup causes memory writes. * * The Balance Theorem bounds the total access time for m operations * and n inserts on an initially empty tree as O((m + n)lg n). The * amortized cost for a sequence of m accesses to a splay tree is O(lg n); * * A red-black tree is a binary search tree with the node color as an * extra attribute. It fulfills a set of conditions: * - every search path from the root to a leaf consists of the * same number of black nodes, * - each red node (except for the root) has a black parent, * - each leaf node is black. * * Every operation on a red-black tree is bounded as O(lg n). * The maximum height of a red-black tree is 2lg (n+1). */ #define SPLAY_HEAD(name, type) \ struct name { \ struct type *sph_root; /* root of the tree */ \ } #define SPLAY_INITIALIZER(root) \ { NULL } #define SPLAY_INIT(root) do { \ (root)->sph_root = NULL; \ } while (0) #define SPLAY_ENTRY(type) \ struct { \ struct type *spe_left; /* left element */ \ struct type *spe_right; /* right element */ \ } #define SPLAY_LEFT(elm, field) (elm)->field.spe_left #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right #define SPLAY_ROOT(head) (head)->sph_root #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_LINKLEFT(head, tmp, field) do { \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ } while (0) #define SPLAY_LINKRIGHT(head, tmp, field) do { \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ } while (0) #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ } while (0) /* Generates prototypes and inline functions */ #define SPLAY_PROTOTYPE(name, type, field, cmp) \ void name##_SPLAY(struct name *, struct type *); \ void name##_SPLAY_MINMAX(struct name *, int); \ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ \ /* Finds the node with the same key as elm */ \ static __unused __inline struct type * \ name##_SPLAY_FIND(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) \ return(NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) \ return (head->sph_root); \ return (NULL); \ } \ \ static __unused __inline struct type * \ name##_SPLAY_NEXT(struct name *head, struct type *elm) \ { \ name##_SPLAY(head, elm); \ if (SPLAY_RIGHT(elm, field) != NULL) { \ elm = SPLAY_RIGHT(elm, field); \ while (SPLAY_LEFT(elm, field) != NULL) { \ elm = SPLAY_LEFT(elm, field); \ } \ } else \ elm = NULL; \ return (elm); \ } \ \ static __unused __inline struct type * \ name##_SPLAY_MIN_MAX(struct name *head, int val) \ { \ name##_SPLAY_MINMAX(head, val); \ return (SPLAY_ROOT(head)); \ } /* Main splay operation. * Moves node close to the key of elm to top */ #define SPLAY_GENERATE(name, type, field, cmp) \ struct type * \ name##_SPLAY_INSERT(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) { \ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ } else { \ int __comp; \ name##_SPLAY(head, elm); \ __comp = (cmp)(elm, (head)->sph_root); \ if(__comp < 0) { \ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ SPLAY_RIGHT(elm, field) = (head)->sph_root; \ SPLAY_LEFT((head)->sph_root, field) = NULL; \ } else if (__comp > 0) { \ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT(elm, field) = (head)->sph_root; \ SPLAY_RIGHT((head)->sph_root, field) = NULL; \ } else \ return ((head)->sph_root); \ } \ (head)->sph_root = (elm); \ return (NULL); \ } \ \ struct type * \ name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ { \ struct type *__tmp; \ if (SPLAY_EMPTY(head)) \ return (NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) { \ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ } else { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ name##_SPLAY(head, elm); \ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ } \ return (elm); \ } \ return (NULL); \ } \ \ void \ name##_SPLAY(struct name *head, struct type *elm) \ { \ struct type __node, *__left, *__right, *__tmp; \ int __comp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while ((__comp = (cmp)(elm, (head)->sph_root))) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) > 0){ \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } \ \ /* Splay with either the minimum or the maximum element \ * Used to find minimum or maximum element in tree. \ */ \ void name##_SPLAY_MINMAX(struct name *head, int __comp) \ { \ struct type __node, *__left, *__right, *__tmp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while (1) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp > 0) { \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } #define SPLAY_NEGINF -1 #define SPLAY_INF 1 #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) #define SPLAY_FOREACH(x, name, head) \ for ((x) = SPLAY_MIN(name, head); \ (x) != NULL; \ (x) = SPLAY_NEXT(name, head, x)) /* Macros that define a red-black tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ } #define RB_INITIALIZER(root) \ { NULL } #define RB_INIT(root) do { \ (root)->rbh_root = NULL; \ } while (0) #define RB_BLACK 0 #define RB_RED 1 #define RB_ENTRY(type) \ struct { \ struct type *rbe_left; /* left element */ \ struct type *rbe_right; /* right element */ \ struct type *rbe_parent; /* parent element */ \ int rbe_color; /* node color */ \ } #define RB_LEFT(elm, field) (elm)->field.rbe_left #define RB_RIGHT(elm, field) (elm)->field.rbe_right #define RB_PARENT(elm, field) (elm)->field.rbe_parent #define RB_COLOR(elm, field) (elm)->field.rbe_color #define RB_ROOT(head) (head)->rbh_root #define RB_EMPTY(head) (RB_ROOT(head) == NULL) #define RB_SET(elm, parent, field) do { \ RB_PARENT(elm, field) = parent; \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ RB_COLOR(elm, field) = RB_RED; \ } while (0) #define RB_SET_BLACKRED(black, red, field) do { \ RB_COLOR(black, field) = RB_BLACK; \ RB_COLOR(red, field) = RB_RED; \ } while (0) #ifndef RB_AUGMENT #define RB_AUGMENT(x) do {} while (0) #endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ (tmp) = RB_RIGHT(elm, field); \ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_LEFT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ (tmp) = RB_LEFT(elm, field); \ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_RIGHT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) /* Generates prototypes and inline functions */ #define RB_PROTOTYPE(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ attr struct type *name##_RB_INSERT(struct name *, struct type *); \ attr struct type *name##_RB_FIND(struct name *, struct type *); \ attr struct type *name##_RB_NFIND(struct name *, struct type *); \ attr struct type *name##_RB_NEXT(struct type *); \ attr struct type *name##_RB_PREV(struct type *); \ attr struct type *name##_RB_MINMAX(struct name *, int); \ \ /* Main rb operation. * Moves node close to the key of elm to top */ #define RB_GENERATE(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp,) #define RB_GENERATE_STATIC(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static) #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ attr void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ struct type *parent, *gparent, *tmp; \ while ((parent = RB_PARENT(elm, field)) && \ RB_COLOR(parent, field) == RB_RED) { \ gparent = RB_PARENT(parent, field); \ if (parent == RB_LEFT(gparent, field)) { \ tmp = RB_RIGHT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_RIGHT(parent, field) == elm) { \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_RIGHT(head, gparent, tmp, field); \ } else { \ tmp = RB_LEFT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_LEFT(parent, field) == elm) { \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_LEFT(head, gparent, tmp, field); \ } \ } \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \ } \ \ attr void \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ { \ struct type *tmp; \ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ elm != RB_ROOT(head)) { \ if (RB_LEFT(parent, field) == elm) { \ tmp = RB_RIGHT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = RB_RIGHT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ struct type *oleft; \ if ((oleft = RB_LEFT(tmp, field)))\ RB_COLOR(oleft, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_RIGHT(head, tmp, oleft, field);\ tmp = RB_RIGHT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_RIGHT(tmp, field)) \ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_LEFT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } else { \ tmp = RB_LEFT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = RB_LEFT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ struct type *oright; \ if ((oright = RB_RIGHT(tmp, field)))\ RB_COLOR(oright, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_LEFT(head, tmp, oright, field);\ tmp = RB_LEFT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_LEFT(tmp, field)) \ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_RIGHT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } \ } \ if (elm) \ RB_COLOR(elm, field) = RB_BLACK; \ } \ \ attr struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ struct type *child, *parent, *old = elm; \ int color; \ if (RB_LEFT(elm, field) == NULL) \ child = RB_RIGHT(elm, field); \ else if (RB_RIGHT(elm, field) == NULL) \ child = RB_LEFT(elm, field); \ else { \ struct type *left; \ elm = RB_RIGHT(elm, field); \ while ((left = RB_LEFT(elm, field))) \ elm = left; \ child = RB_RIGHT(elm, field); \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ if (RB_PARENT(elm, field) == old) \ parent = elm; \ (elm)->field = (old)->field; \ if (RB_PARENT(old, field)) { \ if (RB_LEFT(RB_PARENT(old, field), field) == old)\ RB_LEFT(RB_PARENT(old, field), field) = elm;\ else \ RB_RIGHT(RB_PARENT(old, field), field) = elm;\ RB_AUGMENT(RB_PARENT(old, field)); \ } else \ RB_ROOT(head) = elm; \ RB_PARENT(RB_LEFT(old, field), field) = elm; \ if (RB_RIGHT(old, field)) \ RB_PARENT(RB_RIGHT(old, field), field) = elm; \ if (parent) { \ left = parent; \ do { \ RB_AUGMENT(left); \ } while ((left = RB_PARENT(left, field))); \ } \ goto color; \ } \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ color: \ if (color == RB_BLACK) \ name##_RB_REMOVE_COLOR(head, parent, child); \ return (old); \ } \ \ /* Inserts a node into the RB tree */ \ attr struct type * \ name##_RB_INSERT(struct name *head, struct type *elm) \ { \ struct type *tmp; \ struct type *parent = NULL; \ int comp = 0; \ tmp = RB_ROOT(head); \ while (tmp) { \ parent = tmp; \ comp = (cmp)(elm, parent); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ RB_SET(elm, parent, field); \ if (parent != NULL) { \ if (comp < 0) \ RB_LEFT(parent, field) = elm; \ else \ RB_RIGHT(parent, field) = elm; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = elm; \ name##_RB_INSERT_COLOR(head, elm); \ return (NULL); \ } \ \ /* Finds the node with the same key as elm */ \ attr struct type * \ name##_RB_FIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (NULL); \ } \ \ /* Finds the first node greater than or equal to the search key */ \ attr struct type * \ name##_RB_NFIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *res = NULL; \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) { \ res = tmp; \ tmp = RB_LEFT(tmp, field); \ } \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (res); \ } \ \ /* ARGSUSED */ \ attr struct type * \ name##_RB_NEXT(struct type *elm) \ { \ if (RB_RIGHT(elm, field)) { \ elm = RB_RIGHT(elm, field); \ while (RB_LEFT(elm, field)) \ elm = RB_LEFT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ /* ARGSUSED */ \ attr struct type * \ name##_RB_PREV(struct type *elm) \ { \ if (RB_LEFT(elm, field)) { \ elm = RB_LEFT(elm, field); \ while (RB_RIGHT(elm, field)) \ elm = RB_RIGHT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ attr struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *parent = NULL; \ while (tmp) { \ parent = tmp; \ if (val < 0) \ tmp = RB_LEFT(tmp, field); \ else \ tmp = RB_RIGHT(tmp, field); \ } \ return (parent); \ } #define RB_NEGINF -1 #define RB_INF 1 #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) #define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y) #define RB_PREV(name, x, y) name##_RB_PREV(y) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) #define RB_FOREACH(x, name, head) \ for ((x) = RB_MIN(name, head); \ (x) != NULL; \ (x) = name##_RB_NEXT(x)) #define RB_FOREACH_SAFE(x, name, head, y) \ for ((x) = RB_MIN(name, head); \ ((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \ (x) = (y)) #define RB_FOREACH_REVERSE(x, name, head) \ for ((x) = RB_MAX(name, head); \ (x) != NULL; \ (x) = name##_RB_PREV(x)) #define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ for ((x) = RB_MAX(name, head); \ ((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \ (x) = (y)) /* * Copyright (c) 2016 David Gwynne * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ struct rb_type { int (*t_compare)(const void *, const void *); void (*t_augment)(void *); unsigned int t_offset; /* offset of rb_entry in type */ }; struct rb_tree { struct rb_entry *rbt_root; }; struct rb_entry { struct rb_entry *rbt_parent; struct rb_entry *rbt_left; struct rb_entry *rbt_right; unsigned int rbt_color; }; #define RBT_HEAD(_name, _type) \ struct _name { \ struct rb_tree rbh_root; \ } #define RBT_ENTRY(_type) struct rb_entry static inline void _rb_init(struct rb_tree *rbt) { rbt->rbt_root = NULL; } static inline int _rb_empty(struct rb_tree *rbt) { return (rbt->rbt_root == NULL); } void *_rb_insert(const struct rb_type *, struct rb_tree *, void *); void *_rb_remove(const struct rb_type *, struct rb_tree *, void *); void *_rb_find(const struct rb_type *, struct rb_tree *, const void *); void *_rb_nfind(const struct rb_type *, struct rb_tree *, const void *); void *_rb_root(const struct rb_type *, struct rb_tree *); void *_rb_min(const struct rb_type *, struct rb_tree *); void *_rb_max(const struct rb_type *, struct rb_tree *); void *_rb_next(const struct rb_type *, void *); void *_rb_prev(const struct rb_type *, void *); void *_rb_left(const struct rb_type *, void *); void *_rb_right(const struct rb_type *, void *); void *_rb_parent(const struct rb_type *, void *); void _rb_set_left(const struct rb_type *, void *, void *); void _rb_set_right(const struct rb_type *, void *, void *); void _rb_set_parent(const struct rb_type *, void *, void *); void _rb_poison(const struct rb_type *, void *, unsigned long); int _rb_check(const struct rb_type *, void *, unsigned long); #define RBT_INITIALIZER(_head) { { NULL } } #define RBT_PROTOTYPE(_name, _type, _field, _cmp) \ extern const struct rb_type *const _name##_RBT_TYPE; \ \ __unused static inline void \ _name##_RBT_INIT(struct _name *head) \ { \ _rb_init(&head->rbh_root); \ } \ \ __unused static inline struct _type * \ _name##_RBT_INSERT(struct _name *head, struct _type *elm) \ { \ return _rb_insert(_name##_RBT_TYPE, &head->rbh_root, elm); \ } \ \ __unused static inline struct _type * \ _name##_RBT_REMOVE(struct _name *head, struct _type *elm) \ { \ return _rb_remove(_name##_RBT_TYPE, &head->rbh_root, elm); \ } \ \ __unused static inline struct _type * \ _name##_RBT_FIND(struct _name *head, const struct _type *key) \ { \ return _rb_find(_name##_RBT_TYPE, &head->rbh_root, key); \ } \ \ __unused static inline struct _type * \ _name##_RBT_NFIND(struct _name *head, const struct _type *key) \ { \ return _rb_nfind(_name##_RBT_TYPE, &head->rbh_root, key); \ } \ \ __unused static inline struct _type * \ _name##_RBT_ROOT(struct _name *head) \ { \ return _rb_root(_name##_RBT_TYPE, &head->rbh_root); \ } \ \ __unused static inline int \ _name##_RBT_EMPTY(struct _name *head) \ { \ return _rb_empty(&head->rbh_root); \ } \ \ __unused static inline struct _type * \ _name##_RBT_MIN(struct _name *head) \ { \ return _rb_min(_name##_RBT_TYPE, &head->rbh_root); \ } \ \ __unused static inline struct _type * \ _name##_RBT_MAX(struct _name *head) \ { \ return _rb_max(_name##_RBT_TYPE, &head->rbh_root); \ } \ \ __unused static inline struct _type * \ _name##_RBT_NEXT(struct _type *elm) \ { \ return _rb_next(_name##_RBT_TYPE, elm); \ } \ \ __unused static inline struct _type * \ _name##_RBT_PREV(struct _type *elm) \ { \ return _rb_prev(_name##_RBT_TYPE, elm); \ } \ \ __unused static inline struct _type * \ _name##_RBT_LEFT(struct _type *elm) \ { \ return _rb_left(_name##_RBT_TYPE, elm); \ } \ \ __unused static inline struct _type * \ _name##_RBT_RIGHT(struct _type *elm) \ { \ return _rb_right(_name##_RBT_TYPE, elm); \ } \ \ __unused static inline struct _type * \ _name##_RBT_PARENT(struct _type *elm) \ { \ return _rb_parent(_name##_RBT_TYPE, elm); \ } \ \ __unused static inline void \ _name##_RBT_SET_LEFT(struct _type *elm, struct _type *left) \ { \ return _rb_set_left(_name##_RBT_TYPE, elm, left); \ } \ \ __unused static inline void \ _name##_RBT_SET_RIGHT(struct _type *elm, struct _type *right) \ { \ return _rb_set_right(_name##_RBT_TYPE, elm, right); \ } \ \ __unused static inline void \ _name##_RBT_SET_PARENT(struct _type *elm, struct _type *parent) \ { \ return _rb_set_parent(_name##_RBT_TYPE, elm, parent); \ } \ \ __unused static inline void \ _name##_RBT_POISON(struct _type *elm, unsigned long poison) \ { \ return _rb_poison(_name##_RBT_TYPE, elm, poison); \ } \ \ __unused static inline int \ _name##_RBT_CHECK(struct _type *elm, unsigned long poison) \ { \ return _rb_check(_name##_RBT_TYPE, elm, poison); \ } #define RBT_GENERATE_INTERNAL(_name, _type, _field, _cmp, _aug) \ static int \ _name##_RBT_COMPARE(const void *lptr, const void *rptr) \ { \ const struct _type *l = lptr, *r = rptr; \ return _cmp(l, r); \ } \ static const struct rb_type _name##_RBT_INFO = { \ _name##_RBT_COMPARE, \ _aug, \ offsetof(struct _type, _field), \ }; \ const struct rb_type *const _name##_RBT_TYPE = &_name##_RBT_INFO #define RBT_GENERATE_AUGMENT(_name, _type, _field, _cmp, _aug) \ static void \ _name##_RBT_AUGMENT(void *ptr) \ { \ struct _type *p = ptr; \ return _aug(p); \ } \ RBT_GENERATE_INTERNAL(_name, _type, _field, _cmp, _name##_RBT_AUGMENT) #define RBT_GENERATE(_name, _type, _field, _cmp) \ RBT_GENERATE_INTERNAL(_name, _type, _field, _cmp, NULL) #define RBT_INIT(_name, _head) _name##_RBT_INIT(_head) #define RBT_INSERT(_name, _head, _elm) _name##_RBT_INSERT(_head, _elm) #define RBT_REMOVE(_name, _head, _elm) _name##_RBT_REMOVE(_head, _elm) #define RBT_FIND(_name, _head, _key) _name##_RBT_FIND(_head, _key) #define RBT_NFIND(_name, _head, _key) _name##_RBT_NFIND(_head, _key) #define RBT_ROOT(_name, _head) _name##_RBT_ROOT(_head) #define RBT_EMPTY(_name, _head) _name##_RBT_EMPTY(_head) #define RBT_MIN(_name, _head) _name##_RBT_MIN(_head) #define RBT_MAX(_name, _head) _name##_RBT_MAX(_head) #define RBT_NEXT(_name, _elm) _name##_RBT_NEXT(_elm) #define RBT_PREV(_name, _elm) _name##_RBT_PREV(_elm) #define RBT_LEFT(_name, _elm) _name##_RBT_LEFT(_elm) #define RBT_RIGHT(_name, _elm) _name##_RBT_RIGHT(_elm) #define RBT_PARENT(_name, _elm) _name##_RBT_PARENT(_elm) #define RBT_SET_LEFT(_name, _elm, _l) _name##_RBT_SET_LEFT(_elm, _l) #define RBT_SET_RIGHT(_name, _elm, _r) _name##_RBT_SET_RIGHT(_elm, _r) #define RBT_SET_PARENT(_name, _elm, _p) _name##_RBT_SET_PARENT(_elm, _p) #define RBT_POISON(_name, _elm, _p) _name##_RBT_POISON(_elm, _p) #define RBT_CHECK(_name, _elm, _p) _name##_RBT_CHECK(_elm, _p) #define RBT_FOREACH(_e, _name, _head) \ for ((_e) = RBT_MIN(_name, (_head)); \ (_e) != NULL; \ (_e) = RBT_NEXT(_name, (_e))) #define RBT_FOREACH_SAFE(_e, _name, _head, _n) \ for ((_e) = RBT_MIN(_name, (_head)); \ (_e) != NULL && ((_n) = RBT_NEXT(_name, (_e)), 1); \ (_e) = (_n)) #define RBT_FOREACH_REVERSE(_e, _name, _head) \ for ((_e) = RBT_MAX(_name, (_head)); \ (_e) != NULL; \ (_e) = RBT_PREV(_name, (_e))) #define RBT_FOREACH_REVERSE_SAFE(_e, _name, _head, _n) \ for ((_e) = RBT_MAX(_name, (_head)); \ (_e) != NULL && ((_n) = RBT_PREV(_name, (_e)), 1); \ (_e) = (_n)) #endif /* _SYS_TREE_H_ */ ================================================ FILE: itl80211/zutil.c ================================================ // // zutil.c // itlwm // // Created by qcwap on 2020/9/4. // Copyright © 2020 钟先耀. All rights reserved. // #include extern "C" { typedef struct z_mem { UInt32 alloc_size; UInt8 data[0]; } z_mem; void *zcalloc(void *opaque, uint items, uint size) { void* result = NULL; z_mem* zmem = NULL; UInt32 allocSize = items * size + sizeof(zmem); zmem = (z_mem*)IOMalloc(allocSize); if (zmem) { zmem->alloc_size = allocSize; result = (void*)&(zmem->data); } return result; } void zcfree(void *opaque, void *ptr) { UInt32* skipper = (UInt32 *)ptr - 1; z_mem* zmem = (z_mem*)skipper; IOFree((void*)zmem, zmem->alloc_size); } } ================================================ FILE: itl80211/zutil.h ================================================ // // zutil.h // itlwm // // Created by qcwap on 2020/9/4. // Copyright © 2020 钟先耀. All rights reserved. // #ifndef zutil_h #define zutil_h #include #include extern "C" { void *zcalloc(void *opaque, uint items, uint size); void zcfree(void *opaque, void *ptr); } #endif /* zutil_h */ ================================================ FILE: itlwm/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString $(MODULE_VERSION) CFBundleVersion $(MODULE_VERSION) IOKitPersonalities itlwm CFBundleIdentifier com.zxystd.itlwm IOClass itlwm IOMatchCategory IODefaultMatchCategory IOPCIPrimaryMatch 0x00008086&0x0000ffff IOProbeScore 2000 IOProviderClass IOPCIDevice IOUserClientClass ItlNetworkUserClient WiFiConfig WiFi_1 password zxyssdt112233 ssid ssdt WiFi_2 password zxyssdt112233 ssid ssdt_5G WiFi_3 password ssid Redmi WiFi_4 password 9utc5c5f ssid CMCC-KtG6 NSHumanReadableCopyright Copyright © 2020 钟先耀. All rights reserved. OSBundleLibraries com.apple.iokit.IONetworkingFamily 1.5.0 com.apple.iokit.IOPCIFamily 1.7 com.apple.kpi.bsd 8.10.0 com.apple.kpi.iokit 8.10.0 com.apple.kpi.libkern 8.10.0 com.apple.kpi.mach 8.10.0 OSBundleRequired Network-Root ================================================ FILE: itlwm/ItlNetworkUserClient.cpp ================================================ /* * 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 "ItlNetworkUserClient.hpp" #include #define super IOUserClient OSDefineMetaClassAndStructors( ItlNetworkUserClient, IOUserClient ); const IOControlMethodAction ItlNetworkUserClient::sMethods[IOCTL_ID_MAX] { sDRIVER_INFO, sSTA_INFO, sPOWER, sSTATE, sNW_ID, sWPA_KEY, sASSOCIATE, sDISASSOCIATE, sJOIN, sSCAN, sSCAN_RESULT, sTX_POWER_LEVEL, sNW_BSSID, }; bool ItlNetworkUserClient::initWithTask(task_t owningTask, void *securityID, UInt32 type, OSDictionary *properties) { fTask = owningTask; return super::initWithTask(owningTask, securityID, type, properties); } bool ItlNetworkUserClient::start(IOService *provider) { // IOLog("start\n"); if( !super::start( provider )) return false; fDriver = OSDynamicCast(itlwm, provider); fInf = fDriver->getNetworkInterface(); fIfp = fDriver->getIfp(); fDriverInfo = fDriver->fHalService->getDriverInfo(); fDriverController = fDriver->fHalService->getDriverController(); if (fDriver == NULL) { return false; } return true; } IOReturn ItlNetworkUserClient::clientClose() { // IOLog("clientClose\n"); if( !isInactive()) terminate(); return kIOReturnSuccess; } IOReturn ItlNetworkUserClient::clientDied() { // IOLog("clientDied\n"); return super::clientDied(); } void ItlNetworkUserClient::stop(IOService *provider) { // IOLog("stop\n"); super::stop( provider ); } IOReturn ItlNetworkUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments * arguments, IOExternalMethodDispatch * dispatch, OSObject * target, void * reference) { bool isSet = selector & IOCTL_MASK; selector &= ~IOCTL_MASK; // IOLog("externalMethod invoke. selector=0x%X isSet=%d\n", selector, isSet); if (selector < 0 || selector > IOCTL_ID_MAX) { return super::externalMethod(selector, arguments, NULL, this, NULL); } void *data = isSet ? (void *)arguments->structureInput : (void *)arguments->structureOutput; if (!data) { return kIOReturnError; } return sMethods[selector](this, data, isSet); } IOReturn ItlNetworkUserClient:: sDRIVER_INFO(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); ioctl_driver_info *drv_info = (ioctl_driver_info *)data; memset(drv_info, 0, sizeof(*drv_info)); drv_info->version = IOCTL_VERSION; snprintf(drv_info->bsd_name, sizeof(drv_info->bsd_name), "%s%d", ifnet_name(that->fInf->getIfnet()), ifnet_unit(that->fInf->getIfnet())); strncpy(drv_info->fw_version, that->fDriverInfo->getFirmwareVersion(), sizeof(drv_info->fw_version)); snprintf(drv_info->driver_version, sizeof(drv_info->driver_version), "%s%s", ITLWM_VERSION, GIT_COMMIT); return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sSTA_INFO(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); struct ioctl_sta_info *st = (struct ioctl_sta_info *)data; struct ieee80211com *ic = that->fDriver->fHalService->get80211Controller(); struct ieee80211_node *ic_bss = ic->ic_bss; int nss; int sgi; int index = 0; if (isSet) { return kIOReturnError; } if (ic_bss == NULL) { return kIOReturnError; } if (ic_bss->ni_chan == NULL) { return kIOReturnError; } if (ic->ic_state != IEEE80211_S_RUN) { return kIOReturnError; } st->version = IOCTL_VERSION; st->op_mode = ic->ic_curmode > 0 ? (enum itl_phy_mode)(ic->ic_curmode - 1) : ITL80211_MODE_11A; st->max_mcs = ic_bss->ni_txmcs; st->cur_mcs = ic_bss->ni_txmcs; st->channel = ieee80211_chan2ieee(ic, ic_bss->ni_chan); switch (ic->ic_bss->ni_chw) { case IEEE80211_CHAN_WIDTH_40: st->band_width = 40; break; case IEEE80211_CHAN_WIDTH_80: st->band_width = 80; break; case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: st->band_width = 160; break; default: st->band_width = 20; break; } st->rssi = -(0 - IWM_MIN_DBM - ic_bss->ni_rssi); st->noise = that->fDriver->fHalService->getDriverInfo()->getBSSNoise(); sgi = ieee80211_node_supports_sgi(ic_bss); if (ic->ic_curmode == IEEE80211_MODE_11AC) { if (sgi) { index += 1; } nss = that->fDriverInfo->getTxNSS(); switch (ic_bss->ni_chw) { case IEEE80211_CHAN_WIDTH_40: index += 4; break; case IEEE80211_CHAN_WIDTH_80: index += 8; break; case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: index += 12; break; default: break; } index += 2 * (nss - 1); const struct ieee80211_vht_rateset *rs = &ieee80211_std_ratesets_11ac[index]; st->rate = rs->rates[ic_bss->ni_txmcs % rs->nrates] / 2; } else if (ic->ic_curmode == IEEE80211_MODE_11N) { int is_40mhz = ic_bss->ni_chw == IEEE80211_CHAN_WIDTH_40; if (sgi) { index += 1; } if (is_40mhz) { index += (IEEE80211_HT_RATESET_MIMO4_SGI + 1); } index += (ic_bss->ni_txmcs / 16); nss = ic_bss->ni_txmcs / 8 + 1; index += 2 * (nss - 1); st->rate = ieee80211_std_ratesets_11n[index].rates[ic_bss->ni_txmcs % 8] / 2; } else { st->rate = ic_bss->ni_rates.rs_rates[ic_bss->ni_txrate]; } memset(st->ssid, 0, sizeof(st->ssid)); bcopy(ic->ic_des_essid, st->ssid, ic->ic_des_esslen); memset(st->bssid, 0, sizeof(st->bssid)); bcopy(ic->ic_bss->ni_bssid, st->bssid, ETHER_ADDR_LEN); return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sPOWER(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); struct ioctl_power *ip = (struct ioctl_power *)data; if (isSet) { if (ip->enabled) { that->fDriver->enable(that->fInf); } else { net80211_ifstats(that->fDriver->fHalService->get80211Controller()); that->fDriver->disable(that->fInf); } } else { memset(ip, 0, sizeof(*ip)); ip->version = IOCTL_VERSION; ip->enabled = (that->fIfp->if_flags & (IFF_UP | IFF_RUNNING)) != 0; } return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sSTATE(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); struct ioctl_state *st = (struct ioctl_state *)data; if (isSet) { return kIOReturnError; } memset(st, 0, sizeof(*st)); st->version = IOCTL_VERSION; st->state = (itl_80211_state)that->fDriver->fHalService->get80211Controller()->ic_state; return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sNW_BSSID(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); struct ioctl_nw_bssid *nwid = (struct ioctl_nw_bssid *)data; struct ieee80211com *ic = that->fDriver->fHalService->get80211Controller(); if (isSet) { if (IEEE80211_ADDR_EQ(nwid->bssid, etheranyaddr)) ic->ic_flags &= ~IEEE80211_F_DESBSSID; else { ic->ic_flags |= IEEE80211_F_DESBSSID; IEEE80211_ADDR_COPY(ic->ic_des_bssid, nwid->bssid); } return kIOReturnSuccess; } memset(nwid, 0, sizeof(*nwid)); nwid->version = IOCTL_VERSION; switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) IEEE80211_ADDR_COPY(nwid->bssid, ic->ic_myaddr); else #endif if (ic->ic_flags & IEEE80211_F_DESBSSID) IEEE80211_ADDR_COPY(nwid->bssid, ic->ic_des_bssid); else memset(nwid->bssid, 0, IEEE80211_ADDR_LEN); break; default: IEEE80211_ADDR_COPY(nwid->bssid, ic->ic_bss->ni_bssid); break; } return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sNW_ID(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); struct ioctl_nw_id *nwid = (struct ioctl_nw_id *)data; struct ieee80211com *ic = that->fDriver->fHalService->get80211Controller(); if (isSet) { if (nwid->len > IEEE80211_NWID_LEN) { return kIOReturnError; } memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); ic->ic_des_esslen = nwid->len; memcpy(ic->ic_des_essid, nwid->nwid, nwid->len); if (ic->ic_des_esslen > 0) { /* 'nwid' disables auto-join magic */ ic->ic_flags &= ~IEEE80211_F_AUTO_JOIN; } else if (!TAILQ_EMPTY(&ic->ic_ess)) { /* '-nwid' re-enables auto-join */ ic->ic_flags |= IEEE80211_F_AUTO_JOIN; } /* disable WPA/WEP */ ieee80211_disable_rsn(ic); ieee80211_disable_wep(ic); return kIOReturnSuccess; } memset(nwid, 0, sizeof(*nwid)); nwid->version = IOCTL_VERSION; switch (ic->ic_state) { case IEEE80211_S_INIT: case IEEE80211_S_SCAN: nwid->len = ic->ic_des_esslen; memcpy(nwid->nwid, ic->ic_des_essid, nwid->len); break; default: nwid->len = ic->ic_bss->ni_esslen; memcpy(nwid->nwid, ic->ic_bss->ni_essid, nwid->len); break; } return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sWPA_KEY(OSObject* target, void* data, bool isSet) { return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sASSOCIATE(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); struct ioctl_associate *as = (struct ioctl_associate *)data; that->fDriver->associateSSID(as->nwid.nwid, as->wpa_key.key); return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sDISASSOCIATE(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); struct ioctl_disassociate *dis = (struct ioctl_disassociate *)data; struct ieee80211com *ic = that->fDriver->fHalService->get80211Controller(); if (ic->ic_state > IEEE80211_S_AUTH && ic->ic_bss != NULL) IEEE80211_SEND_MGMT(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); ieee80211_del_ess(ic, (char *)dis->ssid, strlen((char *)dis->ssid), 0); ieee80211_deselect_ess(ic); if (TAILQ_EMPTY(&ic->ic_ess)) { ic->ic_flags |= IEEE80211_F_AUTO_JOIN; } ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sJOIN(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); struct ioctl_join *join = (struct ioctl_join *)data; that->fDriver->joinSSID(join->nwid.nwid, join->wpa_key.key); return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sSCAN(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); ieee80211_begin_cache_bgscan(that->fIfp); return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sSCAN_RESULT(OSObject* target, void* data, bool isSet) { ItlNetworkUserClient *that = OSDynamicCast(ItlNetworkUserClient, target); struct ioctl_network_info *ni = (struct ioctl_network_info *)data; ieee80211com *ic = that->fDriver->fHalService->get80211Controller(); if (that->fNextNodeToSend == NULL) { if (that->fScanResultWrapping) { that->fScanResultWrapping = false; return kIONoScanResult; } else { that->fNextNodeToSend = RB_MIN(ieee80211_tree, &ic->ic_tree); if (that->fNextNodeToSend == NULL) { return kIONoScanResult; } } } bzero(ni, sizeof(*ni)); ni->ni_rsncaps = that->fNextNodeToSend->ni_capinfo;; ni->channel = ieee80211_chan2ieee(ic, that->fNextNodeToSend->ni_chan); ni->ni_rsncipher = (enum itl80211_cipher)that->fNextNodeToSend->ni_rsncipher; ni->rsn_akms = that->fNextNodeToSend->ni_rsnakms; ni->rsn_ciphers = that->fNextNodeToSend->ni_rsnciphers; ni->rsn_protos = that->fNextNodeToSend->ni_rsnprotos; ni->rsn_groupcipher = (enum itl80211_cipher)that->fNextNodeToSend->ni_rsngroupcipher; ni->rsn_groupmgmtcipher = (enum itl80211_cipher)that->fNextNodeToSend->ni_rsngroupmgmtcipher; ni->supported_rsnakms = that->fNextNodeToSend->ni_supported_rsnakms; ni->supported_rsnprotos = that->fNextNodeToSend->ni_supported_rsnprotos; ni->noise = 0; ni->rssi = -(0 - IWM_MIN_DBM - that->fNextNodeToSend->ni_rssi); memcpy(ni->bssid, that->fNextNodeToSend->ni_bssid, 6); memcpy(ni->ssid, that->fNextNodeToSend->ni_essid, 32); that->fNextNodeToSend = RB_NEXT(ieee80211_tree, &ic->ic_tree, that->fNextNodeToSend); if (that->fNextNodeToSend == NULL) that->fScanResultWrapping = true; return kIOReturnSuccess; } IOReturn ItlNetworkUserClient:: sTX_POWER_LEVEL(OSObject* target, void* data, bool isSet) { return kIOReturnSuccess; } ================================================ FILE: itlwm/ItlNetworkUserClient.hpp ================================================ /* * 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. */ #ifndef ItlNetworkUserClient_hpp #define ItlNetworkUserClient_hpp #include #include #include #include #include "itlwm.hpp" #include typedef IOReturn (*IOControlMethodAction)(OSObject * target, void *data, bool isSet); class ItlNetworkUserClient : public IOUserClient { OSDeclareDefaultStructors( ItlNetworkUserClient ); public: virtual bool start( IOService * provider ) override; virtual void stop( IOService * provider ) override; virtual bool initWithTask( task_t owningTask, void * securityID, UInt32 type, OSDictionary * properties ) override; virtual IOReturn clientDied (void) override; virtual IOReturn clientClose( void ) override; virtual IOReturn externalMethod( uint32_t selector, IOExternalMethodArguments * arguments, IOExternalMethodDispatch * dispatch = 0, OSObject * target = 0, void * reference = 0 ) override; private: static IOReturn sDRIVER_INFO(OSObject* target, void* data, bool isSet); static IOReturn sSTA_INFO(OSObject* target, void* data, bool isSet); static IOReturn sPOWER(OSObject* target, void* data, bool isSet); static IOReturn sSTATE(OSObject* target, void* data, bool isSet); static IOReturn sNW_ID(OSObject* target, void* data, bool isSet); static IOReturn sWPA_KEY(OSObject* target, void* data, bool isSet); static IOReturn sASSOCIATE(OSObject* target, void* data, bool isSet); static IOReturn sDISASSOCIATE(OSObject* target, void* data, bool isSet); static IOReturn sJOIN(OSObject* target, void* data, bool isSet); static IOReturn sSCAN(OSObject* target, void* data, bool isSet); static IOReturn sSCAN_RESULT(OSObject* target, void* data, bool isSet); static IOReturn sTX_POWER_LEVEL(OSObject* target, void* data, bool isSet); static IOReturn sNW_BSSID(OSObject* target, void* data, bool isSet); static const IOControlMethodAction sMethods[IOCTL_ID_MAX]; private: task_t fTask; itlwm *fDriver; IOEthernetInterface *fInf; struct _ifnet *fIfp; ItlDriverController *fDriverController; ItlDriverInfo *fDriverInfo; protected: bool fScanResultWrapping; ieee80211_node *fNextNodeToSend; }; #endif /* ItlNetworkUserClient_hpp */ ================================================ FILE: itlwm/PrivateSPI.pch ================================================ #include #include #include #ifdef __PRIVATE_SPI__ typedef u_int32_t ifnet_ctl_cmd_t; #endif #ifndef __MAC_12_0 #define __MAC_12_0 120000 #endif #ifndef __MAC_13_0 #define __MAC_13_0 130000 #endif #ifndef __MAC_14_0 #define __MAC_14_0 140000 #endif #ifndef __MAC_14_4 #define __MAC_14_4 140400 #endif ================================================ FILE: itlwm/hal_iwm/ItlIwm.cpp ================================================ /* * 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 "ItlIwm.hpp" #define super ItlHalService OSDefineMetaClassAndStructors(ItlIwm, ItlHalService) void ItlIwm:: detach(IOPCIDevice *device) { struct _ifnet *ifp = &com.sc_ic.ic_ac.ac_if; struct iwm_softc *sc = &com; for (int txq_i = 0; txq_i < nitems(sc->txq); txq_i++) iwm_free_tx_ring(sc, &sc->txq[txq_i]); iwm_rs_free(sc); iwm_free_rx_ring(sc, &sc->rxq); iwm_dma_contig_free(&sc->ict_dma); iwm_dma_contig_free(&sc->kw_dma); iwm_dma_contig_free(&sc->sched_dma); iwm_dma_contig_free(&sc->fw_dma); ieee80211_ifdetach(ifp); taskq_destroy(systq); taskq_destroy(com.sc_nswq); releaseAll(); } bool ItlIwm:: attach(IOPCIDevice *device) { pci.pa_tag = device; pci.workloop = getMainWorkLoop(); if (!iwm_attach(&com, &pci)) { detach(device); releaseAll(); return false; } return true; } void ItlIwm:: free() { XYLog("%s\n", __FUNCTION__); super::free(); } void ItlIwm:: releaseAll() { XYLog("%s\n", __FUNCTION__); pci_intr_handle *intrHandler = com.ih; if (com.sc_calib_to) { timeout_del(&com.sc_calib_to); timeout_free(&com.sc_calib_to); } if (com.sc_led_blink_to) { timeout_del(&com.sc_led_blink_to); timeout_free(&com.sc_led_blink_to); } if (intrHandler) { if (intrHandler->intr && intrHandler->workloop) { // intrHandler->intr->disable(); intrHandler->workloop->removeEventSource(intrHandler->intr); intrHandler->intr->release(); } intrHandler->intr = NULL; intrHandler->workloop = NULL; intrHandler->arg = NULL; intrHandler->dev = NULL; intrHandler->func = NULL; intrHandler->release(); com.ih = NULL; } pci.pa_tag = NULL; pci.workloop = NULL; } IOReturn ItlIwm:: enable(IONetworkInterface *netif) { XYLog("%s\n", __PRETTY_FUNCTION__); struct _ifnet *ifp = &com.sc_ic.ic_ac.ac_if; if (ifp->if_flags & IFF_UP) { XYLog("%s already in activating state\n", __FUNCTION__); return kIOReturnSuccess; } ifp->if_flags |= IFF_UP; iwm_activate(&com, DVACT_RESUME); iwm_activate(&com, DVACT_WAKEUP); return kIOReturnSuccess; } IOReturn ItlIwm:: disable(IONetworkInterface *netif) { struct _ifnet *ifp = &com.sc_ic.ic_ac.ac_if; if (!(ifp->if_flags & IFF_UP)) { XYLog("%s already in diactivating state\n", __FUNCTION__); return kIOReturnSuccess; } ifp->if_flags &= ~IFF_UP; iwm_activate(&com, DVACT_QUIESCE); return kIOReturnSuccess; } struct ieee80211com *ItlIwm:: get80211Controller() { return &com.sc_ic; } ItlDriverInfo *ItlIwm:: getDriverInfo() { return this; } ItlDriverController *ItlIwm:: getDriverController() { return this; } void ItlIwm:: clearScanningFlags() { com.sc_flags &= ~(IWM_FLAG_SCANNING | IWM_FLAG_BGSCAN); } IOReturn ItlIwm:: setMulticastList(IOEthernetAddress *addr, int count) { struct ieee80211com *ic = &com.sc_ic; struct iwm_mcast_filter_cmd *cmd; int len; uint8_t addr_count; int err; if (ic->ic_state != IEEE80211_S_RUN || ic->ic_bss == NULL) return kIOReturnError; addr_count = count; if (count > IWM_MAX_MCAST_FILTERING_ADDRESSES) addr_count = 0; if (addr == NULL) addr_count = 0; len = roundup(sizeof(struct iwm_mcast_filter_cmd) + addr_count * ETHER_ADDR_LEN, 4); XYLog("%s multicast count=%d bssid=%s\n", __FUNCTION__, count, ether_sprintf(ic->ic_bss->ni_bssid)); cmd = (struct iwm_mcast_filter_cmd *)malloc(len, 0, 0); if (!cmd) return kIOReturnError; cmd->pass_all = addr_count == 0; cmd->count = addr_count; cmd->port_id = 0; IEEE80211_ADDR_COPY(cmd->bssid, ic->ic_bss->ni_bssid); if (addr_count > 0) memcpy(cmd->addr_list, addr->bytes, ETHER_ADDR_LEN * cmd->count); err = iwm_send_cmd_pdu(&com, IWM_MCAST_FILTER_CMD, IWM_CMD_ASYNC, len, cmd); ::free(cmd); return err ? kIOReturnError : kIOReturnSuccess; } const char *ItlIwm:: getFirmwareVersion() { return com.sc_fwver; } const char *ItlIwm:: getFirmwareName() { return com.sc_fwname; } UInt32 ItlIwm:: supportedFeatures() { return kIONetworkFeatureMultiPages; } const char *ItlIwm:: getFirmwareCountryCode() { return com.sc_fw_mcc; } uint32_t ItlIwm:: getTxQueueSize() { return IWM_TX_RING_COUNT; } int16_t ItlIwm:: getBSSNoise() { return com.sc_noise; } bool ItlIwm:: is5GBandSupport() { return com.sc_nvm.sku_cap_band_52GHz_enable; } int ItlIwm:: getTxNSS() { return iwm_mimo_enabled(&com) && (com.sc_ic.ic_bss != NULL && com.sc_ic.ic_bss->ni_rx_nss > 1) ? 2 : 1; } ================================================ FILE: itlwm/hal_iwm/ItlIwm.hpp ================================================ /* * 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. */ #ifndef ItlIwm_hpp #define ItlIwm_hpp #include #include "itlhdr.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class ItlIwm : public ItlHalService, ItlDriverInfo, ItlDriverController { OSDeclareDefaultStructors(ItlIwm) public: //kext void free() override; virtual bool attach(IOPCIDevice *device) override; virtual void detach(IOPCIDevice *device) override; IOReturn enable(IONetworkInterface *netif) override; IOReturn disable(IONetworkInterface *netif) override; virtual struct ieee80211com *get80211Controller() override; static bool intrFilter(OSObject *object, IOFilterInterruptEventSource *src); static IOReturn _iwm_start_task(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); void releaseAll(); struct _ifnet *getIfp(); struct iwm_softc *getSoft(); IOEthernetInterface *getNetworkInterface(); virtual ItlDriverInfo *getDriverInfo() override; virtual ItlDriverController *getDriverController() override; //driver info virtual const char *getFirmwareVersion() override; virtual int16_t getBSSNoise() override; virtual bool is5GBandSupport() override; virtual int getTxNSS() override; virtual const char *getFirmwareName() override; virtual UInt32 supportedFeatures() override; virtual const char *getFirmwareCountryCode() override; virtual uint32_t getTxQueueSize() override; //driver controller virtual void clearScanningFlags() override; virtual IOReturn setMulticastList(IOEthernetAddress *addr, int count) override; //utils int iwm_send_bt_init_conf(struct iwm_softc *); //fw static uint8_t iwm_fw_valid_tx_ant(struct iwm_softc *sc); static uint8_t iwm_fw_valid_rx_ant(struct iwm_softc *sc); void iwm_toggle_tx_ant(struct iwm_softc *sc, uint8_t *ant); uint32_t iwm_get_tx_ant(struct iwm_softc *sc, struct ieee80211_node *ni, int type, struct ieee80211_frame *wh); //scan uint8_t iwm_umac_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_channel_cfg_umac *chan, int n_ssids, int bgscan); //coex uint16_t iwm_coex_agg_time_limit(struct iwm_softc *, struct ieee80211_node *); uint8_t iwm_coex_tx_prio(struct iwm_softc *, struct ieee80211_frame *, uint8_t); static bool iwm_coex_is_ant_avail(struct iwm_softc *, u8); static bool iwm_coex_is_mimo_allowed(struct iwm_softc *, struct ieee80211_node *); static bool iwm_coex_is_tpc_allowed(struct iwm_softc *, bool); static bool iwm_coex_is_shared_ant_avail(struct iwm_softc *); uint8_t iwm_lookup_cmd_ver(struct iwm_softc *, uint8_t, uint8_t); int iwm_store_cscheme(struct iwm_softc *, uint8_t *, size_t); int iwm_firmware_store_section(struct iwm_softc *, enum iwm_ucode_type, uint8_t *, size_t); int iwm_set_default_calib(struct iwm_softc *, const void *); void iwm_fw_info_free(struct iwm_fw_info *); int iwm_read_firmware(struct iwm_softc *, enum iwm_ucode_type); uint32_t iwm_read_prph_unlocked(struct iwm_softc *, uint32_t); uint32_t iwm_read_prph(struct iwm_softc *, uint32_t); void iwm_write_prph_unlocked(struct iwm_softc *, uint32_t, uint32_t); void iwm_write_prph(struct iwm_softc *, uint32_t, uint32_t); void iwm_write_prph64(struct iwm_softc *, uint64_t, uint64_t); int iwm_read_mem(struct iwm_softc *, uint32_t, void *, int); int iwm_write_mem(struct iwm_softc *, uint32_t, const void *, int); int iwm_write_mem32(struct iwm_softc *, uint32_t, uint32_t); int iwm_poll_bit(struct iwm_softc *, int, uint32_t, uint32_t, int); int iwm_nic_lock(struct iwm_softc *); void iwm_nic_assert_locked(struct iwm_softc *); void iwm_nic_unlock(struct iwm_softc *); void iwm_set_bits_mask_prph(struct iwm_softc *, uint32_t, uint32_t, uint32_t); void iwm_set_bits_prph(struct iwm_softc *, uint32_t, uint32_t); void iwm_clear_bits_prph(struct iwm_softc *, uint32_t, uint32_t); int iwm_dma_contig_alloc(bus_dma_tag_t, struct iwm_dma_info *, bus_size_t, bus_size_t); void iwm_dma_contig_free(struct iwm_dma_info *); int iwm_alloc_rx_ring(struct iwm_softc *, struct iwm_rx_ring *); void iwm_disable_rx_dma(struct iwm_softc *); void iwm_reset_rx_ring(struct iwm_softc *, struct iwm_rx_ring *); void iwm_free_rx_ring(struct iwm_softc *, struct iwm_rx_ring *); int iwm_alloc_tx_ring(struct iwm_softc *, struct iwm_tx_ring *, int); void iwm_reset_tx_ring(struct iwm_softc *, struct iwm_tx_ring *); void iwm_free_tx_ring(struct iwm_softc *, struct iwm_tx_ring *); void iwm_enable_rfkill_int(struct iwm_softc *); int iwm_check_rfkill(struct iwm_softc *); void iwm_enable_interrupts(struct iwm_softc *); void iwm_enable_fwload_interrupt(struct iwm_softc *); void iwm_restore_interrupts(struct iwm_softc *); void iwm_disable_interrupts(struct iwm_softc *); void iwm_ict_reset(struct iwm_softc *); int iwm_set_hw_ready(struct iwm_softc *); int iwm_prepare_card_hw(struct iwm_softc *); void iwm_apm_config(struct iwm_softc *); int iwm_apm_init(struct iwm_softc *); void iwm_apm_stop(struct iwm_softc *); int iwm_allow_mcast(struct iwm_softc *); void iwm_init_msix_hw(struct iwm_softc *); void iwm_conf_msix_hw(struct iwm_softc *, int); int iwm_clear_persistence_bit(struct iwm_softc *); int iwm_start_hw(struct iwm_softc *); void iwm_stop_device(struct iwm_softc *); void iwm_nic_config(struct iwm_softc *); int iwm_nic_rx_init(struct iwm_softc *); int iwm_nic_rx_legacy_init(struct iwm_softc *); int iwm_nic_rx_mq_init(struct iwm_softc *); int iwm_nic_tx_init(struct iwm_softc *); int iwm_nic_init(struct iwm_softc *); int iwm_enable_ac_txq(struct iwm_softc *, int, int); int iwm_enable_txq(struct iwm_softc *, int, int, int, int, int, int); int iwm_disable_txq(struct iwm_softc *, uint8_t, uint8_t, uint8_t); int iwm_enable_default_tx_queues(struct iwm_softc *); int iwm_disable_tx_queues(struct iwm_softc *); int iwm_post_alive(struct iwm_softc *); struct iwm_phy_db_entry *iwm_phy_db_get_section(struct iwm_softc *, uint16_t, uint16_t); int iwm_phy_db_set_section(struct iwm_softc *, struct iwm_calib_res_notif_phy_db *); int iwm_is_valid_channel(uint16_t); uint8_t iwm_ch_id_to_ch_index(uint16_t); uint16_t iwm_channel_id_to_papd(uint16_t); uint16_t iwm_channel_id_to_txp(struct iwm_softc *, uint16_t); int iwm_phy_db_get_section_data(struct iwm_softc *, uint32_t, uint8_t **, uint16_t *, uint16_t); int iwm_send_phy_db_cmd(struct iwm_softc *, uint16_t, uint16_t, void *); int iwm_phy_db_send_all_channel_groups(struct iwm_softc *, uint16_t, uint8_t); int iwm_send_phy_db_data(struct iwm_softc *); void iwm_te_v2_to_v1(const struct iwm_time_event_cmd_v2 *, struct iwm_time_event_cmd_v1 *); int iwm_send_time_event_cmd(struct iwm_softc *, const struct iwm_time_event_cmd *); void iwm_protect_session(struct iwm_softc *, struct iwm_node *, uint32_t, uint32_t); void iwm_unprotect_session(struct iwm_softc *, struct iwm_node *); int iwm_nvm_read_chunk(struct iwm_softc *, uint16_t, uint16_t, uint16_t, uint8_t *, uint16_t *); int iwm_nvm_read_section(struct iwm_softc *, uint16_t, uint8_t *, uint16_t *, size_t); void iwm_init_channel_map(struct iwm_softc *, const uint16_t * const, const uint8_t *nvm_channels, size_t nchan); int iwm_mimo_enabled(struct iwm_softc *); void iwm_setup_ht_rates(struct iwm_softc *); void iwm_setup_vht_rates(struct iwm_softc *); static void iwm_mac_ctxt_task(void *); static void iwm_chan_ctxt_task(void *); static void iwm_updateprot(struct ieee80211com *); static void iwm_updateslot(struct ieee80211com *); static void iwm_updateedca(struct ieee80211com *); static void iwm_updatedtim(struct ieee80211com *); void iwm_init_reorder_buffer(struct iwm_reorder_buffer *, uint16_t, uint16_t); void iwm_clear_reorder_buffer(struct iwm_softc *, struct iwm_rxba_data *); static int iwm_ampdu_rx_start(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwm_ampdu_rx_stop(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwm_rx_ba_session_expired(void *); static void iwm_reorder_timer_expired(void *); static uint8_t iwm_num_of_ant(uint8_t mask); int iwm_sta_rx_agg(struct iwm_softc *, struct ieee80211_node *, uint8_t, uint16_t, uint16_t, int, int); static int iwm_ampdu_tx_start(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwm_ampdu_tx_stop(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwm_update_chw(struct ieee80211com *); int iwm_sta_tx_agg(struct iwm_softc *, struct ieee80211_node *, uint8_t, uint8_t, uint16_t, int); static void iwm_ba_task(void *); int iwm_parse_nvm_data(struct iwm_softc *, const uint16_t *, const uint16_t *, const uint16_t *, const uint16_t *, const uint16_t *, const uint16_t *, int); void iwm_set_hw_address_8000(struct iwm_softc *, struct iwm_nvm_data *, const uint16_t *, const uint16_t *); int iwm_parse_nvm_sections(struct iwm_softc *, struct iwm_nvm_section *); int iwm_nvm_init(struct iwm_softc *); int iwm_firmware_load_sect(struct iwm_softc *, uint32_t, const uint8_t *, uint32_t); int iwm_firmware_load_chunk(struct iwm_softc *, uint32_t, const uint8_t *, uint32_t); int iwm_load_firmware_7000(struct iwm_softc *, enum iwm_ucode_type); int iwm_load_cpu_sections_8000(struct iwm_softc *, struct iwm_fw_sects *, int , int *); int iwm_load_firmware_8000(struct iwm_softc *, enum iwm_ucode_type); int iwm_load_firmware(struct iwm_softc *, enum iwm_ucode_type); int iwm_start_fw(struct iwm_softc *, enum iwm_ucode_type); int iwm_send_tx_ant_cfg(struct iwm_softc *, uint8_t); int iwm_send_phy_cfg_cmd(struct iwm_softc *); int iwm_load_ucode_wait_alive(struct iwm_softc *, enum iwm_ucode_type); int iwm_send_dqa_cmd(struct iwm_softc *); int iwm_run_init_mvm_ucode(struct iwm_softc *, int); int iwm_config_ltr(struct iwm_softc *); int iwm_rx_addbuf(struct iwm_softc *, int, int); int iwm_get_signal_strength(struct iwm_softc *, struct ieee80211_rx_status *, struct iwm_rx_phy_info *); int iwm_rxmq_get_signal_strength(struct iwm_softc *, struct ieee80211_rx_status *, uint32_t, struct iwm_rx_mpdu_desc *); void iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_rx_data *); int iwm_get_noise(const struct iwm_statistics_rx_non_phy *); int iwm_rx_hwdecrypt(struct iwm_softc *, mbuf_t, uint32_t, struct ieee80211_rxinfo *); int iwm_ccmp_decap(struct iwm_softc *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *); void iwm_rx_frame(struct iwm_softc *, mbuf_t, int, uint32_t, int, int, uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *); void iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_tx_resp *, int, int); void iwm_ampdu_tx_done(struct iwm_softc *, struct iwm_cmd_header *, struct iwm_node *, struct iwm_tx_ring *, uint32_t, uint8_t, uint8_t, uint16_t, int, struct iwm_agg_tx_status *); void iwm_rx_tx_ba_notif(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_rx_data *); void iwm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_rx_data *); void iwm_ampdu_rate_control(struct iwm_softc *, struct ieee80211_node *, struct iwm_tx_ring *, uint16_t, uint16_t, struct ieee80211_tx_info *, int, uint32_t); void iwm_rx_mpdu_mq(struct iwm_softc *sc, mbuf_t m, void *pktdata, size_t maxlen, struct mbuf_list *ml); void iwm_rx_bmiss(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_rx_data *); int iwm_binding_cmd(struct iwm_softc *, struct iwm_node *, uint32_t); int iwm_phy_ctxt_cmd_uhb(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t, uint8_t, uint32_t, uint32_t); void iwm_phy_ctxt_cmd_hdr(struct iwm_softc *, struct iwm_phy_ctxt *, struct iwm_phy_context_cmd *, uint32_t, uint32_t); void iwm_phy_ctxt_cmd_data(struct iwm_softc *, struct iwm_phy_context_cmd *, struct ieee80211_channel *, uint8_t, uint8_t); int iwm_phy_ctxt_cmd(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t, uint8_t, uint32_t, uint32_t); int iwm_send_cmd(struct iwm_softc *, struct iwm_host_cmd *); int iwm_send_cmd_pdu(struct iwm_softc *, uint32_t, uint32_t, uint16_t, const void *); int iwm_send_cmd_status(struct iwm_softc *, struct iwm_host_cmd *, uint32_t *); int iwm_send_cmd_pdu_status(struct iwm_softc *, uint32_t, uint16_t, const void *, uint32_t *); void iwm_free_resp(struct iwm_softc *, struct iwm_host_cmd *); void iwm_cmd_done(struct iwm_softc *, int, int, int); void iwm_update_sched(struct iwm_softc *, int, int, uint8_t, uint16_t); void iwm_reset_sched(struct iwm_softc *, int, int, uint8_t); const struct iwl_rs_rate_info *iwm_tx_fill_cmd(struct iwm_softc *, struct iwm_node *, struct ieee80211_frame *, struct iwm_tx_cmd *); void iwm_txd_done(struct iwm_softc *, struct iwm_tx_data *); void iwm_ampdu_txq_advance(struct iwm_softc *, struct iwm_tx_ring *, int); void iwm_clear_oactive(struct iwm_softc *, struct iwm_tx_ring *); int iwm_tx(struct iwm_softc *, mbuf_t, struct ieee80211_node *, int); int iwm_flush_tx_path(struct iwm_softc *, int); void iwm_led_enable(struct iwm_softc *); void iwm_led_disable(struct iwm_softc *); int iwm_led_is_enabled(struct iwm_softc *); static void iwm_led_blink_timeout(void *); void iwm_led_blink_start(struct iwm_softc *); void iwm_led_blink_stop(struct iwm_softc *); int iwm_beacon_filter_send_cmd(struct iwm_softc *, struct iwm_beacon_filter_cmd *); void iwm_beacon_filter_set_cqm_params(struct iwm_softc *, struct iwm_node *, struct iwm_beacon_filter_cmd *); int iwm_update_beacon_abort(struct iwm_softc *, struct iwm_node *, int); void iwm_power_build_cmd(struct iwm_softc *, struct iwm_node *, struct iwm_mac_power_cmd *); int iwm_power_mac_update_mode(struct iwm_softc *, struct iwm_node *); int iwm_power_update_device(struct iwm_softc *); int iwm_enable_beacon_filter(struct iwm_softc *, struct iwm_node *); int iwm_disable_beacon_filter(struct iwm_softc *); int iwm_add_sta_cmd(struct iwm_softc *, struct iwm_node *, int, unsigned int); int iwm_add_aux_sta(struct iwm_softc *); int iwm_rm_sta_cmd(struct iwm_softc *, struct iwm_node *); int iwm_drain_sta(struct iwm_softc *, struct iwm_node *, bool); uint16_t iwm_scan_rx_chain(struct iwm_softc *); uint32_t iwm_scan_rate_n_flags(struct iwm_softc *, int, int); uint8_t iwm_lmac_scan_fill_channels(struct iwm_softc *, struct iwm_scan_channel_cfg_lmac *, int, int); int iwm_fill_probe_req_v1(struct iwm_softc *, struct iwm_scan_probe_req_v1 *); int iwm_fill_probe_req(struct iwm_softc *, struct iwm_scan_probe_req *); int iwm_lmac_scan(struct iwm_softc *, int); int iwm_config_umac_scan(struct iwm_softc *); int iwm_umac_scan_size(struct iwm_softc *sc); struct iwm_scan_umac_chan_param *iwm_get_scan_req_umac_chan_param(struct iwm_softc *sc, struct iwm_scan_req_umac *req); void *iwm_get_scan_req_umac_data(struct iwm_softc *sc, struct iwm_scan_req_umac *req); int iwm_umac_scan(struct iwm_softc *, int); void iwm_mcc_update(struct iwm_softc *, struct iwm_mcc_chub_notif *); uint8_t iwm_ridx2rate(struct ieee80211_rateset *, int); void iwm_ack_rates(struct iwm_softc *, struct iwm_node *, int *, int *); void iwm_mac_ctxt_cmd_common(struct iwm_softc *, struct iwm_node *, struct iwm_mac_ctx_cmd *, uint32_t); void iwm_mac_ctxt_cmd_fill_sta(struct iwm_softc *, struct iwm_node *, struct iwm_mac_data_sta *, int); int iwm_mac_ctxt_cmd(struct iwm_softc *, struct iwm_node *, uint32_t, int); int iwm_update_quotas(struct iwm_softc *, struct iwm_node *, int); void iwm_add_task(struct iwm_softc *, struct taskq *, struct task *); void iwm_del_task(struct iwm_softc *, struct taskq *, struct task *); int iwm_scan(struct iwm_softc *); static int iwm_bgscan(struct ieee80211com *); int iwm_umac_scan_abort(struct iwm_softc *); int iwm_lmac_scan_abort(struct iwm_softc *); int iwm_scan_abort(struct iwm_softc *); int iwm_phy_ctxt_update(struct iwm_softc *, struct iwm_phy_ctxt *, struct ieee80211_channel *, uint8_t, uint8_t, uint32_t); int iwm_auth(struct iwm_softc *); int iwm_deauth(struct iwm_softc *); int iwm_run(struct iwm_softc *); int iwm_run_stop(struct iwm_softc *); static struct ieee80211_node *iwm_node_alloc(struct ieee80211com *); int iwm_set_key_v1(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); static int iwm_set_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); void iwm_delete_key_v1(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); static void iwm_delete_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); static void iwm_calib_timeout(void *); int iwm_media_change(struct _ifnet *); static void iwm_newstate_task(void *); static int iwm_newstate(struct ieee80211com *, enum ieee80211_state, int); void iwm_endscan(struct iwm_softc *); void iwm_fill_sf_command(struct iwm_softc *, struct iwm_sf_cfg_cmd *, struct ieee80211_node *); int iwm_sf_config(struct iwm_softc *, int); int iwm_send_update_mcc_cmd(struct iwm_softc *, const char *); int iwm_send_soc_conf(struct iwm_softc *); int iwm_send_temp_report_ths_cmd(struct iwm_softc *); void iwm_tt_tx_backoff(struct iwm_softc *, uint32_t); int iwm_fill_paging_mem(struct iwm_softc *, const struct iwm_fw_sects *); int iwm_alloc_fw_paging_mem(struct iwm_softc *, const struct iwm_fw_sects *); void iwm_free_fw_paging(struct iwm_softc *); int iwm_save_fw_paging(struct iwm_softc *, const struct iwm_fw_sects *); int iwm_send_paging_cmd(struct iwm_softc *, const struct iwm_fw_sects *); int iwm_init_hw(struct iwm_softc *); int iwm_init(struct _ifnet *); static void iwm_start(struct _ifnet *); void iwm_stop(struct _ifnet *); static void iwm_watchdog(struct _ifnet *); static int iwm_ioctl(struct _ifnet *, u_long, caddr_t); #ifdef IWM_DEBUG const char *iwm_desc_lookup(uint32_t); void iwm_nic_error(struct iwm_softc *); void iwm_nic_umac_error(struct iwm_softc *); #endif void iwm_rx_mpdu(struct iwm_softc *, mbuf_t, void *, size_t, struct mbuf_list *); void iwm_flip_address(uint8_t *); int iwm_detect_duplicate(struct iwm_softc *, mbuf_t, struct iwm_rx_mpdu_desc *, struct ieee80211_rxinfo *); int iwm_is_sn_less(uint16_t, uint16_t, uint16_t); void iwm_release_frames(struct iwm_softc *, struct ieee80211_node *, struct iwm_rxba_data *, struct iwm_reorder_buffer *, uint16_t, struct mbuf_list *); int iwm_oldsn_workaround(struct iwm_softc *, struct ieee80211_node *, int, struct iwm_reorder_buffer *, uint32_t, uint32_t); int iwm_rx_reorder(struct iwm_softc *, mbuf_t, int, struct iwm_rx_mpdu_desc *, int, int, uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *); int iwm_rx_pkt_valid(struct iwm_rx_packet *); void iwm_rx_pkt(struct iwm_softc *, struct iwm_rx_data *, struct mbuf_list *); void iwm_notif_intr(struct iwm_softc *); static int iwm_intr(OSObject *object, IOInterruptEventSource* sender, int count); static int iwm_intr_msix(OSObject *object, IOInterruptEventSource* sender, int count); static int iwm_match(IOPCIDevice *); int iwm_preinit(struct iwm_softc *); void iwm_attach_hook(struct device *); bool iwm_attach(struct iwm_softc *, struct pci_attach_args *); static void iwm_init_task(void *); int iwm_activate(struct iwm_softc *, int); int iwm_resume(struct iwm_softc *); public: IOInterruptEventSource* fInterrupt; IOPCIDevice *pciNub; struct pci_attach_args pci; struct iwm_softc com; }; #endif /* ItlIwm_hpp */ ================================================ FILE: itlwm/hal_iwm/coex.cpp ================================================ /* * 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. */ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2013-2014, 2018-2020 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH */ #include "ItlIwm.hpp" #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) #define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200) uint16_t ItlIwm:: iwm_coex_agg_time_limit(struct iwm_softc *sc, struct ieee80211_node *ni) { return LINK_QUAL_AGG_TIME_LIMIT_DEF; } uint8_t ItlIwm:: iwm_coex_tx_prio(struct iwm_softc *sc, struct ieee80211_frame *wh, uint8_t ac) { uint8_t type, subtype; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; bool mplut_enabled = isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT); if (!ni || !ni->ni_chan) return 0; if (!IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) return 0; type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (type == IEEE80211_FC0_TYPE_DATA) { if (ieee80211_has_qos(wh)) { switch (ac) { case EDCA_AC_BE: return mplut_enabled ? 1 : 0; case EDCA_AC_VI: return mplut_enabled ? 2 : 3; case EDCA_AC_VO: return 3; default: return 0; } } else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) return 3; else return 0; } else if (type == IEEE80211_FC0_TYPE_MGT) return subtype == IEEE80211_FC0_SUBTYPE_DISASSOC ? 0 : 3; else if (type == IEEE80211_FC0_TYPE_CTL) /* ignore cfend and cfendack frames as we never send those */ return 3; return 0; } bool ItlIwm:: iwm_coex_is_ant_avail(struct iwm_softc *sc, u8 ant) { #if 0 /* there is no other antenna, shared antenna is always available */ if (mvm->cfg->bt_shared_single_ant) return true; #endif if (ant & sc->non_shared_ant) return true; #ifdef notyet_coex return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC; #else return true; #endif } bool ItlIwm:: iwm_coex_is_mimo_allowed(struct iwm_softc *sc, struct ieee80211_node *ni) { #ifdef notyet_coex struct iwm_node *in = (struct iwm_node *)ni; struct iwm_phy_ctxt *phy_ctxt = in->in_phyctxt; enum iwl_bt_coex_lut_type lut_type; if (sc->last_bt_notif.ttc_status & BIT(phy_ctxt->id)) return true; if (le32_to_cpu(sc->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC) return true; /* * In Tight / TxTxDis, BT can't Rx while we Tx, so use both antennas * since BT is already killed. * In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while * we Tx. * When we are in 5GHz, we'll get BT_COEX_INVALID_LUT allowing MIMO. */ lut_type = iwl_get_coex_type(mvm, mvmsta->vif); return lut_type != BT_COEX_LOOSE_LUT; #else return true; #endif } bool ItlIwm:: iwm_coex_is_tpc_allowed(struct iwm_softc *mvm, bool is5G) { if (is5G) return false; #ifdef notyet_coex return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) >= BT_LOW_TRAFFIC; #else return false; #endif } bool ItlIwm:: iwm_coex_is_shared_ant_avail(struct iwm_softc *mvm) { #ifdef notyet_coex return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC; #else return mvm->sc_device_family == IWM_DEVICE_FAMILY_9000 && (iwm_fw_valid_tx_ant(mvm) & IWM_ANT_B); #endif } ================================================ FILE: itlwm/hal_iwm/ctxt.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" void ItlIwm:: iwm_phy_ctxt_cmd_hdr(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt, struct iwm_phy_context_cmd *cmd, uint32_t action, uint32_t apply_time) { memset(cmd, 0, sizeof(struct iwm_phy_context_cmd)); cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ctxt->id, ctxt->color)); cmd->action = htole32(action); cmd->apply_time = htole32(apply_time); } static uint8_t iwm_get_channel_width(struct ieee80211com *ic, struct ieee80211_channel *c) { uint8_t ret = IWM_PHY_VHT_CHANNEL_MODE20; if (ic->ic_bss == NULL || ic->ic_state < IEEE80211_S_ASSOC) { return ret; } switch (ic->ic_bss->ni_chw) { case IEEE80211_CHAN_WIDTH_20_NOHT: case IEEE80211_CHAN_WIDTH_20: return IWM_PHY_VHT_CHANNEL_MODE20; case IEEE80211_CHAN_WIDTH_40: return IWM_PHY_VHT_CHANNEL_MODE40; case IEEE80211_CHAN_WIDTH_80: return IWM_PHY_VHT_CHANNEL_MODE80; case IEEE80211_CHAN_WIDTH_160: return IWM_PHY_VHT_CHANNEL_MODE160; default: XYLog("Invalid channel width=%u\n", ic->ic_bss->ni_chw); return ret; } } static uint8_t iwm_get_ctrl_pos(struct ieee80211com *ic, struct ieee80211_channel *c) { if (ic->ic_bss == NULL || ic->ic_state < IEEE80211_S_ASSOC || iwm_get_channel_width(ic, c) == IWM_PHY_VHT_CHANNEL_MODE20) return IWM_PHY_VHT_CTRL_POS_1_BELOW; signed int offset = ic->ic_bss->ni_chan->ic_freq - ic->ic_bss->ni_chan->ic_center_freq1; switch (offset) { case -70: return IWM_PHY_VHT_CTRL_POS_4_BELOW; case -50: return IWM_PHY_VHT_CTRL_POS_3_BELOW; case -30: return IWM_PHY_VHT_CTRL_POS_2_BELOW; case -10: return IWM_PHY_VHT_CTRL_POS_1_BELOW; case 10: return IWM_PHY_VHT_CTRL_POS_1_ABOVE; case 30: return IWM_PHY_VHT_CTRL_POS_2_ABOVE; case 50: return IWM_PHY_VHT_CTRL_POS_3_ABOVE; case 70: return IWM_PHY_VHT_CTRL_POS_4_ABOVE; default: XYLog("Invalid channel definition freq=%d %d\n", ic->ic_bss->ni_chan->ic_freq, offset); /* fall through */ case 0: /* * The FW is expected to check the control channel position only * when in HT/VHT and the channel width is not 20MHz. Return * this value as the default one. */ return IWM_PHY_VHT_CTRL_POS_1_BELOW; } } void ItlIwm:: iwm_phy_ctxt_cmd_data(struct iwm_softc *sc, struct iwm_phy_context_cmd *cmd, struct ieee80211_channel *chan, uint8_t chains_static, uint8_t chains_dynamic) { struct ieee80211com *ic = &sc->sc_ic; uint8_t active_cnt, idle_cnt; cmd->ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ? IWM_PHY_BAND_24 : IWM_PHY_BAND_5; cmd->ci.channel = ieee80211_chan2ieee(ic, chan); cmd->ci.width = iwm_get_channel_width(ic, chan); cmd->ci.ctrl_pos = iwm_get_ctrl_pos(ic, chan); /* Set rx the chains */ idle_cnt = chains_static; active_cnt = chains_dynamic; cmd->rxchain_info = htole32(iwm_fw_valid_rx_ant(sc) << IWM_PHY_RX_CHAIN_VALID_POS); cmd->rxchain_info |= htole32(idle_cnt << IWM_PHY_RX_CHAIN_CNT_POS); cmd->rxchain_info |= htole32(active_cnt << IWM_PHY_RX_CHAIN_MIMO_CNT_POS); cmd->txchain_info = htole32(iwm_fw_valid_tx_ant(sc)); } int ItlIwm:: iwm_phy_ctxt_cmd_uhb(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt, uint8_t chains_static, uint8_t chains_dynamic, uint32_t action, uint32_t apply_time) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwm_phy_context_cmd_uhb cmd; uint8_t active_cnt, idle_cnt; struct ieee80211_channel *chan = ctxt->channel; memset(&cmd, 0, sizeof(cmd)); cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ctxt->id, ctxt->color)); cmd.action = htole32(action); cmd.apply_time = htole32(apply_time); cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ? IWM_PHY_BAND_24 : IWM_PHY_BAND_5; cmd.ci.channel = htole32(ieee80211_chan2ieee(ic, chan)); cmd.ci.width = iwm_get_channel_width(ic, chan); cmd.ci.ctrl_pos = iwm_get_ctrl_pos(ic, chan); idle_cnt = chains_static; active_cnt = chains_dynamic; cmd.rxchain_info = htole32(iwm_fw_valid_rx_ant(sc) << IWM_PHY_RX_CHAIN_VALID_POS); cmd.rxchain_info |= htole32(idle_cnt << IWM_PHY_RX_CHAIN_CNT_POS); cmd.rxchain_info |= htole32(active_cnt << IWM_PHY_RX_CHAIN_MIMO_CNT_POS); cmd.txchain_info = htole32(iwm_fw_valid_tx_ant(sc)); return iwm_send_cmd_pdu(sc, IWM_PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } int ItlIwm:: iwm_phy_ctxt_cmd(struct iwm_softc *sc, struct iwm_phy_ctxt *ctxt, uint8_t chains_static, uint8_t chains_dynamic, uint32_t action, uint32_t apply_time) { XYLog("%s\n", __FUNCTION__); struct iwm_phy_context_cmd cmd; /* * Intel increased the size of the fw_channel_info struct and neglected * to bump the phy_context_cmd struct, which contains an fw_channel_info * member in the middle. * To keep things simple we use a separate function to handle the larger * variant of the phy context command. */ if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS)) return iwm_phy_ctxt_cmd_uhb(sc, ctxt, chains_static, chains_dynamic, action, apply_time); iwm_phy_ctxt_cmd_hdr(sc, ctxt, &cmd, action, apply_time); iwm_phy_ctxt_cmd_data(sc, &cmd, ctxt->channel, chains_static, chains_dynamic); return iwm_send_cmd_pdu(sc, IWM_PHY_CONTEXT_CMD, 0, sizeof(struct iwm_phy_context_cmd), &cmd); } ================================================ FILE: itlwm/hal_iwm/fw.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" #include "rs.h" #include uint8_t ItlIwm:: iwm_lookup_cmd_ver(struct iwm_softc *sc, uint8_t grp, uint8_t cmd) { const struct iwm_fw_cmd_version *entry; int i; for (i = 0; i < sc->n_cmd_versions; i++) { entry = &sc->cmd_versions[i]; if (entry->group == grp && entry->cmd == cmd) return entry->cmd_ver; } return IWM_FW_CMD_VER_UNKNOWN; } int ItlIwm:: iwm_store_cscheme(struct iwm_softc *sc, uint8_t *data, size_t dlen) { struct iwm_fw_cscheme_list *l = (struct iwm_fw_cscheme_list *)data; if (dlen < sizeof(*l) || dlen < sizeof(l->size) + l->size * sizeof(*l->cs)) return EINVAL; /* we don't actually store anything for now, always use s/w crypto */ return 0; } int ItlIwm:: iwm_firmware_store_section(struct iwm_softc *sc, enum iwm_ucode_type type, uint8_t *data, size_t dlen) { struct iwm_fw_sects *fws; struct iwm_fw_onesect *fwone; if (type >= IWM_UCODE_TYPE_MAX) return EINVAL; if (dlen < sizeof(uint32_t)) return EINVAL; fws = (struct iwm_fw_sects*)&sc->sc_fw.fw_sects[type]; if (fws->fw_count >= IWM_UCODE_SECT_MAX) return EINVAL; fwone = (struct iwm_fw_onesect*)&fws->fw_sect[fws->fw_count]; /* first 32bit are device load offset */ memcpy(&fwone->fws_devoff, data, sizeof(uint32_t)); /* rest is data */ fwone->fws_data = data + sizeof(uint32_t); fwone->fws_len = dlen - sizeof(uint32_t); fws->fw_count++; fws->fw_totlen += fwone->fws_len; return 0; } #define IWM_DEFAULT_SCAN_CHANNELS 40 /* Newer firmware might support more channels. Raise this value if needed. */ #define IWM_MAX_SCAN_CHANNELS 52 /* as of 8265-34 firmware image */ struct iwm_tlv_calib_data { uint32_t ucode_type; struct iwm_tlv_calib_ctrl calib; } __packed; int ItlIwm:: iwm_set_default_calib(struct iwm_softc *sc, const void *data) { const struct iwm_tlv_calib_data *def_calib = (const struct iwm_tlv_calib_data *)data; uint32_t ucode_type = le32toh(def_calib->ucode_type); if (ucode_type >= IWM_UCODE_TYPE_MAX) return EINVAL; sc->sc_default_calib[ucode_type].flow_trigger = def_calib->calib.flow_trigger; sc->sc_default_calib[ucode_type].event_trigger = def_calib->calib.event_trigger; return 0; } void ItlIwm:: iwm_fw_info_free(struct iwm_fw_info *fw) { ::free(fw->fw_rawdata); fw->fw_rawdata = NULL; fw->fw_rawsize = 0; /* don't touch fw->fw_status */ memset(fw->fw_sects, 0, sizeof(fw->fw_sects)); } void iwm_fw_version_str(char *buf, size_t bufsize, uint32_t major, uint32_t minor, uint32_t api) { /* * Starting with major version 35 the Linux driver prints the minor * version in hexadecimal. */ if (major >= 35) snprintf(buf, bufsize, "%u.%08x.%u", major, minor, api); else snprintf(buf, bufsize, "%u.%u.%u", major, minor, api); } int ItlIwm:: iwm_read_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { struct iwm_fw_info *fw = &sc->sc_fw; struct iwm_tlv_ucode_header *uhdr; struct iwm_ucode_tlv tlv; uint32_t usniffer_img; uint32_t paging_mem_size; uint32_t tlv_type; uint8_t *data; int err = 0; size_t len; OSData *fwData = NULL; if (fw->fw_status == IWM_FW_STATUS_DONE && ucode_type != IWM_UCODE_TYPE_INIT) return 0; while (fw->fw_status == IWM_FW_STATUS_INPROGRESS) tsleep_nsec(&sc->sc_fw, 0, "iwmfwp", INFSLP); fw->fw_status = IWM_FW_STATUS_INPROGRESS; if (fw->fw_rawdata != NULL) iwm_fw_info_free(fw); //TODO // err = loadfirmware(sc->sc_fwname, // (u_char **)&fw->fw_rawdata, &fw->fw_rawsize); // IOLockLock(fwLoadLock); // ResourceCallbackContext context = // { // .context = this, // .resource = NULL // }; // // //here leaks // IOReturn ret = OSKextRequestResource(OSKextGetCurrentIdentifier(), sc->sc_fwname, onLoadFW, &context, NULL); // IOLockSleep(fwLoadLock, this, 0); // IOLockUnlock(fwLoadLock); // if (context.resource == NULL) { // XYLog("%s resource load fail.\n", sc->sc_fwname); // goto out; // } // fw->fw_rawdata = malloc(context.resource->getLength(), 1, 1); // memcpy(fw->fw_rawdata, context.resource->getBytesNoCopy(), context.resource->getLength()); // fw->fw_rawsize = context.resource->getLength(); fwData = getFWDescByName(sc->sc_fwname); if (fwData == NULL) { XYLog("%s resource load fail.\n", sc->sc_fwname); err = EINVAL; goto out; } fw->fw_rawsize = fwData->getLength() * 4; fw->fw_rawdata = malloc(fw->fw_rawsize, 1, 1); uncompressFirmware((u_char *)fw->fw_rawdata, (uint *)&fw->fw_rawsize, (u_char *)fwData->getBytesNoCopy(), fwData->getLength()); XYLog("load firmware %s done\n", sc->sc_fwname); sc->sc_capaflags = 0; sc->sc_capa_n_scan_channels = IWM_DEFAULT_SCAN_CHANNELS; memset(sc->sc_enabled_capa, 0, sizeof(sc->sc_enabled_capa)); sc->n_cmd_versions = 0; memset(sc->sc_ucode_api, 0, sizeof(sc->sc_ucode_api)); memcpy(sc->sc_fw_mcc, "ZZ", sizeof(sc->sc_fw_mcc)); sc->sc_fw_mcc_int = 0x3030; uhdr = (struct iwm_tlv_ucode_header *)fw->fw_rawdata; if (*(uint32_t *)fw->fw_rawdata != 0 || le32toh(uhdr->magic) != IWM_TLV_UCODE_MAGIC) { XYLog("%s: invalid firmware %s\n", DEVNAME(sc), sc->sc_fwname); err = EINVAL; goto out; } iwm_fw_version_str(sc->sc_fwver, sizeof(sc->sc_fwver), IWM_UCODE_MAJOR(le32toh(uhdr->ver)), IWM_UCODE_MINOR(le32toh(uhdr->ver)), IWM_UCODE_API(le32toh(uhdr->ver))); data = uhdr->data; len = fw->fw_rawsize - sizeof(*uhdr); while (len >= sizeof(tlv)) { size_t tlv_len; void *tlv_data; memcpy(&tlv, data, sizeof(tlv)); tlv_len = le32toh(tlv.length); tlv_type = le32toh(tlv.type); len -= sizeof(tlv); data += sizeof(tlv); tlv_data = data; if (len < tlv_len) { XYLog("%s: firmware too short: %zu bytes\n", DEVNAME(sc), len); err = EINVAL; goto parse_out; } switch (tlv_type) { case IWM_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len < sizeof(uint32_t)) { err = EINVAL; goto parse_out; } sc->sc_capa_max_probe_len = le32toh(*(uint32_t *)tlv_data); if (sc->sc_capa_max_probe_len > IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE) { err = EINVAL; goto parse_out; } break; case IWM_UCODE_TLV_PAN: if (tlv_len) { err = EINVAL; goto parse_out; } sc->sc_capaflags |= IWM_UCODE_TLV_FLAGS_PAN; break; case IWM_UCODE_TLV_FLAGS: if (tlv_len < sizeof(uint32_t)) { err = EINVAL; goto parse_out; } /* * Apparently there can be many flags, but Linux driver * parses only the first one, and so do we. * * XXX: why does this override IWM_UCODE_TLV_PAN? * Intentional or a bug? Observations from * current firmware file: * 1) TLV_PAN is parsed first * 2) TLV_FLAGS contains TLV_FLAGS_PAN * ==> this resets TLV_PAN to itself... hnnnk */ sc->sc_capaflags = le32toh(*(uint32_t *)tlv_data); break; case IWM_UCODE_TLV_CSCHEME: err = iwm_store_cscheme(sc, (uint8_t*)tlv_data, tlv_len); if (err) goto parse_out; break; case IWM_UCODE_TLV_NUM_OF_CPU: { uint32_t num_cpu; if (tlv_len != sizeof(uint32_t)) { err = EINVAL; goto parse_out; } num_cpu = le32toh(*(uint32_t *)tlv_data); if (num_cpu < 1 || num_cpu > 2) { err = EINVAL; goto parse_out; } break; } case IWM_UCODE_TLV_SEC_RT: err = iwm_firmware_store_section(sc, IWM_UCODE_TYPE_REGULAR, (uint8_t*)tlv_data, tlv_len); if (err) goto parse_out; break; case IWM_UCODE_TLV_SEC_INIT: err = iwm_firmware_store_section(sc, IWM_UCODE_TYPE_INIT, (uint8_t*)tlv_data, tlv_len); if (err) goto parse_out; break; case IWM_UCODE_TLV_SEC_WOWLAN: err = iwm_firmware_store_section(sc, IWM_UCODE_TYPE_WOW, (uint8_t*)tlv_data, tlv_len); if (err) goto parse_out; break; case IWM_UCODE_TLV_DEF_CALIB: if (tlv_len != sizeof(struct iwm_tlv_calib_data)) { err = EINVAL; goto parse_out; } err = iwm_set_default_calib(sc, tlv_data); if (err) goto parse_out; break; case IWM_UCODE_TLV_PHY_SKU: if (tlv_len != sizeof(uint32_t)) { err = EINVAL; goto parse_out; } sc->sc_fw_phy_config = le32toh(*(uint32_t *)tlv_data); break; case IWM_UCODE_TLV_API_CHANGES_SET: { struct iwm_ucode_api *api; int idx, i; if (tlv_len != sizeof(*api)) { err = EINVAL; goto parse_out; } api = (struct iwm_ucode_api *)tlv_data; idx = le32toh(api->api_index); if (idx >= howmany(IWM_NUM_UCODE_TLV_API, 32)) { err = EINVAL; goto parse_out; } for (i = 0; i < 32; i++) { if ((le32toh(api->api_flags) & (1 << i)) == 0) continue; setbit(sc->sc_ucode_api, i + (32 * idx)); } break; } case IWM_UCODE_TLV_ENABLED_CAPABILITIES: { struct iwm_ucode_capa *capa; int idx, i; if (tlv_len != sizeof(*capa)) { err = EINVAL; goto parse_out; } capa = (struct iwm_ucode_capa *)tlv_data; idx = le32toh(capa->api_index); if (idx >= howmany(IWM_NUM_UCODE_TLV_CAPA, 32)) { goto parse_out; } for (i = 0; i < 32; i++) { if ((le32toh(capa->api_capa) & (1 << i)) == 0) continue; setbit(sc->sc_enabled_capa, i + (32 * idx)); } break; } case IWM_UCODE_TLV_CMD_VERSIONS: if (tlv_len % sizeof(struct iwm_fw_cmd_version)) { tlv_len /= sizeof(struct iwm_fw_cmd_version); tlv_len *= sizeof(struct iwm_fw_cmd_version); } if (sc->n_cmd_versions != 0) { err = EINVAL; goto parse_out; } if (tlv_len > sizeof(sc->cmd_versions)) { err = EINVAL; goto parse_out; } memcpy(&sc->cmd_versions[0], tlv_data, tlv_len); sc->n_cmd_versions = tlv_len / sizeof(struct iwm_fw_cmd_version); break; case IWM_UCODE_TLV_SDIO_ADMA_ADDR: case IWM_UCODE_TLV_FW_GSCAN_CAPA: /* ignore, not used by current driver */ break; case IWM_UCODE_TLV_SEC_RT_USNIFFER: err = iwm_firmware_store_section(sc, IWM_UCODE_TYPE_REGULAR_USNIFFER, (uint8_t*)tlv_data, tlv_len); if (err) goto parse_out; break; case IWM_UCODE_TLV_PAGING: if (tlv_len != sizeof(uint32_t)) { err = EINVAL; goto parse_out; } paging_mem_size = le32toh(*(const uint32_t *)tlv_data); DPRINTF(("%s: Paging: paging enabled (size = %u bytes)\n", DEVNAME(sc), paging_mem_size)); if (paging_mem_size > IWM_MAX_PAGING_IMAGE_SIZE) { XYLog("%s: Driver only supports up to %u" " bytes for paging image (%u requested)\n", DEVNAME(sc), IWM_MAX_PAGING_IMAGE_SIZE, paging_mem_size); err = EINVAL; goto out; } if (paging_mem_size & (IWM_FW_PAGING_SIZE - 1)) { XYLog("%s: Paging: image isn't multiple of %u\n", DEVNAME(sc), IWM_FW_PAGING_SIZE); err = EINVAL; goto out; } fw->fw_sects[IWM_UCODE_TYPE_REGULAR].paging_mem_size = paging_mem_size; usniffer_img = IWM_UCODE_TYPE_REGULAR_USNIFFER; fw->fw_sects[usniffer_img].paging_mem_size = paging_mem_size; break; case IWM_UCODE_TLV_N_SCAN_CHANNELS: if (tlv_len != sizeof(uint32_t)) { err = EINVAL; goto parse_out; } sc->sc_capa_n_scan_channels = le32toh(*(uint32_t *)tlv_data); if (sc->sc_capa_n_scan_channels > IWM_MAX_SCAN_CHANNELS) { err = ERANGE; goto parse_out; } break; case IWM_UCODE_TLV_FW_VERSION: if (tlv_len != sizeof(uint32_t) * 3) { err = EINVAL; goto parse_out; } iwm_fw_version_str(sc->sc_fwver, sizeof(sc->sc_fwver), le32toh(((uint32_t *)tlv_data)[0]), le32toh(((uint32_t *)tlv_data)[1]), le32toh(((uint32_t *)tlv_data)[2])); break; case IWM_UCODE_TLV_FW_DBG_DEST: case IWM_UCODE_TLV_FW_DBG_CONF: case IWM_UCODE_TLV_UMAC_DEBUG_ADDRS: case IWM_UCODE_TLV_LMAC_DEBUG_ADDRS: case IWM_UCODE_TLV_TYPE_DEBUG_INFO: case IWM_UCODE_TLV_TYPE_BUFFER_ALLOCATION: case IWM_UCODE_TLV_TYPE_HCMD: case IWM_UCODE_TLV_TYPE_REGIONS: case IWM_UCODE_TLV_TYPE_TRIGGERS: break; case IWM_UCODE_TLV_HW_TYPE: break; case IWM_UCODE_TLV_FW_MEM_SEG: break; /* undocumented TLVs found in iwm-9000-43 image */ case 0x1000003: case 0x1000004: break; case 52://IWL_UCODE_TLV_IML case 53://IWL_UCODE_TLV_FW_FMAC_API_VERSION case 57://IWL_UCODE_TLV_FW_RECOVERY_INFO case 59://IWL_UCODE_TLV_FW_FMAC_RECOVERY_INFO break; case 60: {//IWL_UCODE_TLV_FW_FSEQ_VERSION typedef struct { u8 version[32]; u8 sha1[20]; } SEQVER, *PSEQVER; PSEQVER fseq_ver = (PSEQVER)tlv_data; if (tlv_len != sizeof(SEQVER)) { err = EINVAL; goto parse_out; } XYLog("TLV_FW_FSEQ_VERSION: %s\n", fseq_ver->version); } break; /* TLVs 0x1000-0x2000 are for internal driver usage */ case 0x1000://IWL_UCODE_TLV_FW_DBG_DUMP_LST break; default: err = EINVAL; goto parse_out; } /* * Check for size_t overflow and ignore missing padding at * end of firmware file. */ if (roundup(tlv_len, 4) > len) break; len -= roundup(tlv_len, 4); data += roundup(tlv_len, 4); } _KASSERT(err == 0); parse_out: if (err) { XYLog("%s: firmware parse error %d, " "section type %d\n", DEVNAME(sc), err, tlv_type); } out: if (err) { fw->fw_status = IWM_FW_STATUS_NONE; if (fw->fw_rawdata != NULL) iwm_fw_info_free(fw); } else fw->fw_status = IWM_FW_STATUS_DONE; wakeupOn(&sc->sc_fw); OSSafeReleaseNULL(fwData); return err; } int ItlIwm:: iwm_post_alive(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); int nwords; int err, chnl; uint32_t base; if (!iwm_nic_lock(sc)) return EBUSY; base = iwm_read_prph(sc, IWM_SCD_SRAM_BASE_ADDR); iwm_ict_reset(sc); iwm_nic_unlock(sc); /* Clear TX scheduler state in SRAM. */ nwords = (IWM_SCD_TRANS_TBL_MEM_UPPER_BOUND - IWM_SCD_CONTEXT_MEM_LOWER_BOUND) / sizeof(uint32_t); err = iwm_write_mem(sc, sc->sched_base + IWM_SCD_CONTEXT_MEM_LOWER_BOUND, NULL, nwords); if (err) return err; if (!iwm_nic_lock(sc)) return EBUSY; /* Set physical address of TX scheduler rings (1KB aligned). */ iwm_write_prph(sc, IWM_SCD_DRAM_BASE_ADDR, sc->sched_dma.paddr >> 10); iwm_write_prph(sc, IWM_SCD_CHAINEXT_EN, 0); /* enable command channel */ err = iwm_enable_ac_txq(sc, sc->cmdqid, IWM_TX_FIFO_CMD); if (err) { iwm_nic_unlock(sc); return err; } /* Activate TX scheduler. */ iwm_write_prph(sc, IWM_SCD_TXFACT, 0xff); /* Enable DMA channels. */ for (chnl = 0; chnl < IWM_FH_TCSR_CHNL_NUM; chnl++) { IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl), IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); } IWM_SETBITS(sc, IWM_FH_TX_CHICKEN_BITS_REG, IWM_FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); iwm_nic_unlock(sc); /* Enable L1-Active */ if (sc->sc_device_family < IWM_DEVICE_FAMILY_8000) iwm_clear_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG, IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS); return err; } uint8_t ItlIwm:: iwm_fw_valid_tx_ant(struct iwm_softc *sc) { uint8_t tx_ant; tx_ant = ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_TX_CHAIN) >> IWM_FW_PHY_CFG_TX_CHAIN_POS); if (sc->sc_nvm.valid_tx_ant) tx_ant &= sc->sc_nvm.valid_tx_ant; return tx_ant; } uint8_t ItlIwm:: iwm_fw_valid_rx_ant(struct iwm_softc *sc) { uint8_t rx_ant; rx_ant = ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RX_CHAIN) >> IWM_FW_PHY_CFG_RX_CHAIN_POS); if (sc->sc_nvm.valid_rx_ant) rx_ant &= sc->sc_nvm.valid_rx_ant; return rx_ant; } uint32_t ItlIwm:: iwm_get_tx_ant(struct iwm_softc *sc, struct ieee80211_node *ni, int type, struct ieee80211_frame *wh) { if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) && !ItlIwm::iwm_coex_is_shared_ant_avail(sc)) return sc->non_shared_ant << RATE_MCS_ANT_POS; if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && type == IEEE80211_FC0_TYPE_DATA) return ((1 << sc->sc_tx_ant) << RATE_MCS_ANT_POS); return ((1 << sc->sc_mgmt_last_antenna_idx) << RATE_MCS_ANT_POS); } void ItlIwm:: iwm_toggle_tx_ant(struct iwm_softc *sc, uint8_t *ant) { int i; uint8_t ind = *ant; uint8_t valid = iwm_fw_valid_tx_ant(sc); for (i = 0; i < IWM_RATE_MCS_ANT_NUM; i++) { ind = (ind + 1) % IWM_RATE_MCS_ANT_NUM; if (valid & (1 << ind)) break; } *ant = ind; } int ItlIwm:: iwm_firmware_load_sect(struct iwm_softc *sc, uint32_t dst_addr, const uint8_t *section, uint32_t byte_cnt) { int err = EINVAL; uint32_t chunk_sz, offset; chunk_sz = MIN(IWM_FH_MEM_TB_MAX_LENGTH, byte_cnt); for (offset = 0; offset < byte_cnt; offset += chunk_sz) { uint32_t addr, len; const uint8_t *data; addr = dst_addr + offset; len = MIN(chunk_sz, byte_cnt - offset); data = section + offset; err = iwm_firmware_load_chunk(sc, addr, data, len); if (err) break; } return err; } int ItlIwm:: iwm_firmware_load_chunk(struct iwm_softc *sc, uint32_t dst_addr, const uint8_t *chunk, uint32_t byte_cnt) { struct iwm_dma_info *dma = &sc->fw_dma; int err; /* Copy firmware chunk into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, chunk, byte_cnt); // bus_dmamap_sync(sc->sc_dmat, // dma->map, 0, byte_cnt, BUS_DMASYNC_PREWRITE); if (dst_addr >= IWM_FW_MEM_EXTENDED_START && dst_addr <= IWM_FW_MEM_EXTENDED_END) iwm_set_bits_prph(sc, IWM_LMPM_CHICK, IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE); sc->sc_fw_chunk_done = 0; if (!iwm_nic_lock(sc)) return EBUSY; IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(IWM_FH_SRVC_CHNL), IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); IWM_WRITE(sc, IWM_FH_SRVC_CHNL_SRAM_ADDR_REG(IWM_FH_SRVC_CHNL), dst_addr); IWM_WRITE(sc, IWM_FH_TFDIB_CTRL0_REG(IWM_FH_SRVC_CHNL), dma->paddr & IWM_FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); IWM_WRITE(sc, IWM_FH_TFDIB_CTRL1_REG(IWM_FH_SRVC_CHNL), (iwm_get_dma_hi_addr(dma->paddr) << IWM_FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_BUF_STS_REG(IWM_FH_SRVC_CHNL), 1 << IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | 1 << IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(IWM_FH_SRVC_CHNL), IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); iwm_nic_unlock(sc); /* Wait for this segment to load. */ err = 0; while (!sc->sc_fw_chunk_done) { err = tsleep_nsec(&sc->sc_fw, 0, "iwmfw", SEC_TO_NSEC(1)); if (err) break; } if (!sc->sc_fw_chunk_done) XYLog("%s: fw chunk addr 0x%x len %d failed to load\n", DEVNAME(sc), dst_addr, byte_cnt); if (dst_addr >= IWM_FW_MEM_EXTENDED_START && dst_addr <= IWM_FW_MEM_EXTENDED_END) { iwm_clear_bits_prph(sc, IWM_LMPM_CHICK, IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE); } return err; } int ItlIwm:: iwm_load_firmware_7000(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { struct iwm_fw_sects *fws; int err, i; void *data; uint32_t dlen; uint32_t offset; fws = &sc->sc_fw.fw_sects[ucode_type]; for (i = 0; i < fws->fw_count; i++) { data = fws->fw_sect[i].fws_data; dlen = fws->fw_sect[i].fws_len; offset = fws->fw_sect[i].fws_devoff; if (dlen > sc->sc_fwdmasegsz) { err = EFBIG; } else err = iwm_firmware_load_sect(sc, offset, (const uint8_t*)data, dlen); if (err) { XYLog("%s: could not load firmware chunk %u of %u\n", DEVNAME(sc), i, fws->fw_count); return err; } } iwm_enable_interrupts(sc); IWM_WRITE(sc, IWM_CSR_RESET, 0); return 0; } int ItlIwm:: iwm_load_cpu_sections_8000(struct iwm_softc *sc, struct iwm_fw_sects *fws, int cpu, int *first_ucode_section) { int shift_param; int i, err = 0, sec_num = 0x1; uint32_t val, last_read_idx = 0; void *data; uint32_t dlen; uint32_t offset; if (cpu == 1) { shift_param = 0; *first_ucode_section = 0; } else { shift_param = 16; (*first_ucode_section)++; } for (i = *first_ucode_section; i < IWM_UCODE_SECT_MAX; i++) { last_read_idx = i; data = fws->fw_sect[i].fws_data; dlen = fws->fw_sect[i].fws_len; offset = fws->fw_sect[i].fws_devoff; /* * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between * CPU1 to CPU2. * PAGING_SEPARATOR_SECTION delimiter - separate between * CPU2 non paged to CPU2 paging sec. */ if (!data || offset == IWM_CPU1_CPU2_SEPARATOR_SECTION || offset == IWM_PAGING_SEPARATOR_SECTION) break; if (dlen > sc->sc_fwdmasegsz) { err = EFBIG; } else err = iwm_firmware_load_sect(sc, offset, (const uint8_t*)data, dlen); if (err) { XYLog("%s: could not load firmware chunk %d " "(error %d)\n", DEVNAME(sc), i, err); return err; } /* Notify the ucode of the loaded section number and status */ if (iwm_nic_lock(sc)) { val = IWM_READ(sc, IWM_FH_UCODE_LOAD_STATUS); val = val | (sec_num << shift_param); IWM_WRITE(sc, IWM_FH_UCODE_LOAD_STATUS, val); sec_num = (sec_num << 1) | 0x1; iwm_nic_unlock(sc); } else { err = EBUSY; XYLog("%s: could not load firmware chunk %d " "(error %d)\n", DEVNAME(sc), i, err); return err; } } *first_ucode_section = last_read_idx; if (iwm_nic_lock(sc)) { if (cpu == 1) IWM_WRITE(sc, IWM_FH_UCODE_LOAD_STATUS, 0xFFFF); else IWM_WRITE(sc, IWM_FH_UCODE_LOAD_STATUS, 0xFFFFFFFF); iwm_nic_unlock(sc); } else { err = EBUSY; XYLog("%s: could not finalize firmware loading (error %d)\n", DEVNAME(sc), err); return err; } return 0; } int ItlIwm:: iwm_load_firmware_8000(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { struct iwm_fw_sects *fws; int err = 0; int first_ucode_section; fws = &sc->sc_fw.fw_sects[ucode_type]; /* configure the ucode to be ready to get the secured image */ /* release CPU reset */ if (iwm_nic_lock(sc)) { iwm_write_prph(sc, IWM_RELEASE_CPU_RESET, IWM_RELEASE_CPU_RESET_BIT); iwm_nic_unlock(sc); } /* load to FW the binary Secured sections of CPU1 */ err = iwm_load_cpu_sections_8000(sc, fws, 1, &first_ucode_section); if (err) return err; /* load to FW the binary sections of CPU2 */ err = iwm_load_cpu_sections_8000(sc, fws, 2, &first_ucode_section); if (err) return err; iwm_enable_interrupts(sc); return 0; } int ItlIwm:: iwm_load_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { XYLog("%s\n", __FUNCTION__); int err/*, w*/; sc->sc_uc.uc_intr = 0; if (sc->sc_device_family >= IWM_DEVICE_FAMILY_8000) err = iwm_load_firmware_8000(sc, ucode_type); else err = iwm_load_firmware_7000(sc, ucode_type); if (err) return err; /* wait for the firmware to load */ // for (w = 0; !sc->sc_uc.uc_intr && w < 10; w++) { // err = tsleep_nsec(&sc->sc_uc, 0, "iwmuc", MSEC_TO_NSEC(100)); // } err = tsleep_nsec(&sc->sc_uc, 0, "iwmuc", SEC_TO_NSEC(1)); if (err || !sc->sc_uc.uc_ok) XYLog("%s: could not load firmware\n", DEVNAME(sc)); return err; } int ItlIwm:: iwm_start_fw(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { XYLog("%s ucode_type=%d\n", __FUNCTION__, ucode_type); int err; IWM_WRITE(sc, IWM_CSR_INT, ~0); err = iwm_nic_init(sc); if (err) { XYLog("%s: unable to init nic\n", DEVNAME(sc)); return err; } /* make sure rfkill handshake bits are cleared */ IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL); IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); /* clear (again), then enable firwmare load interrupt */ IWM_WRITE(sc, IWM_CSR_INT, ~0); iwm_enable_fwload_interrupt(sc); /* really make sure rfkill handshake bits are cleared */ /* maybe we should write a few times more? just to make sure */ IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL); IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL); return iwm_load_firmware(sc, ucode_type); } int ItlIwm:: iwm_send_tx_ant_cfg(struct iwm_softc *sc, uint8_t valid_tx_ant) { XYLog("%s\n", __FUNCTION__); struct iwm_tx_ant_cfg_cmd tx_ant_cmd = { .valid = htole32(valid_tx_ant), }; return iwm_send_cmd_pdu(sc, IWM_TX_ANT_CONFIGURATION_CMD, 0, sizeof(tx_ant_cmd), &tx_ant_cmd); } int ItlIwm:: iwm_load_ucode_wait_alive(struct iwm_softc *sc, enum iwm_ucode_type ucode_type) { XYLog("%s ucode_type=%d\n", __FUNCTION__, ucode_type); enum iwm_ucode_type old_type = sc->sc_uc_current; struct iwm_fw_sects *fw = &sc->sc_fw.fw_sects[ucode_type]; int err; err = iwm_read_firmware(sc, ucode_type); if (err) return err; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) sc->cmdqid = IWM_DQA_CMD_QUEUE; else sc->cmdqid = IWM_CMD_QUEUE; sc->sc_uc_current = ucode_type; err = iwm_start_fw(sc, ucode_type); if (err) { sc->sc_uc_current = old_type; return err; } err = iwm_post_alive(sc); if (err) return err; /* * configure and operate fw paging mechanism. * driver configures the paging flow only once, CPU2 paging image * included in the IWM_UCODE_INIT image. */ if (fw->paging_mem_size) { err = iwm_save_fw_paging(sc, fw); if (err) { XYLog("%s: failed to save the FW paging image\n", DEVNAME(sc)); return err; } err = iwm_send_paging_cmd(sc, fw); if (err) { XYLog("%s: failed to send the paging cmd\n", DEVNAME(sc)); iwm_free_fw_paging(sc); return err; } } return 0; } int ItlIwm:: iwm_run_init_mvm_ucode(struct iwm_softc *sc, int justnvm) { XYLog("%s justnvm=%d\n", __FUNCTION__, justnvm); const int wait_flags = (IWM_INIT_COMPLETE | IWM_CALIB_COMPLETE); int err; if ((sc->sc_flags & IWM_FLAG_RFKILL) && !justnvm) { XYLog("%s: radio is disabled by hardware switch\n", DEVNAME(sc)); return EPERM; } sc->sc_init_complete = 0; err = iwm_load_ucode_wait_alive(sc, IWM_UCODE_TYPE_INIT); if (err) { XYLog("%s: failed to load init firmware\n", DEVNAME(sc)); return err; } if (sc->sc_device_family < IWM_DEVICE_FAMILY_8000) { err = iwm_send_bt_init_conf(sc); if (err) { XYLog("%s: could not init bt coex (error %d)\n", DEVNAME(sc), err); return err; } } if (justnvm) { err = iwm_nvm_init(sc); if (err) { XYLog("%s: failed to read nvm\n", DEVNAME(sc)); return err; } if (IEEE80211_ADDR_EQ(etheranyaddr, sc->sc_ic.ic_myaddr)) IEEE80211_ADDR_COPY(sc->sc_ic.ic_myaddr, sc->sc_nvm.hw_addr); return 0; } err = iwm_sf_config(sc, IWM_SF_INIT_OFF); if (err) return err; /* Send TX valid antennas before triggering calibrations */ err = iwm_send_tx_ant_cfg(sc, iwm_fw_valid_tx_ant(sc)); if (err) return err; /* * Send phy configurations command to init uCode * to start the 16.0 uCode init image internal calibrations. */ err = iwm_send_phy_cfg_cmd(sc); if (err) return err; /* * Nothing to do but wait for the init complete and phy DB * notifications from the firmware. */ // while ((sc->sc_init_complete & wait_flags) != wait_flags) { // err = tsleep_nsec(&sc->sc_init_complete, 0, "iwminit", // SEC_TO_NSEC(2)); // if (err) // break; // } err = tsleep_nsec(&sc->sc_init_complete, 0, "iwminit", SEC_TO_NSEC(2)); return err; } int ItlIwm:: iwm_config_ltr(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwm_ltr_config_cmd cmd = { .flags = htole32(IWM_LTR_CFG_FLAG_FEATURE_ENABLE), }; if (!sc->sc_ltr_enabled) return 0; return iwm_send_cmd_pdu(sc, IWM_LTR_CONFIG, 0, sizeof(cmd), &cmd); } ================================================ FILE: itlwm/hal_iwm/hw.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" void ItlIwm:: iwm_enable_rfkill_int(struct iwm_softc *sc) { if (!sc->sc_msix) { sc->sc_intmask = IWM_CSR_INT_BIT_RF_KILL; IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); } else { IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, sc->sc_fh_init_mask); IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, ~IWM_MSIX_HW_INT_CAUSES_REG_RF_KILL); sc->sc_hw_mask = IWM_MSIX_HW_INT_CAUSES_REG_RF_KILL; } if (sc->sc_device_family >= IWM_DEVICE_FAMILY_9000) IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); } int ItlIwm:: iwm_check_rfkill(struct iwm_softc *sc) { uint32_t v; int s; int rv; s = splnet(); /* * "documentation" is not really helpful here: * 27: HW_RF_KILL_SW * Indicates state of (platform's) hardware RF-Kill switch * * But apparently when it's off, it's on ... */ v = IWM_READ(sc, IWM_CSR_GP_CNTRL); rv = (v & IWM_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) == 0; if (rv) { sc->sc_flags |= IWM_FLAG_RFKILL; } else { sc->sc_flags &= ~IWM_FLAG_RFKILL; } XYLog("%s RF_KILL hw: %d\n", __FUNCTION__, rv); splx(s); return rv; } void ItlIwm:: iwm_enable_interrupts(struct iwm_softc *sc) { if (!sc->sc_msix) { sc->sc_intmask = IWM_CSR_INI_SET_MASK; IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); } else { /* * fh/hw_mask keeps all the unmasked causes. * Unlike msi, in msix cause is enabled when it is unset. */ sc->sc_hw_mask = sc->sc_hw_init_mask; sc->sc_fh_mask = sc->sc_fh_init_mask; IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, ~sc->sc_fh_mask); IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, ~sc->sc_hw_mask); } } void ItlIwm:: iwm_enable_fwload_interrupt(struct iwm_softc *sc) { if (!sc->sc_msix) { sc->sc_intmask = IWM_CSR_INT_BIT_FH_TX; IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); } else { IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, sc->sc_hw_init_mask); IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, ~IWM_MSIX_FH_INT_CAUSES_D2S_CH0_NUM); sc->sc_fh_mask = IWM_MSIX_FH_INT_CAUSES_D2S_CH0_NUM; } } void ItlIwm:: iwm_disable_interrupts(struct iwm_softc *sc) { int s = splnet(); if (!sc->sc_msix) { IWM_WRITE(sc, IWM_CSR_INT_MASK, 0); /* acknowledge all interrupts */ IWM_WRITE(sc, IWM_CSR_INT, ~0); IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, ~0); } else { IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, sc->sc_fh_init_mask); IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, sc->sc_hw_init_mask); } splx(s); } void ItlIwm:: iwm_ict_reset(struct iwm_softc *sc) { iwm_disable_interrupts(sc); memset(sc->ict_dma.vaddr, 0, IWM_ICT_SIZE); sc->ict_cur = 0; /* Set physical address of ICT (4KB aligned). */ IWM_WRITE(sc, IWM_CSR_DRAM_INT_TBL_REG, IWM_CSR_DRAM_INT_TBL_ENABLE | IWM_CSR_DRAM_INIT_TBL_WRAP_CHECK | IWM_CSR_DRAM_INIT_TBL_WRITE_POINTER | sc->ict_dma.paddr >> IWM_ICT_PADDR_SHIFT); /* Switch to ICT interrupt mode in driver. */ sc->sc_flags |= IWM_FLAG_USE_ICT; IWM_WRITE(sc, IWM_CSR_INT, ~0); iwm_enable_interrupts(sc); } #define IWM_HW_READY_TIMEOUT 50 int ItlIwm:: iwm_set_hw_ready(struct iwm_softc *sc) { int ready; IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); ready = iwm_poll_bit(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, IWM_HW_READY_TIMEOUT); if (ready) IWM_SETBITS(sc, IWM_CSR_MBOX_SET_REG, IWM_CSR_MBOX_SET_REG_OS_ALIVE); return ready; } #undef IWM_HW_READY_TIMEOUT int ItlIwm:: iwm_prepare_card_hw(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); int t = 0; int ntries; if (iwm_set_hw_ready(sc)) return 0; IWM_SETBITS(sc, IWM_CSR_DBG_LINK_PWR_MGMT_REG, IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED); DELAY(1000); for (ntries = 0; ntries < 10; ntries++) { /* If HW is not ready, prepare the conditions to check again */ IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_PREPARE); do { if (iwm_set_hw_ready(sc)) return 0; DELAY(200); t += 200; } while (t < 150000); DELAY(25000); } return ETIMEDOUT; } void ItlIwm:: iwm_apm_config(struct iwm_softc *sc) { pcireg_t lctl, cap; /* * L0S states have been found to be unstable with our devices * and in newer hardware they are not officially supported at * all, so we must always set the L0S_DISABLED bit. */ lctl = pci_conf_read(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_LCSR); IWM_SETBITS(sc, IWM_CSR_GIO_REG, IWM_CSR_GIO_REG_VAL_L0S_DISABLED); /* * Disable L0s and L1s in PCIE register because we don't support ASPM now. */ lctl &= ~(PCI_PCIE_LCSR_ASPM_L0S | PCI_PCIE_LCSR_ASPM_L1); pci_conf_write(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_LCSR, lctl); lctl = pci_conf_read(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_LCSR); cap = pci_conf_read(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_DCSR2); sc->sc_ltr_enabled = (cap & PCI_PCIE_DCSR2_LTREN) ? 1 : 0; XYLog("%s: L1 %sabled - LTR %sabled\n", DEVNAME(sc), (lctl & PCI_PCIE_LCSR_ASPM_L1) ? "En" : "Dis", sc->sc_ltr_enabled ? "En" : "Dis"); } /* * Start up NIC's basic functionality after it has been reset * e.g. after platform boot or shutdown. * NOTE: This does not load uCode nor start the embedded processor */ int ItlIwm:: iwm_apm_init(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); int err = 0; /* Disable L0S exit timer (platform NMI workaround) */ if (sc->sc_device_family < IWM_DEVICE_FAMILY_8000) IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS, IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); /* * Disable L0s without affecting L1; * don't wait for ICH L0s (ICH bug W/A) */ IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS, IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); /* Set FH wait threshold to maximum (HW error during stress W/A) */ IWM_SETBITS(sc, IWM_CSR_DBG_HPET_MEM_REG, IWM_CSR_DBG_HPET_MEM_REG_VAL); /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s */ IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); iwm_apm_config(sc); #if 0 /* not for 7k/8k */ /* Configure analog phase-lock-loop before activating to D0A */ if (trans->cfg->base_params->pll_cfg_val) IWM_SETBITS(trans, IWM_CSR_ANA_PLL_CFG, trans->cfg->base_params->pll_cfg_val); #endif /* * Set "initialization complete" bit to move adapter from * D0U* --> D0A* (powered-up active) state. */ IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* * Wait for clock stabilization; once stabilized, access to * device-internal resources is supported, e.g. iwm_write_prph() * and accesses to uCode SRAM. */ if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000)) { XYLog("%s: timeout waiting for clock stabilization\n", DEVNAME(sc)); err = ETIMEDOUT; goto out; } if (sc->host_interrupt_operation_mode) { /* * This is a bit of an abuse - This is needed for 7260 / 3160 * only check host_interrupt_operation_mode even if this is * not related to host_interrupt_operation_mode. * * Enable the oscillator to count wake up time for L1 exit. This * consumes slightly more power (100uA) - but allows to be sure * that we wake up from L1 on time. * * This looks weird: read twice the same register, discard the * value, set a bit, and yet again, read that same register * just to discard the value. But that's the way the hardware * seems to like it. */ if (iwm_nic_lock(sc)) { iwm_read_prph(sc, IWM_OSC_CLK); iwm_read_prph(sc, IWM_OSC_CLK); iwm_nic_unlock(sc); } iwm_set_bits_prph(sc, IWM_OSC_CLK, IWM_OSC_CLK_FORCE_CONTROL); if (iwm_nic_lock(sc)) { iwm_read_prph(sc, IWM_OSC_CLK); iwm_read_prph(sc, IWM_OSC_CLK); iwm_nic_unlock(sc); } } /* * Enable DMA clock and wait for it to stabilize. * * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits * do not disable clocks. This preserves any hardware bits already * set by default in "CLK_CTRL_REG" after reset. */ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { if (iwm_nic_lock(sc)) { iwm_write_prph(sc, IWM_APMG_CLK_EN_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT); iwm_nic_unlock(sc); } DELAY(20); /* Disable L1-Active */ iwm_set_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG, IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS); /* Clear the interrupt in APMG if the NIC is in RFKILL */ if (iwm_nic_lock(sc)) { iwm_write_prph(sc, IWM_APMG_RTC_INT_STT_REG, IWM_APMG_RTC_INT_STT_RFKILL); iwm_nic_unlock(sc); } } out: if (err) XYLog("%s: apm init error %d\n", DEVNAME(sc), err); return err; } void ItlIwm:: iwm_apm_stop(struct iwm_softc *sc) { IWM_SETBITS(sc, IWM_CSR_DBG_LINK_PWR_MGMT_REG, IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED); IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG, IWM_CSR_HW_IF_CONFIG_REG_PREPARE | IWM_CSR_HW_IF_CONFIG_REG_ENABLE_PME); DELAY(1000); IWM_CLRBITS(sc, IWM_CSR_DBG_LINK_PWR_MGMT_REG, IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED); DELAY(5000); /* stop device's busmaster DMA activity */ IWM_SETBITS(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_STOP_MASTER); if (!iwm_poll_bit(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, 100)) XYLog("%s: timeout waiting for master\n", DEVNAME(sc)); /* * Clear "initialization complete" bit to move adapter from * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE); } void ItlIwm:: iwm_init_msix_hw(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); iwm_conf_msix_hw(sc, 0); if (!sc->sc_msix) return; sc->sc_fh_init_mask = ~IWM_READ(sc, IWM_CSR_MSIX_FH_INT_MASK_AD); sc->sc_fh_mask = sc->sc_fh_init_mask; sc->sc_hw_init_mask = ~IWM_READ(sc, IWM_CSR_MSIX_HW_INT_MASK_AD); sc->sc_hw_mask = sc->sc_hw_init_mask; } void ItlIwm:: iwm_conf_msix_hw(struct iwm_softc *sc, int stopped) { XYLog("%s\n", __FUNCTION__); int vector = 0; if (!sc->sc_msix) { /* Newer chips default to MSIX. */ if (sc->sc_mqrx_supported && !stopped && iwm_nic_lock(sc)) { iwm_write_prph(sc, IWM_UREG_CHICK, IWM_UREG_CHICK_MSI_ENABLE); iwm_nic_unlock(sc); } return; } if (!stopped && iwm_nic_lock(sc)) { iwm_write_prph(sc, IWM_UREG_CHICK, IWM_UREG_CHICK_MSIX_ENABLE); iwm_nic_unlock(sc); } /* Disable all interrupts */ IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, ~0); IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, ~0); /* Map fallback-queue (command/mgmt) to a single vector */ IWM_WRITE_1(sc, IWM_CSR_MSIX_RX_IVAR(0), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); /* Map RSS queue (data) to the same vector */ IWM_WRITE_1(sc, IWM_CSR_MSIX_RX_IVAR(1), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); /* Enable the RX queues cause interrupts */ IWM_CLRBITS(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, IWM_MSIX_FH_INT_CAUSES_Q0 | IWM_MSIX_FH_INT_CAUSES_Q1); /* Map non-RX causes to the same vector */ IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_D2S_CH0_NUM), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_D2S_CH1_NUM), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_S2D), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_FH_ERR), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_ALIVE), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_WAKEUP), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_IML), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_CT_KILL), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_RF_KILL), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_PERIODIC), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_SW_ERR), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_SCD), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_FH_TX), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_HW_ERR), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); IWM_WRITE_1(sc, IWM_CSR_MSIX_IVAR(IWM_MSIX_IVAR_CAUSE_REG_HAP), vector | IWM_MSIX_NON_AUTO_CLEAR_CAUSE); /* Enable non-RX causes interrupts */ IWM_CLRBITS(sc, IWM_CSR_MSIX_FH_INT_MASK_AD, IWM_MSIX_FH_INT_CAUSES_D2S_CH0_NUM | IWM_MSIX_FH_INT_CAUSES_D2S_CH1_NUM | IWM_MSIX_FH_INT_CAUSES_S2D | IWM_MSIX_FH_INT_CAUSES_FH_ERR); IWM_CLRBITS(sc, IWM_CSR_MSIX_HW_INT_MASK_AD, IWM_MSIX_HW_INT_CAUSES_REG_ALIVE | IWM_MSIX_HW_INT_CAUSES_REG_WAKEUP | IWM_MSIX_HW_INT_CAUSES_REG_IML | IWM_MSIX_HW_INT_CAUSES_REG_CT_KILL | IWM_MSIX_HW_INT_CAUSES_REG_RF_KILL | IWM_MSIX_HW_INT_CAUSES_REG_PERIODIC | IWM_MSIX_HW_INT_CAUSES_REG_SW_ERR | IWM_MSIX_HW_INT_CAUSES_REG_SCD | IWM_MSIX_HW_INT_CAUSES_REG_FH_TX | IWM_MSIX_HW_INT_CAUSES_REG_HW_ERR | IWM_MSIX_HW_INT_CAUSES_REG_HAP); } int ItlIwm:: iwm_clear_persistence_bit(struct iwm_softc *sc) { uint32_t hpm, wprot; hpm = iwm_read_prph_unlocked(sc, IWM_HPM_DEBUG); if (hpm != 0xa5a5a5a0 && (hpm & IWM_HPM_PERSISTENCE_BIT)) { wprot = iwm_read_prph_unlocked(sc, IWM_PREG_PRPH_WPROT_9000); if (wprot & IWM_PREG_WFPM_ACCESS) { printf("%s: cannot clear persistence bit\n", DEVNAME(sc)); return EPERM; } iwm_write_prph_unlocked(sc, IWM_HPM_DEBUG, hpm & ~IWM_HPM_PERSISTENCE_BIT); } return 0; } int ItlIwm:: iwm_start_hw(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); int err; err = iwm_prepare_card_hw(sc); if (err) return err; if (sc->sc_device_family == IWM_DEVICE_FAMILY_9000) { err = iwm_clear_persistence_bit(sc); if (err) return err; } /* Reset the entire device */ IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET); DELAY(5000); err = iwm_apm_init(sc); if (err) return err; iwm_init_msix_hw(sc); iwm_enable_rfkill_int(sc); iwm_check_rfkill(sc); return 0; } void ItlIwm:: iwm_stop_device(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); int chnl, ntries; int qid; iwm_disable_interrupts(sc); sc->sc_flags &= ~IWM_FLAG_USE_ICT; /* Stop all DMA channels. */ if (iwm_nic_lock(sc)) { /* Deactivate TX scheduler. */ iwm_write_prph(sc, IWM_SCD_TXFACT, 0); for (chnl = 0; chnl < IWM_FH_TCSR_CHNL_NUM; chnl++) { IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl), 0); for (ntries = 0; ntries < 200; ntries++) { uint32_t r; r = IWM_READ(sc, IWM_FH_TSSR_TX_STATUS_REG); if (r & IWM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE( chnl)) break; DELAY(20); } } iwm_nic_unlock(sc); } iwm_disable_rx_dma(sc); iwm_reset_rx_ring(sc, &sc->rxq); for (qid = 0; qid < nitems(sc->txq); qid++) iwm_reset_tx_ring(sc, &sc->txq[qid]); if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { if (iwm_nic_lock(sc)) { /* Power-down device's busmaster DMA clocks */ iwm_write_prph(sc, IWM_APMG_CLK_DIS_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT); iwm_nic_unlock(sc); } DELAY(5); } /* Make sure (redundant) we've released our request to stay awake */ IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); if (sc->sc_nic_locks > 0) XYLog("%s: %d active NIC locks forcefully cleared\n", DEVNAME(sc), sc->sc_nic_locks); sc->sc_nic_locks = 0; /* Stop the device, and put it in low power state */ iwm_apm_stop(sc); /* Reset the on-board processor. */ IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET); DELAY(5000); /* * Upon stop, the IVAR table gets erased, so msi-x won't * work. This causes a bug in RF-KILL flows, since the interrupt * that enables radio won't fire on the correct irq, and the * driver won't be able to handle the interrupt. * Configure the IVAR table again after reset. */ iwm_conf_msix_hw(sc, 1); /* * Upon stop, the APM issues an interrupt if HW RF kill is set. * Clear the interrupt again. */ iwm_disable_interrupts(sc); /* Even though we stop the HW we still want the RF kill interrupt. */ iwm_enable_rfkill_int(sc); iwm_check_rfkill(sc); iwm_prepare_card_hw(sc); } void ItlIwm:: iwm_nic_config(struct iwm_softc *sc) { uint8_t radio_cfg_type, radio_cfg_step, radio_cfg_dash; uint32_t mask, val, reg_val = 0; radio_cfg_type = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_TYPE) >> IWM_FW_PHY_CFG_RADIO_TYPE_POS; radio_cfg_step = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_STEP) >> IWM_FW_PHY_CFG_RADIO_STEP_POS; radio_cfg_dash = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_DASH) >> IWM_FW_PHY_CFG_RADIO_DASH_POS; reg_val |= IWM_CSR_HW_REV_STEP(sc->sc_hw_rev) << IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; reg_val |= IWM_CSR_HW_REV_DASH(sc->sc_hw_rev) << IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; /* radio configuration */ reg_val |= radio_cfg_type << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; reg_val |= radio_cfg_step << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; reg_val |= radio_cfg_dash << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; mask = IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | IWM_CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | IWM_CSR_HW_IF_CONFIG_REG_BIT_MAC_SI; val = IWM_READ(sc, IWM_CSR_HW_IF_CONFIG_REG); val &= ~mask; val |= reg_val; IWM_WRITE(sc, IWM_CSR_HW_IF_CONFIG_REG, val); /* * W/A : NIC is stuck in a reset state after Early PCIe power off * (PCIe power is lost before PERST# is asserted), causing ME FW * to lose ownership and not being able to obtain it back. */ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG, IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); } int ItlIwm:: iwm_nic_rx_init(struct iwm_softc *sc) { if (sc->sc_mqrx_supported) return iwm_nic_rx_mq_init(sc); else return iwm_nic_rx_legacy_init(sc); } int ItlIwm:: iwm_nic_rx_mq_init(struct iwm_softc *sc) { int enabled; if (!iwm_nic_lock(sc)) return EBUSY; /* Stop RX DMA. */ iwm_write_prph(sc, IWM_RFH_RXF_DMA_CFG, 0); /* Disable RX used and free queue operation. */ iwm_write_prph(sc, IWM_RFH_RXF_RXQ_ACTIVE, 0); iwm_write_prph64(sc, IWM_RFH_Q0_FRBDCB_BA_LSB, sc->rxq.free_desc_dma.paddr); iwm_write_prph64(sc, IWM_RFH_Q0_URBDCB_BA_LSB, sc->rxq.used_desc_dma.paddr); iwm_write_prph64(sc, IWM_RFH_Q0_URBD_STTS_WPTR_LSB, sc->rxq.stat_dma.paddr); iwm_write_prph(sc, IWM_RFH_Q0_FRBDCB_WIDX, 0); iwm_write_prph(sc, IWM_RFH_Q0_FRBDCB_RIDX, 0); iwm_write_prph(sc, IWM_RFH_Q0_URBDCB_WIDX, 0); /* We configure only queue 0 for now. */ enabled = ((1 << 0) << 16) | (1 << 0); /* Enable RX DMA, 4KB buffer size. */ iwm_write_prph(sc, IWM_RFH_RXF_DMA_CFG, IWM_RFH_DMA_EN_ENABLE_VAL | IWM_RFH_RXF_DMA_RB_SIZE_4K | IWM_RFH_RXF_DMA_MIN_RB_4_8 | IWM_RFH_RXF_DMA_DROP_TOO_LARGE_MASK | IWM_RFH_RXF_DMA_RBDCB_SIZE_512); /* Enable RX DMA snooping. */ iwm_write_prph(sc, IWM_RFH_GEN_CFG, IWM_RFH_GEN_CFG_RFH_DMA_SNOOP | IWM_RFH_GEN_CFG_SERVICE_DMA_SNOOP | (sc->sc_integrated ? IWM_RFH_GEN_CFG_RB_CHUNK_SIZE_64 : IWM_RFH_GEN_CFG_RB_CHUNK_SIZE_128)); /* Enable the configured queue(s). */ iwm_write_prph(sc, IWM_RFH_RXF_RXQ_ACTIVE, enabled); iwm_nic_unlock(sc); IWM_WRITE_1(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_TIMEOUT_DEF); IWM_WRITE(sc, IWM_RFH_Q0_FRBDCB_WIDX_TRG, 8); return 0; } int ItlIwm:: iwm_nic_rx_legacy_init(struct iwm_softc *sc) { memset(sc->rxq.stat, 0, sizeof(*sc->rxq.stat)); iwm_disable_rx_dma(sc); if (!iwm_nic_lock(sc)) return EBUSY; /* reset and flush pointers */ IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0); IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0); IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RDPTR, 0); IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); /* Set physical address of RX ring (256-byte aligned). */ IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG, sc->rxq.free_desc_dma.paddr >> 8); /* Set physical address of RX status (16-byte aligned). */ IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG, sc->rxq.stat_dma.paddr >> 4); /* Enable RX. */ IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, IWM_FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | /* HW bug */ IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | (IWM_RX_RB_TIMEOUT << IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) | IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K | IWM_RX_QUEUE_SIZE_LOG << IWM_FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS); IWM_WRITE_1(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_TIMEOUT_DEF); /* W/A for interrupt coalescing bug in 7260 and 3160 */ if (sc->host_interrupt_operation_mode) IWM_SETBITS(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_OPER_MODE); iwm_nic_unlock(sc); /* * This value should initially be 0 (before preparing any RBs), * and should be 8 after preparing the first 8 RBs (for example). */ IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, 8); return 0; } int ItlIwm:: iwm_nic_tx_init(struct iwm_softc *sc) { int qid; if (!iwm_nic_lock(sc)) return EBUSY; /* Deactivate TX scheduler. */ iwm_write_prph(sc, IWM_SCD_TXFACT, 0); /* Set physical address of "keep warm" page (16-byte aligned). */ IWM_WRITE(sc, IWM_FH_KW_MEM_ADDR_REG, sc->kw_dma.paddr >> 4); for (qid = 0; qid < nitems(sc->txq); qid++) { struct iwm_tx_ring *txq = &sc->txq[qid]; /* Set physical address of TX ring (256-byte aligned). */ IWM_WRITE(sc, IWM_FH_MEM_CBBC_QUEUE(qid), txq->desc_dma.paddr >> 8); } iwm_set_bits_prph(sc, IWM_SCD_GP_CTRL, IWM_SCD_GP_CTRL_AUTO_ACTIVE_MODE | IWM_SCD_GP_CTRL_ENABLE_31_QUEUES); iwm_nic_unlock(sc); return 0; } int ItlIwm:: iwm_nic_init(struct iwm_softc *sc) { int err; iwm_apm_init(sc); if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG, IWM_APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~IWM_APMG_PS_CTRL_MSK_PWR_SRC); iwm_nic_config(sc); err = iwm_nic_rx_init(sc); if (err) return err; err = iwm_nic_tx_init(sc); if (err) return err; IWM_SETBITS(sc, IWM_CSR_MAC_SHADOW_REG_CTRL, 0x800fffff); return 0; } void ItlIwm:: iwm_restore_interrupts(struct iwm_softc *sc) { IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask); } ================================================ FILE: itlwm/hal_iwm/if_iwmreg.h ================================================ /* * 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. */ /* $OpenBSD: if_iwmreg.h,v 1.48 2020/05/18 17:56:41 stsp Exp $ */ /****************************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ /* * CSR (control and status registers) * * CSR registers are mapped directly into PCI bus space, and are accessible * whenever platform supplies power to device, even when device is in * low power states due to driver-invoked device resets * (e.g. IWM_CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes. * * Use iwl_write32() and iwl_read32() family to access these registers; * these provide simple PCI bus access, without waking up the MAC. * Do not use iwl_write_direct32() family for these registers; * no need to "grab nic access" via IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ. * The MAC (uCode processor, etc.) does not need to be powered up for accessing * the CSR registers. * * NOTE: Device does need to be awake in order to read this memory * via IWM_CSR_EEPROM and IWM_CSR_OTP registers */ #define IWM_CSR_HW_IF_CONFIG_REG (0x000) /* hardware interface config */ #define IWM_CSR_INT_COALESCING (0x004) /* accum ints, 32-usec units */ #define IWM_CSR_INT (0x008) /* host interrupt status/ack */ #define IWM_CSR_INT_MASK (0x00c) /* host interrupt enable */ #define IWM_CSR_FH_INT_STATUS (0x010) /* busmaster int status/ack*/ #define IWM_CSR_GPIO_IN (0x018) /* read external chip pins */ #define IWM_CSR_RESET (0x020) /* busmaster enable, NMI, etc*/ #define IWM_CSR_GP_CNTRL (0x024) /* 2nd byte of IWM_CSR_INT_COALESCING, not accessible via iwl_write32()! */ #define IWM_CSR_INT_PERIODIC_REG (0x005) /* * Hardware revision info * Bit fields: * 31-16: Reserved * 15-4: Type of device: see IWM_CSR_HW_REV_TYPE_xxx definitions * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D * 1-0: "Dash" (-) value, as in A-1, etc. */ #define IWM_CSR_HW_REV (0x028) /* * EEPROM and OTP (one-time-programmable) memory reads * * NOTE: Device must be awake, initialized via apm_ops.init(), * in order to read. */ #define IWM_CSR_EEPROM_REG (0x02c) #define IWM_CSR_EEPROM_GP (0x030) #define IWM_CSR_OTP_GP_REG (0x034) #define IWM_CSR_GIO_REG (0x03C) #define IWM_CSR_GP_UCODE_REG (0x048) #define IWM_CSR_GP_DRIVER_REG (0x050) /* * UCODE-DRIVER GP (general purpose) mailbox registers. * SET/CLR registers set/clear bit(s) if "1" is written. */ #define IWM_CSR_UCODE_DRV_GP1 (0x054) #define IWM_CSR_UCODE_DRV_GP1_SET (0x058) #define IWM_CSR_UCODE_DRV_GP1_CLR (0x05c) #define IWM_CSR_UCODE_DRV_GP2 (0x060) #define IWM_CSR_MBOX_SET_REG (0x088) #define IWM_CSR_MBOX_SET_REG_OS_ALIVE 0x20 #define IWM_CSR_LED_REG (0x094) #define IWM_CSR_DRAM_INT_TBL_REG (0x0A0) #define IWM_CSR_MAC_SHADOW_REG_CTRL (0x0A8) /* 6000 and up */ /* GIO Chicken Bits (PCI Express bus link power management) */ #define IWM_CSR_GIO_CHICKEN_BITS (0x100) /* Analog phase-lock-loop configuration */ #define IWM_CSR_ANA_PLL_CFG (0x20c) /* * CSR Hardware Revision Workaround Register. Indicates hardware rev; * "step" determines CCK backoff for txpower calculation. Used for 4965 only. * See also IWM_CSR_HW_REV register. * Bit fields: * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step * 1-0: "Dash" (-) value, as in C-1, etc. */ #define IWM_CSR_HW_REV_WA_REG (0x22C) #define IWM_CSR_DBG_HPET_MEM_REG (0x240) #define IWM_CSR_DBG_LINK_PWR_MGMT_REG (0x250) /* Bits for IWM_CSR_HW_IF_CONFIG_REG */ #define IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH (0x00000003) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP (0x0000000C) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x000000C0) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE (0x00000C00) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH (0x00003000) #define IWM_CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP (0x0000C000) #define IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_DASH (0) #define IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_STEP (2) #define IWM_CSR_HW_IF_CONFIG_REG_POS_BOARD_VER (6) #define IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE (10) #define IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH (12) #define IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP (14) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) #define IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ #define IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ #define IWM_CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ #define IWM_CSR_HW_IF_CONFIG_REG_ENABLE_PME (0x10000000) #define IWM_CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ #define IWM_CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ #define IWM_CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), * acknowledged (reset) by host writing "1" to flagged bits. */ #define IWM_CSR_INT_BIT_FH_RX (1U << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ #define IWM_CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ #define IWM_CSR_INT_BIT_RX_PERIODIC (1 << 28) /* Rx periodic */ #define IWM_CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ #define IWM_CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ #define IWM_CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ #define IWM_CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ #define IWM_CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ #define IWM_CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ #define IWM_CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ #define IWM_CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ #define IWM_CSR_INI_SET_MASK (IWM_CSR_INT_BIT_FH_RX | \ IWM_CSR_INT_BIT_HW_ERR | \ IWM_CSR_INT_BIT_FH_TX | \ IWM_CSR_INT_BIT_SW_ERR | \ IWM_CSR_INT_BIT_RF_KILL | \ IWM_CSR_INT_BIT_SW_RX | \ IWM_CSR_INT_BIT_WAKEUP | \ IWM_CSR_INT_BIT_ALIVE | \ IWM_CSR_INT_BIT_RX_PERIODIC) /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ #define IWM_CSR_FH_INT_BIT_ERR (1U << 31) /* Error */ #define IWM_CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ #define IWM_CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ #define IWM_CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ #define IWM_CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ #define IWM_CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ #define IWM_CSR_FH_INT_RX_MASK (IWM_CSR_FH_INT_BIT_HI_PRIOR | \ IWM_CSR_FH_INT_BIT_RX_CHNL1 | \ IWM_CSR_FH_INT_BIT_RX_CHNL0) #define IWM_CSR_FH_INT_TX_MASK (IWM_CSR_FH_INT_BIT_TX_CHNL1 | \ IWM_CSR_FH_INT_BIT_TX_CHNL0) /* GPIO */ #define IWM_CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) #define IWM_CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) #define IWM_CSR_GPIO_IN_VAL_VMAIN_PWR_SRC (0x00000200) /* RESET */ #define IWM_CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) #define IWM_CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) #define IWM_CSR_RESET_REG_FLAG_SW_RESET (0x00000080) #define IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) #define IWM_CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) #define IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000) /* * GP (general purpose) CONTROL REGISTER * Bit fields: * 27: HW_RF_KILL_SW * Indicates state of (platform's) hardware RF-Kill switch * 26-24: POWER_SAVE_TYPE * Indicates current power-saving mode: * 000 -- No power saving * 001 -- MAC power-down * 010 -- PHY (radio) power-down * 011 -- Error * 9-6: SYS_CONFIG * Indicates current system configuration, reflecting pins on chip * as forced high/low by device circuit board. * 4: GOING_TO_SLEEP * Indicates MAC is entering a power-saving sleep power-down. * Not a good time to access device-internal resources. * 3: MAC_ACCESS_REQ * Host sets this to request and maintain MAC wakeup, to allow host * access to device-internal resources. Host must wait for * MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR * device registers. * 2: INIT_DONE * Host sets this to put device into fully operational D0 power mode. * Host resets this after SW_RESET to put device into low power mode. * 0: MAC_CLOCK_READY * Indicates MAC (ucode processor, etc.) is powered up and can run. * Internal resources are accessible. * NOTE: This does not indicate that the processor is actually running. * NOTE: This does not indicate that device has completed * init or post-power-down restore of internal SRAM memory. * Use IWM_CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that * SRAM is restored and uCode is in normal operation mode. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and * do not need to save/restore it. * NOTE: After device reset, this bit remains "0" until host sets * INIT_DONE */ #define IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) #define IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) #define IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) #define IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) #define IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) #define IWM_CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) #define IWM_CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN (0x04000000) #define IWM_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) /* HW REV */ #define IWM_CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) #define IWM_CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) #define IWM_CSR_HW_REV_TYPE_MSK (0x000FFF0) #define IWM_CSR_HW_REV_TYPE_5300 (0x0000020) #define IWM_CSR_HW_REV_TYPE_5350 (0x0000030) #define IWM_CSR_HW_REV_TYPE_5100 (0x0000050) #define IWM_CSR_HW_REV_TYPE_5150 (0x0000040) #define IWM_CSR_HW_REV_TYPE_1000 (0x0000060) #define IWM_CSR_HW_REV_TYPE_6x00 (0x0000070) #define IWM_CSR_HW_REV_TYPE_6x50 (0x0000080) #define IWM_CSR_HW_REV_TYPE_6150 (0x0000084) #define IWM_CSR_HW_REV_TYPE_6x05 (0x00000B0) #define IWM_CSR_HW_REV_TYPE_6x30 IWM_CSR_HW_REV_TYPE_6x05 #define IWM_CSR_HW_REV_TYPE_6x35 IWM_CSR_HW_REV_TYPE_6x05 #define IWM_CSR_HW_REV_TYPE_2x30 (0x00000C0) #define IWM_CSR_HW_REV_TYPE_2x00 (0x0000100) #define IWM_CSR_HW_REV_TYPE_105 (0x0000110) #define IWM_CSR_HW_REV_TYPE_135 (0x0000120) #define IWM_CSR_HW_REV_TYPE_7265D (0x0000210) #define IWM_CSR_HW_REV_TYPE_NONE (0x00001F0) /* EEPROM REG */ #define IWM_CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) #define IWM_CSR_EEPROM_REG_BIT_CMD (0x00000002) #define IWM_CSR_EEPROM_REG_MSK_ADDR (0x0000FFFC) #define IWM_CSR_EEPROM_REG_MSK_DATA (0xFFFF0000) /* EEPROM GP */ #define IWM_CSR_EEPROM_GP_VALID_MSK (0x00000007) /* signature */ #define IWM_CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) #define IWM_CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP (0x00000000) #define IWM_CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP (0x00000001) #define IWM_CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K (0x00000002) #define IWM_CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K (0x00000004) /* One-time-programmable memory general purpose reg */ #define IWM_CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */ #define IWM_CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ #define IWM_CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ #define IWM_CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ /* GP REG */ #define IWM_CSR_GP_REG_POWER_SAVE_STATUS_MSK (0x03000000) /* bit 24/25 */ #define IWM_CSR_GP_REG_NO_POWER_SAVE (0x00000000) #define IWM_CSR_GP_REG_MAC_POWER_SAVE (0x01000000) #define IWM_CSR_GP_REG_PHY_POWER_SAVE (0x02000000) #define IWM_CSR_GP_REG_POWER_SAVE_ERROR (0x03000000) /* CSR GIO */ #define IWM_CSR_GIO_REG_VAL_L0S_DISABLED (0x00000002) /* * UCODE-DRIVER GP (general purpose) mailbox register 1 * Host driver and uCode write and/or read this register to communicate with * each other. * Bit fields: * 4: UCODE_DISABLE * Host sets this to request permanent halt of uCode, same as * sending CARD_STATE command with "halt" bit set. * 3: CT_KILL_EXIT * Host sets this to request exit from CT_KILL state, i.e. host thinks * device temperature is low enough to continue normal operation. * 2: CMD_BLOCKED * Host sets this during RF KILL power-down sequence (HW, SW, CT KILL) * to release uCode to clear all Tx and command queues, enter * unassociated mode, and power down. * NOTE: Some devices also use HBUS_TARG_MBX_C register for this bit. * 1: SW_BIT_RFKILL * Host sets this when issuing CARD_STATE command to request * device sleep. * 0: MAC_SLEEP * uCode sets this when preparing a power-saving power-down. * uCode resets this when power-up is complete and SRAM is sane. * NOTE: device saves internal SRAM data to host when powering down, * and must restore this data after powering back up. * MAC_SLEEP is the best indication that restore is complete. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and * do not need to save/restore it. */ #define IWM_CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) #define IWM_CSR_UCODE_SW_BIT_RFKILL (0x00000002) #define IWM_CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) #define IWM_CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) #define IWM_CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE (0x00000020) /* GP Driver */ #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_SKU_MSK (0x00000003) #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_SKU_3x3_HYB (0x00000000) #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_HYB (0x00000001) #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA (0x00000002) #define IWM_CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6 (0x00000004) #define IWM_CSR_GP_DRIVER_REG_BIT_6050_1x2 (0x00000008) #define IWM_CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER (0x00000080) /* GIO Chicken Bits (PCI Express bus link power management) */ #define IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) /* LED */ #define IWM_CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF) #define IWM_CSR_LED_REG_TURN_ON (0x60) #define IWM_CSR_LED_REG_TURN_OFF (0x20) /* ANA_PLL */ #define IWM_CSR50_ANA_PLL_CFG_VAL (0x00880300) /* HPET MEM debug */ #define IWM_CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) /* DRAM INT TABLE */ #define IWM_CSR_DRAM_INT_TBL_ENABLE (1U << 31) #define IWM_CSR_DRAM_INIT_TBL_WRITE_POINTER (1 << 28) #define IWM_CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) /* SECURE boot registers */ #define IWM_CSR_SECURE_BOOT_CONFIG_ADDR (0x100) #define IWM_CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP 0x00000001 #define IWM_CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ 0x00000002 #define IWM_CSR_SECURE_BOOT_CPU1_STATUS_ADDR (0x100) #define IWM_CSR_SECURE_BOOT_CPU2_STATUS_ADDR (0x100) #define IWM_CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS 0x00000003 #define IWM_CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED 0x00000002 #define IWM_CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS 0x00000004 #define IWM_CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL 0x00000008 #define IWM_CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL 0x00000010 #define IWM_FH_UCODE_LOAD_STATUS 0x1af0 #define IWM_FH_MEM_TB_MAX_LENGTH 0x20000 /* 9000 rx series registers */ #define IWM_RFH_Q0_FRBDCB_BA_LSB 0xA08000 /* 64 bit address */ #define IWM_RFH_Q_FRBDCB_BA_LSB(q) (IWM_RFH_Q0_FRBDCB_BA_LSB + (q) * 8) /* Write index table */ #define IWM_RFH_Q0_FRBDCB_WIDX 0xA08080 #define IWM_RFH_Q_FRBDCB_WIDX(q) (IWM_RFH_Q0_FRBDCB_WIDX + (q) * 4) /* Write index table - shadow registers */ #define IWM_RFH_Q0_FRBDCB_WIDX_TRG 0x1C80 #define IWM_RFH_Q_FRBDCB_WIDX_TRG(q) (IWM_RFH_Q0_FRBDCB_WIDX_TRG + (q) * 4) /* Read index table */ #define IWM_RFH_Q0_FRBDCB_RIDX 0xA080C0 #define IWM_RFH_Q_FRBDCB_RIDX(q) (IWM_RFH_Q0_FRBDCB_RIDX + (q) * 4) /* Used list table */ #define IWM_RFH_Q0_URBDCB_BA_LSB 0xA08100 /* 64 bit address */ #define IWM_RFH_Q_URBDCB_BA_LSB(q) (IWM_RFH_Q0_URBDCB_BA_LSB + (q) * 8) /* Write index table */ #define IWM_RFH_Q0_URBDCB_WIDX 0xA08180 #define IWM_RFH_Q_URBDCB_WIDX(q) (IWM_RFH_Q0_URBDCB_WIDX + (q) * 4) #define IWM_RFH_Q0_URBDCB_VAID 0xA081C0 #define IWM_RFH_Q_URBDCB_VAID(q) (IWM_RFH_Q0_URBDCB_VAID + (q) * 4) /* stts */ #define IWM_RFH_Q0_URBD_STTS_WPTR_LSB 0xA08200 /*64 bits address */ #define IWM_RFH_Q_URBD_STTS_WPTR_LSB(q) (IWM_RFH_Q0_URBD_STTS_WPTR_LSB + (q) * 8) #define IWM_RFH_Q0_ORB_WPTR_LSB 0xA08280 #define IWM_RFH_Q_ORB_WPTR_LSB(q) (IWM_RFH_Q0_ORB_WPTR_LSB + (q) * 8) #define IWM_RFH_RBDBUF_RBD0_LSB 0xA08300 #define IWM_RFH_RBDBUF_RBD_LSB(q) (IWM_RFH_RBDBUF_RBD0_LSB + (q) * 8) /** * RFH Status Register * * Bit fields: * * Bit 29: RBD_FETCH_IDLE * This status flag is set by the RFH when there is no active RBD fetch from * DRAM. * Once the RFH RBD controller starts fetching (or when there is a pending * RBD read response from DRAM), this flag is immediately turned off. * * Bit 30: SRAM_DMA_IDLE * This status flag is set by the RFH when there is no active transaction from * SRAM to DRAM. * Once the SRAM to DRAM DMA is active, this flag is immediately turned off. * * Bit 31: RXF_DMA_IDLE * This status flag is set by the RFH when there is no active transaction from * RXF to DRAM. * Once the RXF-to-DRAM DMA is active, this flag is immediately turned off. */ #define IWM_RFH_GEN_STATUS 0xA09808 #define IWM_RFH_GEN_STATUS_GEN3 0xA07824 #define IWM_RBD_FETCH_IDLE (1 << 29) #define IWM_SRAM_DMA_IDLE (1 << 30) #define IWM_RXF_DMA_IDLE (1U << 31) /* DMA configuration */ #define IWM_RFH_RXF_DMA_CFG 0xA09820 #define IWM_RFH_RXF_DMA_CFG_GEN3 0xA07880 /* RB size */ #define IWM_RFH_RXF_DMA_RB_SIZE_MASK (0x000F0000) /* bits 16-19 */ #define IWM_RFH_RXF_DMA_RB_SIZE_POS 16 #define IWM_RFH_RXF_DMA_RB_SIZE_1K (0x1 << IWM_RFH_RXF_DMA_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_RB_SIZE_2K (0x2 << IWM_RFH_RXF_DMA_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_RB_SIZE_4K (0x4 << IWM_RFH_RXF_DMA_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_RB_SIZE_8K (0x8 << IWM_RFH_RXF_DMA_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_RB_SIZE_12K (0x9 << IWM_RFH_RXF_DMA_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_RB_SIZE_16K (0xA << IWM_RFH_RXF_DMA_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_RB_SIZE_20K (0xB << IWM_RFH_RXF_DMA_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_RB_SIZE_24K (0xC << IWM_RFH_RXF_DMA_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_RB_SIZE_28K (0xD << IWM_RFH_RXF_DMA_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_RB_SIZE_32K (0xE << IWM_RFH_RXF_DMA_RB_SIZE_POS) /* RB Circular Buffer size:defines the table sizes in RBD units */ #define IWM_RFH_RXF_DMA_RBDCB_SIZE_MASK (0x00F00000) /* bits 20-23 */ #define IWM_RFH_RXF_DMA_RBDCB_SIZE_POS 20 #define IWM_RFH_RXF_DMA_RBDCB_SIZE_8 (0x3 << IWM_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWM_RFH_RXF_DMA_RBDCB_SIZE_16 (0x4 << IWM_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWM_RFH_RXF_DMA_RBDCB_SIZE_32 (0x5 << IWM_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWM_RFH_RXF_DMA_RBDCB_SIZE_64 (0x7 << IWM_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWM_RFH_RXF_DMA_RBDCB_SIZE_128 (0x7 << IWM_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWM_RFH_RXF_DMA_RBDCB_SIZE_256 (0x8 << IWM_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWM_RFH_RXF_DMA_RBDCB_SIZE_512 (0x9 << IWM_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWM_RFH_RXF_DMA_RBDCB_SIZE_1024 (0xA << IWM_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWM_RFH_RXF_DMA_RBDCB_SIZE_2048 (0xB << IWM_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWM_RFH_RXF_DMA_MIN_RB_SIZE_MASK (0x03000000) /* bit 24-25 */ #define IWM_RFH_RXF_DMA_MIN_RB_SIZE_POS 24 #define IWM_RFH_RXF_DMA_MIN_RB_4_8 (3 << IWM_RFH_RXF_DMA_MIN_RB_SIZE_POS) #define IWM_RFH_RXF_DMA_DROP_TOO_LARGE_MASK (0x04000000) /* bit 26 */ #define IWM_RFH_RXF_DMA_SINGLE_FRAME_MASK (0x20000000) /* bit 29 */ #define IWM_RFH_DMA_EN_MASK (0xC0000000) /* bits 30-31*/ #define IWM_RFH_DMA_EN_ENABLE_VAL (1U << 31) #define IWM_RFH_RXF_RXQ_ACTIVE 0xA0980C #define IWM_RFH_GEN_CFG 0xA09800 #define IWM_RFH_GEN_CFG_SERVICE_DMA_SNOOP (1 << 0) #define IWM_RFH_GEN_CFG_RFH_DMA_SNOOP (1 << 1) #define IWM_RFH_GEN_CFG_RB_CHUNK_SIZE_128 0x00000010 #define IWM_RFH_GEN_CFG_RB_CHUNK_SIZE_64 0x00000000 /* the driver assumes everywhere that the default RXQ is 0 */ #define IWM_RFH_GEN_CFG_DEFAULT_RXQ_NUM 0xF00 /* end of 9000 rx series registers */ #define IWM_LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR 0x1e78 #define IWM_LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR 0x1e7c #define IWM_LMPM_SECURE_CPU1_HDR_MEM_SPACE 0x420000 #define IWM_LMPM_SECURE_CPU2_HDR_MEM_SPACE 0x420400 #define IWM_CSR_SECURE_TIME_OUT (100) /* extended range in FW SRAM */ #define IWM_FW_MEM_EXTENDED_START 0x40000 #define IWM_FW_MEM_EXTENDED_END 0x57FFF /* FW chicken bits */ #define IWM_LMPM_CHICK 0xa01ff8 #define IWM_LMPM_CHICK_EXTENDED_ADDR_SPACE 0x01 #define IWM_FH_TCSR_0_REG0 (0x1D00) /* * HBUS (Host-side Bus) * * HBUS registers are mapped directly into PCI bus space, but are used * to indirectly access device's internal memory or registers that * may be powered-down. * * Use iwl_write_direct32()/iwl_read_direct32() family for these registers; * host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ * to make sure the MAC (uCode processor, etc.) is powered up for accessing * internal resources. * * Do not use iwl_write32()/iwl_read32() family to access these registers; * these provide only simple PCI bus access, without waking up the MAC. */ #define IWM_HBUS_BASE (0x400) /* * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM * structures, error log, event log, verifying uCode load). * First write to address register, then read from or write to data register * to complete the job. Once the address register is set up, accesses to * data registers auto-increment the address by one dword. * Bit usage for address registers (read or write): * 0-31: memory address within device */ #define IWM_HBUS_TARG_MEM_RADDR (IWM_HBUS_BASE+0x00c) #define IWM_HBUS_TARG_MEM_WADDR (IWM_HBUS_BASE+0x010) #define IWM_HBUS_TARG_MEM_WDAT (IWM_HBUS_BASE+0x018) #define IWM_HBUS_TARG_MEM_RDAT (IWM_HBUS_BASE+0x01c) /* Mailbox C, used as workaround alternative to CSR_UCODE_DRV_GP1 mailbox */ #define IWM_HBUS_TARG_MBX_C (IWM_HBUS_BASE+0x030) #define IWM_HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) /* * Registers for accessing device's internal peripheral registers * (e.g. SCD, BSM, etc.). First write to address register, * then read from or write to data register to complete the job. * Bit usage for address registers (read or write): * 0-15: register address (offset) within device * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) */ #define IWM_HBUS_TARG_PRPH_WADDR (IWM_HBUS_BASE+0x044) #define IWM_HBUS_TARG_PRPH_RADDR (IWM_HBUS_BASE+0x048) #define IWM_HBUS_TARG_PRPH_WDAT (IWM_HBUS_BASE+0x04c) #define IWM_HBUS_TARG_PRPH_RDAT (IWM_HBUS_BASE+0x050) /* enable the ID buf for read */ #define IWM_WFPM_PS_CTL_CLR 0xa0300c #define IWM_WFMP_MAC_ADDR_0 0xa03080 #define IWM_WFMP_MAC_ADDR_1 0xa03084 #define IWM_LMPM_PMG_EN 0xa01cec #define IWM_RADIO_REG_SYS_MANUAL_DFT_0 0xad4078 #define IWM_RFIC_REG_RD 0xad0470 #define IWM_WFPM_CTRL_REG 0xa03030 #define IWM_WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK 0x08000000 #define IWM_ENABLE_WFPM 0x80000000 #define IWM_AUX_MISC_REG 0xa200b0 #define IWM_HW_STEP_LOCATION_BITS 24 #define IWM_AUX_MISC_MASTER1_EN 0xa20818 #define IWM_AUX_MISC_MASTER1_EN_SBE_MSK 0x1 #define IWM_AUX_MISC_MASTER1_SMPHR_STATUS 0xa20800 #define IWM_RSA_ENABLE 0xa24b08 #define IWM_PREG_AUX_BUS_WPROT_0 0xa04cc0 #define IWM_PREG_PRPH_WPROT_9000 0xa04ce0 #define IWM_PREG_PRPH_WPROT_22000 0xa04d00 #define IWM_SB_CFG_OVERRIDE_ADDR 0xa26c78 #define IWM_SB_CFG_OVERRIDE_ENABLE 0x8000 #define IWM_SB_CFG_BASE_OVERRIDE 0xa20000 #define IWM_SB_MODIFY_CFG_FLAG 0xa03088 #define IWM_SB_CPU_1_STATUS 0xa01e30 #define IWM_SB_CPU_2_STATUS 0Xa01e34 #define IWM_UREG_CHICK 0xa05c00 #define IWM_UREG_CHICK_MSI_ENABLE (1 << 24) #define IWM_UREG_CHICK_MSIX_ENABLE (1 << 25) #define IWM_HPM_DEBUG 0xa03440 #define IWM_HPM_PERSISTENCE_BIT (1 << 12) #define IWM_PREG_WFPM_ACCESS (1 << 12) /* Used to enable DBGM */ #define IWM_HBUS_TARG_TEST_REG (IWM_HBUS_BASE+0x05c) /* * Per-Tx-queue write pointer (index, really!) * Indicates index to next TFD that driver will fill (1 past latest filled). * Bit usage: * 0-7: queue write index * 11-8: queue selector */ #define IWM_HBUS_TARG_WRPTR (IWM_HBUS_BASE+0x060) /********************************************************** * CSR values **********************************************************/ /* * host interrupt timeout value * used with setting interrupt coalescing timer * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit * * default interrupt coalescing timer is 64 x 32 = 2048 usecs */ #define IWM_HOST_INT_TIMEOUT_MAX (0xFF) #define IWM_HOST_INT_TIMEOUT_DEF (0x40) #define IWM_HOST_INT_TIMEOUT_MIN (0x0) #define IWM_HOST_INT_OPER_MODE (1U << 31) /***************************************************************************** * 7000/3000 series SHR DTS addresses * *****************************************************************************/ /* Diode Results Register Structure: */ #define IWM_DTS_DIODE_REG_DIG_VAL 0x000000FF /* bits [7:0] */ #define IWM_DTS_DIODE_REG_VREF_LOW 0x0000FF00 /* bits [15:8] */ #define IWM_DTS_DIODE_REG_VREF_HIGH 0x00FF0000 /* bits [23:16] */ #define IWM_DTS_DIODE_REG_VREF_ID 0x03000000 /* bits [25:24] */ #define IWM_DTS_DIODE_REG_PASS_ONCE 0x80000000 /* bits [31:31] */ #define IWM_DTS_DIODE_REG_FLAGS_MSK 0xFF000000 /* bits [31:24] */ /* Those are the masks INSIDE the flags bit-field: */ #define IWM_DTS_DIODE_REG_FLAGS_VREFS_ID_POS 0 #define IWM_DTS_DIODE_REG_FLAGS_VREFS_ID 0x00000003 /* bits [1:0] */ #define IWM_DTS_DIODE_REG_FLAGS_PASS_ONCE_POS 7 #define IWM_DTS_DIODE_REG_FLAGS_PASS_ONCE 0x00000080 /* bits [7:7] */ /***************************************************************************** * MSIX related registers * *****************************************************************************/ #define IWM_CSR_MSIX_BASE (0x2000) #define IWM_CSR_MSIX_FH_INT_CAUSES_AD (IWM_CSR_MSIX_BASE + 0x800) #define IWM_CSR_MSIX_FH_INT_MASK_AD (IWM_CSR_MSIX_BASE + 0x804) #define IWM_CSR_MSIX_HW_INT_CAUSES_AD (IWM_CSR_MSIX_BASE + 0x808) #define IWM_CSR_MSIX_HW_INT_MASK_AD (IWM_CSR_MSIX_BASE + 0x80C) #define IWM_CSR_MSIX_AUTOMASK_ST_AD (IWM_CSR_MSIX_BASE + 0x810) #define IWM_CSR_MSIX_RX_IVAR_AD_REG (IWM_CSR_MSIX_BASE + 0x880) #define IWM_CSR_MSIX_IVAR_AD_REG (IWM_CSR_MSIX_BASE + 0x890) #define IWM_CSR_MSIX_PENDING_PBA_AD (IWM_CSR_MSIX_BASE + 0x1000) #define IWM_CSR_MSIX_RX_IVAR(cause) (IWM_CSR_MSIX_RX_IVAR_AD_REG + (cause)) #define IWM_CSR_MSIX_IVAR(cause) (IWM_CSR_MSIX_IVAR_AD_REG + (cause)) /* * Causes for the FH register interrupts */ enum iwm_msix_fh_int_causes { IWM_MSIX_FH_INT_CAUSES_Q0 = (1 << 0), IWM_MSIX_FH_INT_CAUSES_Q1 = (1 << 1), IWM_MSIX_FH_INT_CAUSES_D2S_CH0_NUM = (1 << 16), IWM_MSIX_FH_INT_CAUSES_D2S_CH1_NUM = (1 << 17), IWM_MSIX_FH_INT_CAUSES_S2D = (1 << 19), IWM_MSIX_FH_INT_CAUSES_FH_ERR = (1 << 21), }; /* * Causes for the HW register interrupts */ enum iwm_msix_hw_int_causes { IWM_MSIX_HW_INT_CAUSES_REG_ALIVE = (1 << 0), IWM_MSIX_HW_INT_CAUSES_REG_WAKEUP = (1 << 1), IWM_MSIX_HW_INT_CAUSES_REG_IPC = (1 << 1), IWM_MSIX_HW_INT_CAUSES_REG_IML = (1 << 2), IWM_MSIX_HW_INT_CAUSES_REG_SW_ERR_V2 = (1 << 5), IWM_MSIX_HW_INT_CAUSES_REG_CT_KILL = (1 << 6), IWM_MSIX_HW_INT_CAUSES_REG_RF_KILL = (1 << 7), IWM_MSIX_HW_INT_CAUSES_REG_PERIODIC = (1 << 8), IWM_MSIX_HW_INT_CAUSES_REG_SW_ERR = (1 << 25), IWM_MSIX_HW_INT_CAUSES_REG_SCD = (1 << 26), IWM_MSIX_HW_INT_CAUSES_REG_FH_TX = (1 << 27), IWM_MSIX_HW_INT_CAUSES_REG_HW_ERR = (1 << 29), IWM_MSIX_HW_INT_CAUSES_REG_HAP = (1 << 30), }; /* * Registers to map causes to vectors */ enum iwm_msix_ivar_for_cause { IWM_MSIX_IVAR_CAUSE_D2S_CH0_NUM = 0x0, IWM_MSIX_IVAR_CAUSE_D2S_CH1_NUM = 0x1, IWM_MSIX_IVAR_CAUSE_S2D = 0x3, IWM_MSIX_IVAR_CAUSE_FH_ERR = 0x5, IWM_MSIX_IVAR_CAUSE_REG_ALIVE = 0x10, IWM_MSIX_IVAR_CAUSE_REG_WAKEUP = 0x11, IWM_MSIX_IVAR_CAUSE_REG_IML = 0x12, IWM_MSIX_IVAR_CAUSE_REG_CT_KILL = 0x16, IWM_MSIX_IVAR_CAUSE_REG_RF_KILL = 0x17, IWM_MSIX_IVAR_CAUSE_REG_PERIODIC = 0x18, IWM_MSIX_IVAR_CAUSE_REG_SW_ERR = 0x29, IWM_MSIX_IVAR_CAUSE_REG_SCD = 0x2a, IWM_MSIX_IVAR_CAUSE_REG_FH_TX = 0x2b, IWM_MSIX_IVAR_CAUSE_REG_HW_ERR = 0x2d, IWM_MSIX_IVAR_CAUSE_REG_HAP = 0x2e, }; #define IWM_MSIX_AUTO_CLEAR_CAUSE (0 << 7) #define IWM_MSIX_NON_AUTO_CLEAR_CAUSE (1 << 7) /** * uCode API flags * @IWM_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * was a separate TLV but moved here to save space. * @IWM_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, * treats good CRC threshold as a boolean * @IWM_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). * @IWM_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. * @IWM_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS * @IWM_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD * @IWM_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan * offload profile config command. * @IWM_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six * (rather than two) IPv6 addresses * @IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element * from the probe request template. * @IWM_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) * @IWM_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) * @IWM_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a * single bound interface). * @IWM_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD * @IWM_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. * @IWM_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save * @IWM_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. * @IWM_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients * */ #define IWM_UCODE_TLV_FLAGS_PAN (1 << 0) #define IWM_UCODE_TLV_FLAGS_NEWSCAN (1 << 1) #define IWM_UCODE_TLV_FLAGS_MFP (1 << 2) #define IWM_UCODE_TLV_FLAGS_P2P (1 << 3) #define IWM_UCODE_TLV_FLAGS_DW_BC_TABLE (1 << 4) #define IWM_UCODE_TLV_FLAGS_SHORT_BL (1 << 7) #define IWM_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS (1 << 10) #define IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID (1 << 12) #define IWM_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL (1 << 15) #define IWM_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE (1 << 16) #define IWM_UCODE_TLV_FLAGS_P2P_PS (1 << 21) #define IWM_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM (1 << 22) #define IWM_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM (1 << 23) #define IWM_UCODE_TLV_FLAGS_UAPSD_SUPPORT (1 << 24) #define IWM_UCODE_TLV_FLAGS_EBS_SUPPORT (1 << 25) #define IWM_UCODE_TLV_FLAGS_P2P_PS_UAPSD (1 << 26) #define IWM_UCODE_TLV_FLAGS_BCAST_FILTERING (1 << 29) #define IWM_UCODE_TLV_FLAGS_GO_UAPSD (1 << 30) #define IWM_UCODE_TLV_FLAGS_LTE_COEX (1U << 31) #define IWM_UCODE_TLV_FLAG_BITS \ "\020\1PAN\2NEWSCAN\3MFP\4P2P\5DW_BC_TABLE\6NEWBT_COEX\7PM_CMD\10SHORT_BL\11RX_ENERGY\12TIME_EVENT_V2\13D3_6_IPV6\14BF_UPDATED\15NO_BASIC_SSID\17D3_CONTINUITY\20NEW_NSOFFL_S\21NEW_NSOFFL_L\22SCHED_SCAN\24STA_KEY_CMD\25DEVICE_PS_CMD\26P2P_PS\27P2P_PS_DCM\30P2P_PS_SCM\31UAPSD_SUPPORT\32EBS\33P2P_PS_UAPSD\36BCAST_FILTERING\37GO_UAPSD\40LTE_COEX" /** * uCode TLV api * @IWM_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. * @IWM_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * @IWM_UCODE_TLV_API_WIDE_CMD_HDR: ucode supports wide command header * @IWM_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params * @IWM_UCODE_TLV_API_NEW_VERSION: new versioning format * @IWM_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size * (command version 3) that supports per-chain limits * @IWM_UCODE_TLV_API_SCAN_TSF_REPORT: Scan start time reported in scan * iteration complete notification, and the timestamp reported for RX * received during scan, are reported in TSF of the mac specified in the * scan request. * @IWM_UCODE_TLV_API_TKIP_MIC_KEYS: This ucode supports version 2 of * ADD_MODIFY_STA_KEY_API_S_VER_2. * @IWM_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. * @IWM_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority * instead of 3. * @IWM_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used * * @IWM_NUM_UCODE_TLV_API: number of bits used */ #define IWM_UCODE_TLV_API_FRAGMENTED_SCAN 8 #define IWM_UCODE_TLV_API_WIFI_MCC_UPDATE 9 #define IWM_UCODE_TLV_API_WIDE_CMD_HDR 14 #define IWM_UCODE_TLV_API_LQ_SS_PARAMS 18 #define IWM_UCODE_TLV_API_NEW_VERSION 20 #define IWM_UCODE_TLV_API_EXT_SCAN_PRIORITY 24 #define IWM_UCODE_TLV_API_TX_POWER_CHAIN 27 #define IWM_UCODE_TLV_API_SCAN_TSF_REPORT 28 #define IWM_UCODE_TLV_API_TKIP_MIC_KEYS 29 #define IWM_UCODE_TLV_API_STA_TYPE 30 #define IWM_UCODE_TLV_API_NAN2_VER2 31 #define IWM_UCODE_TLV_API_ADAPTIVE_DWELL 32 #define IWM_UCODE_TLV_API_NEW_RX_STATS 35 #define IWM_UCODE_TLV_API_QUOTA_LOW_LATENCY 38 #define IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2 42 #define IWM_UCODE_TLV_API_SCAN_EXT_CHAN_VER 58 #define IWM_NUM_UCODE_TLV_API 128 #define IWM_UCODE_TLV_API_BITS \ "\020\10FRAGMENTED_SCAN\11WIFI_MCC_UPDATE\16WIDE_CMD_HDR\22LQ_SS_PARAMS\30EXT_SCAN_PRIO\33TX_POWER_CHAIN\35TKIP_MIC_KEYS" /** * uCode capabilities * @IWM_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 * @IWM_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory * @IWM_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. * @IWM_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer * @IWM_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM) * @IWM_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality * @IWM_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current * tx power value into TPC Report action frame and Link Measurement Report * action frame * @IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports updating current * channel in DS parameter set element in probe requests. * @IWM_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in * probe requests. * @IWM_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests * @IWM_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), * which also implies support for the scheduler configuration command * @IWM_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching * @IWM_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG: Consolidated D3-D0 image * @IWM_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command * @IWM_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command * @IWM_UCODE_TLV_CAPA_2G_COEX_SUPPORT: supports 2G coex Command * @IWM_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload * @IWM_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics * @IWM_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD * @IWM_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running * @IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different * sources for the MCC. This TLV bit is a future replacement to * IWM_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR * is supported. * @IWM_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC * @IWM_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan * @IWM_UCODE_TLV_CAPA_NAN_SUPPORT: supports NAN * @IWM_UCODE_TLV_CAPA_UMAC_UPLOAD: supports upload mode in umac (1=supported, * 0=no support) * @IWM_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement * @IWM_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts * @IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT * @IWM_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what * antenna the beacon should be transmitted * @IWM_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon * from AP and will send it upon d0i3 exit. * @IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2 * @IWM_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill * @IWM_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature * thresholds reporting * @IWM_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command * @IWM_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in * regular image. * @IWM_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared * memory addresses from the firmware. * @IWM_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement * @IWM_UCODE_TLV_CAPA_LMAC_UPLOAD: supports upload mode in lmac (1=supported, * 0=no support) * * @IWM_NUM_UCODE_TLV_CAPA: number of bits used */ #define IWM_UCODE_TLV_CAPA_D0I3_SUPPORT 0 #define IWM_UCODE_TLV_CAPA_LAR_SUPPORT 1 #define IWM_UCODE_TLV_CAPA_UMAC_SCAN 2 #define IWM_UCODE_TLV_CAPA_BEAMFORMER 3 #define IWM_UCODE_TLV_CAPA_TOF_SUPPORT 5 #define IWM_UCODE_TLV_CAPA_TDLS_SUPPORT 6 #define IWM_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT 8 #define IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT 9 #define IWM_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT 10 #define IWM_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT 11 #define IWM_UCODE_TLV_CAPA_DQA_SUPPORT 12 #define IWM_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH 13 #define IWM_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG 17 #define IWM_UCODE_TLV_CAPA_HOTSPOT_SUPPORT 18 #define IWM_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT 19 #define IWM_UCODE_TLV_CAPA_2G_COEX_SUPPORT 20 #define IWM_UCODE_TLV_CAPA_CSUM_SUPPORT 21 #define IWM_UCODE_TLV_CAPA_RADIO_BEACON_STATS 22 #define IWM_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD 26 #define IWM_UCODE_TLV_CAPA_BT_COEX_PLCR 28 #define IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC 29 #define IWM_UCODE_TLV_CAPA_BT_COEX_RRC 30 #define IWM_UCODE_TLV_CAPA_GSCAN_SUPPORT 31 #define IWM_UCODE_TLV_CAPA_NAN_SUPPORT 34 #define IWM_UCODE_TLV_CAPA_UMAC_UPLOAD 35 #define IWM_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT 37 #define IWM_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT 39 #define IWM_UCODE_TLV_CAPA_CDB_SUPPORT 40 #define IWM_UCODE_TLV_CAPA_DYNAMIC_QUOTA 44 #define IWM_UCODE_TLV_CAPA_COEX_SCHEMA_2 45 #define IWM_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS 48 #define IWM_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE 64 #define IWM_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS 65 #define IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT 67 #define IWM_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT 68 #define IWM_UCODE_TLV_CAPA_BEACON_ANT_SELECTION 71 #define IWM_UCODE_TLV_CAPA_BEACON_STORING 72 #define IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V3 73 #define IWM_UCODE_TLV_CAPA_CT_KILL_BY_FW 74 #define IWM_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT 75 #define IWM_UCODE_TLV_CAPA_CTDP_SUPPORT 76 #define IWM_UCODE_TLV_CAPA_USNIFFER_UNIFIED 77 #define IWM_UCODE_TLV_CAPA_LMAC_UPLOAD 79 #define IWM_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG 80 #define IWM_UCODE_TLV_CAPA_LQM_SUPPORT 81 #define IWM_NUM_UCODE_TLV_CAPA 128 /* The default calibrate table size if not specified by firmware file */ #define IWM_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE 18 #define IWM_MAX_STANDARD_PHY_CALIBRATE_TBL_SIZE 19 #define IWM_MAX_PHY_CALIBRATE_TBL_SIZE 253 /* The default max probe length if not specified by the firmware file */ #define IWM_DEFAULT_MAX_PROBE_LENGTH 200 /* * For 16.0 uCode and above, there is no differentiation between sections, * just an offset to the HW address. */ #define IWM_CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC #define IWM_PAGING_SEPARATOR_SECTION 0xAAAABBBB /* uCode version contains 4 values: Major/Minor/API/Serial */ #define IWM_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) #define IWM_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) #define IWM_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) #define IWM_UCODE_SERIAL(ver) ((ver) & 0x000000FF) /* * Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to * flow triggers. * @event_trigger: bitmap for which calibrations to perform according to * event triggers. */ struct iwm_tlv_calib_ctrl { uint32_t flow_trigger; uint32_t event_trigger; } __packed; #define IWM_FW_PHY_CFG_RADIO_TYPE_POS 0 #define IWM_FW_PHY_CFG_RADIO_TYPE (0x3 << IWM_FW_PHY_CFG_RADIO_TYPE_POS) #define IWM_FW_PHY_CFG_RADIO_STEP_POS 2 #define IWM_FW_PHY_CFG_RADIO_STEP (0x3 << IWM_FW_PHY_CFG_RADIO_STEP_POS) #define IWM_FW_PHY_CFG_RADIO_DASH_POS 4 #define IWM_FW_PHY_CFG_RADIO_DASH (0x3 << IWM_FW_PHY_CFG_RADIO_DASH_POS) #define IWM_FW_PHY_CFG_TX_CHAIN_POS 16 #define IWM_FW_PHY_CFG_TX_CHAIN (0xf << IWM_FW_PHY_CFG_TX_CHAIN_POS) #define IWM_FW_PHY_CFG_RX_CHAIN_POS 20 #define IWM_FW_PHY_CFG_RX_CHAIN (0xf << IWM_FW_PHY_CFG_RX_CHAIN_POS) #define IWM_UCODE_MAX_CS 1 /** * struct iwm_fw_cipher_scheme - a cipher scheme supported by FW. * @cipher: a cipher suite selector * @flags: cipher scheme flags (currently reserved for a future use) * @hdr_len: a size of MPDU security header * @pn_len: a size of PN * @pn_off: an offset of pn from the beginning of the security header * @key_idx_off: an offset of key index byte in the security header * @key_idx_mask: a bit mask of key_idx bits * @key_idx_shift: bit shift needed to get key_idx * @mic_len: mic length in bytes * @hw_cipher: a HW cipher index used in host commands */ struct iwm_fw_cipher_scheme { uint32_t cipher; uint8_t flags; uint8_t hdr_len; uint8_t pn_len; uint8_t pn_off; uint8_t key_idx_off; uint8_t key_idx_mask; uint8_t key_idx_shift; uint8_t mic_len; uint8_t hw_cipher; } __packed; /** * struct iwm_fw_cscheme_list - a cipher scheme list * @size: a number of entries * @cs: cipher scheme entries */ struct iwm_fw_cscheme_list { uint8_t size; struct iwm_fw_cipher_scheme cs[]; } __packed; /* v1/v2 uCode file layout */ struct iwm_ucode_header { uint32_t ver; /* major/minor/API/serial */ union { struct { uint32_t inst_size; /* bytes of runtime code */ uint32_t data_size; /* bytes of runtime data */ uint32_t init_size; /* bytes of init code */ uint32_t init_data_size; /* bytes of init data */ uint32_t boot_size; /* bytes of bootstrap code */ uint8_t data[0]; /* in same order as sizes */ } v1; struct { uint32_t build; /* build number */ uint32_t inst_size; /* bytes of runtime code */ uint32_t data_size; /* bytes of runtime data */ uint32_t init_size; /* bytes of init code */ uint32_t init_data_size; /* bytes of init data */ uint32_t boot_size; /* bytes of bootstrap code */ uint8_t data[0]; /* in same order as sizes */ } v2; } u; }; /* * new TLV uCode file layout * * The new TLV file format contains TLVs, that each specify * some piece of data. */ #define IWM_UCODE_TLV_INVALID 0 /* unused */ #define IWM_UCODE_TLV_INST 1 #define IWM_UCODE_TLV_DATA 2 #define IWM_UCODE_TLV_INIT 3 #define IWM_UCODE_TLV_INIT_DATA 4 #define IWM_UCODE_TLV_BOOT 5 #define IWM_UCODE_TLV_PROBE_MAX_LEN 6 /* a uint32_t value */ #define IWM_UCODE_TLV_PAN 7 #define IWM_UCODE_TLV_RUNT_EVTLOG_PTR 8 #define IWM_UCODE_TLV_RUNT_EVTLOG_SIZE 9 #define IWM_UCODE_TLV_RUNT_ERRLOG_PTR 10 #define IWM_UCODE_TLV_INIT_EVTLOG_PTR 11 #define IWM_UCODE_TLV_INIT_EVTLOG_SIZE 12 #define IWM_UCODE_TLV_INIT_ERRLOG_PTR 13 #define IWM_UCODE_TLV_ENHANCE_SENS_TBL 14 #define IWM_UCODE_TLV_PHY_CALIBRATION_SIZE 15 #define IWM_UCODE_TLV_WOWLAN_INST 16 #define IWM_UCODE_TLV_WOWLAN_DATA 17 #define IWM_UCODE_TLV_FLAGS 18 #define IWM_UCODE_TLV_SEC_RT 19 #define IWM_UCODE_TLV_SEC_INIT 20 #define IWM_UCODE_TLV_SEC_WOWLAN 21 #define IWM_UCODE_TLV_DEF_CALIB 22 #define IWM_UCODE_TLV_PHY_SKU 23 #define IWM_UCODE_TLV_SECURE_SEC_RT 24 #define IWM_UCODE_TLV_SECURE_SEC_INIT 25 #define IWM_UCODE_TLV_SECURE_SEC_WOWLAN 26 #define IWM_UCODE_TLV_NUM_OF_CPU 27 #define IWM_UCODE_TLV_CSCHEME 28 /* * Following two are not in our base tag, but allow * handling ucode version 9. */ #define IWM_UCODE_TLV_API_CHANGES_SET 29 #define IWM_UCODE_TLV_ENABLED_CAPABILITIES 30 #define IWM_UCODE_TLV_N_SCAN_CHANNELS 31 #define IWM_UCODE_TLV_PAGING 32 #define IWM_UCODE_TLV_SEC_RT_USNIFFER 34 #define IWM_UCODE_TLV_SDIO_ADMA_ADDR 35 #define IWM_UCODE_TLV_FW_VERSION 36 #define IWM_UCODE_TLV_FW_DBG_DEST 38 #define IWM_UCODE_TLV_FW_DBG_CONF 39 #define IWM_UCODE_TLV_FW_DBG_TRIGGER 40 #define IWM_UCODE_TLV_CMD_VERSIONS 48 #define IWM_UCODE_TLV_FW_GSCAN_CAPA 50 #define IWM_UCODE_TLV_FW_MEM_SEG 51 #define IWM_UCODE_TLV_UMAC_DEBUG_ADDRS 54 #define IWM_UCODE_TLV_LMAC_DEBUG_ADDRS 55 #define IWM_UCODE_TLV_HW_TYPE 58 #define IWM_UCODE_TLV_DEBUG_BASE 0x1000005 #define IWM_UCODE_TLV_TYPE_DEBUG_INFO (IWM_UCODE_TLV_DEBUG_BASE + 0) #define IWM_UCODE_TLV_TYPE_BUFFER_ALLOCATION (IWM_UCODE_TLV_DEBUG_BASE + 1) #define IWM_UCODE_TLV_TYPE_HCMD (IWM_UCODE_TLV_DEBUG_BASE + 2) #define IWM_UCODE_TLV_TYPE_REGIONS (IWM_UCODE_TLV_DEBUG_BASE + 3) #define IWM_UCODE_TLV_TYPE_TRIGGERS (IWM_UCODE_TLV_DEBUG_BASE + 4) #define IWM_UCODE_TLV_DEBUG_MAX IWM_UCODE_TLV_TYPE_TRIGGERS struct iwm_ucode_tlv { uint32_t type; /* see above */ uint32_t length; /* not including type/length fields */ uint8_t data[0]; }; struct iwm_ucode_api { uint32_t api_index; uint32_t api_flags; } __packed; struct iwm_ucode_capa { uint32_t api_index; uint32_t api_capa; } __packed; #define IWM_TLV_UCODE_MAGIC 0x0a4c5749 struct iwm_tlv_ucode_header { /* * The TLV style ucode header is distinguished from * the v1/v2 style header by first four bytes being * zero, as such is an invalid combination of * major/minor/API/serial versions. */ uint32_t zero; uint32_t magic; uint8_t human_readable[64]; uint32_t ver; /* major/minor/API/serial */ uint32_t build; uint64_t ignore; /* * The data contained herein has a TLV layout, * see above for the TLV header and types. * Note that each TLV is padded to a length * that is a multiple of 4 for alignment. */ uint8_t data[0]; }; /* * Registers in this file are internal, not PCI bus memory mapped. * Driver accesses these via IWM_HBUS_TARG_PRPH_* registers. */ #define IWM_PRPH_BASE (0x00000) #define IWM_PRPH_END (0xFFFFF) /* APMG (power management) constants */ #define IWM_APMG_BASE (IWM_PRPH_BASE + 0x3000) #define IWM_APMG_CLK_CTRL_REG (IWM_APMG_BASE + 0x0000) #define IWM_APMG_CLK_EN_REG (IWM_APMG_BASE + 0x0004) #define IWM_APMG_CLK_DIS_REG (IWM_APMG_BASE + 0x0008) #define IWM_APMG_PS_CTRL_REG (IWM_APMG_BASE + 0x000c) #define IWM_APMG_PCIDEV_STT_REG (IWM_APMG_BASE + 0x0010) #define IWM_APMG_RFKILL_REG (IWM_APMG_BASE + 0x0014) #define IWM_APMG_RTC_INT_STT_REG (IWM_APMG_BASE + 0x001c) #define IWM_APMG_RTC_INT_MSK_REG (IWM_APMG_BASE + 0x0020) #define IWM_APMG_DIGITAL_SVR_REG (IWM_APMG_BASE + 0x0058) #define IWM_APMG_ANALOG_SVR_REG (IWM_APMG_BASE + 0x006C) #define IWM_APMS_CLK_VAL_MRB_FUNC_MODE (0x00000001) #define IWM_APMG_CLK_VAL_DMA_CLK_RQT (0x00000200) #define IWM_APMG_CLK_VAL_BSM_CLK_RQT (0x00000800) #define IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS (0x00400000) #define IWM_APMG_PS_CTRL_VAL_RESET_REQ (0x04000000) #define IWM_APMG_PS_CTRL_MSK_PWR_SRC (0x03000000) #define IWM_APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000) #define IWM_APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000) #define IWM_APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */ #define IWM_APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060) #define IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) #define IWM_APMG_RTC_INT_STT_RFKILL (0x10000000) /* Device system time */ #define IWM_DEVICE_SYSTEM_TIME_REG 0xA0206C /* Device NMI register */ #define IWM_DEVICE_SET_NMI_REG 0x00a01c30 #define IWM_DEVICE_SET_NMI_VAL_HW 0x01 #define IWM_DEVICE_SET_NMI_VAL_DRV 0x80 #define IWM_DEVICE_SET_NMI_8000_REG 0x00a01c24 #define IWM_DEVICE_SET_NMI_8000_VAL 0x1000000 /* * Device reset for family 8000 * write to bit 24 in order to reset the CPU */ #define IWM_RELEASE_CPU_RESET 0x300c #define IWM_RELEASE_CPU_RESET_BIT 0x1000000 /***************************************************************************** * 7000/3000 series SHR DTS addresses * *****************************************************************************/ #define IWM_SHR_MISC_WFM_DTS_EN (0x00a10024) #define IWM_DTSC_CFG_MODE (0x00a10604) #define IWM_DTSC_VREF_AVG (0x00a10648) #define IWM_DTSC_VREF5_AVG (0x00a1064c) #define IWM_DTSC_CFG_MODE_PERIODIC (0x2) #define IWM_DTSC_PTAT_AVG (0x00a10650) /** * Tx Scheduler * * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in * host DRAM. It steers each frame's Tx command (which contains the frame * data) into one of up to 7 prioritized Tx DMA FIFO channels within the * device. A queue maps to only one (selectable by driver) Tx DMA channel, * but one DMA channel may take input from several queues. * * Tx DMA FIFOs have dedicated purposes. * * For 5000 series and up, they are used differently * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c): * * 0 -- EDCA BK (background) frames, lowest priority * 1 -- EDCA BE (best effort) frames, normal priority * 2 -- EDCA VI (video) frames, higher priority * 3 -- EDCA VO (voice) and management frames, highest priority * 4 -- unused * 5 -- unused * 6 -- unused * 7 -- Commands * * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. * In addition, driver can map the remaining queues to Tx DMA/FIFO * channels 0-3 to support 11n aggregation via EDCA DMA channels. * * The driver sets up each queue to work in one of two modes: * * 1) Scheduler-Ack, in which the scheduler automatically supports a * block-ack (BA) window of up to 64 TFDs. In this mode, each queue * contains TFDs for a unique combination of Recipient Address (RA) * and Traffic Identifier (TID), that is, traffic of a given * Quality-Of-Service (QOS) priority, destined for a single station. * * In scheduler-ack mode, the scheduler keeps track of the Tx status of * each frame within the BA window, including whether it's been transmitted, * and whether it's been acknowledged by the receiving station. The device * automatically processes block-acks received from the receiving STA, * and reschedules un-acked frames to be retransmitted (successful * Tx completion may end up being out-of-order). * * The driver must maintain the queue's Byte Count table in host DRAM * for this mode. * This mode does not support fragmentation. * * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. * The device may automatically retry Tx, but will retry only one frame * at a time, until receiving ACK from receiving station, or reaching * retry limit and giving up. * * The command queue (#4/#9) must use this mode! * This mode does not require use of the Byte Count table in host DRAM. * * Driver controls scheduler operation via 3 means: * 1) Scheduler registers * 2) Shared scheduler data base in internal SRAM * 3) Shared data in host DRAM * * Initialization: * * When loading, driver should allocate memory for: * 1) 16 TFD circular buffers, each with space for (typically) 256 TFDs. * 2) 16 Byte Count circular buffers in 16 KBytes contiguous memory * (1024 bytes for each queue). * * After receiving "Alive" response from uCode, driver must initialize * the scheduler (especially for queue #4/#9, the command queue, otherwise * the driver can't issue commands!): */ #define IWM_SCD_MEM_LOWER_BOUND (0x0000) /** * Max Tx window size is the max number of contiguous TFDs that the scheduler * can keep track of at one time when creating block-ack chains of frames. * Note that "64" matches the number of ack bits in a block-ack packet. */ #define IWM_SCD_WIN_SIZE 64 #define IWM_SCD_FRAME_LIMIT 64 #define IWM_SCD_TXFIFO_POS_TID (0) #define IWM_SCD_TXFIFO_POS_RA (4) #define IWM_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) /* agn SCD */ #define IWM_SCD_QUEUE_STTS_REG_POS_TXF (0) #define IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE (3) #define IWM_SCD_QUEUE_STTS_REG_POS_WSL (4) #define IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19) #define IWM_SCD_QUEUE_STTS_REG_MSK (0x017F0000) #define IWM_SCD_QUEUE_CTX_REG1_CREDIT_POS (8) #define IWM_SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) #define IWM_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) #define IWM_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) #define IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0) #define IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) #define IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) #define IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) #define IWM_SCD_GP_CTRL_ENABLE_31_QUEUES (1 << 0) #define IWM_SCD_GP_CTRL_AUTO_ACTIVE_MODE (1 << 18) /* Context Data */ #define IWM_SCD_CONTEXT_MEM_LOWER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x600) #define IWM_SCD_CONTEXT_MEM_UPPER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x6A0) /* Tx status */ #define IWM_SCD_TX_STTS_MEM_LOWER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x6A0) #define IWM_SCD_TX_STTS_MEM_UPPER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x7E0) /* Translation Data */ #define IWM_SCD_TRANS_TBL_MEM_LOWER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x7E0) #define IWM_SCD_TRANS_TBL_MEM_UPPER_BOUND (IWM_SCD_MEM_LOWER_BOUND + 0x808) #define IWM_SCD_CONTEXT_QUEUE_OFFSET(x)\ (IWM_SCD_CONTEXT_MEM_LOWER_BOUND + ((x) * 8)) #define IWM_SCD_TX_STTS_QUEUE_OFFSET(x)\ (IWM_SCD_TX_STTS_MEM_LOWER_BOUND + ((x) * 16)) #define IWM_SCD_TRANS_TBL_OFFSET_QUEUE(x) \ ((IWM_SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc) #define IWM_SCD_BASE (IWM_PRPH_BASE + 0xa02c00) #define IWM_SCD_SRAM_BASE_ADDR (IWM_SCD_BASE + 0x0) #define IWM_SCD_DRAM_BASE_ADDR (IWM_SCD_BASE + 0x8) #define IWM_SCD_AIT (IWM_SCD_BASE + 0x0c) #define IWM_SCD_TXFACT (IWM_SCD_BASE + 0x10) #define IWM_SCD_ACTIVE (IWM_SCD_BASE + 0x14) #define IWM_SCD_QUEUECHAIN_SEL (IWM_SCD_BASE + 0xe8) #define IWM_SCD_CHAINEXT_EN (IWM_SCD_BASE + 0x244) #define IWM_SCD_AGGR_SEL (IWM_SCD_BASE + 0x248) #define IWM_SCD_INTERRUPT_MASK (IWM_SCD_BASE + 0x108) #define IWM_SCD_GP_CTRL (IWM_SCD_BASE + 0x1a8) #define IWM_SCD_EN_CTRL (IWM_SCD_BASE + 0x254) static inline unsigned int IWM_SCD_QUEUE_WRPTR(unsigned int chnl) { if (chnl < 20) return IWM_SCD_BASE + 0x18 + chnl * 4; return IWM_SCD_BASE + 0x284 + (chnl - 20) * 4; } static inline unsigned int IWM_SCD_QUEUE_RDPTR(unsigned int chnl) { if (chnl < 20) return IWM_SCD_BASE + 0x68 + chnl * 4; return IWM_SCD_BASE + 0x2B4 + chnl * 4; } static inline unsigned int IWM_SCD_QUEUE_STATUS_BITS(unsigned int chnl) { if (chnl < 20) return IWM_SCD_BASE + 0x10c + chnl * 4; return IWM_SCD_BASE + 0x334 + chnl * 4; } /*********************** END TX SCHEDULER *************************************/ /* Oscillator clock */ #define IWM_OSC_CLK (0xa04068) #define IWM_OSC_CLK_FORCE_CONTROL (0x8) /****************************/ /* Flow Handler Definitions */ /****************************/ /** * This I/O area is directly read/writable by driver (e.g. Linux uses writel()) * Addresses are offsets from device's PCI hardware base address. */ #define IWM_FH_MEM_LOWER_BOUND (0x1000) #define IWM_FH_MEM_UPPER_BOUND (0x2000) /** * Keep-Warm (KW) buffer base address. * * Driver must allocate a 4KByte buffer that is for keeping the * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency * DRAM access when doing Txing or Rxing. The dummy accesses prevent host * from going into a power-savings mode that would cause higher DRAM latency, * and possible data over/under-runs, before all Tx/Rx is complete. * * Driver loads IWM_FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) * of the buffer, which must be 4K aligned. Once this is set up, the device * automatically invokes keep-warm accesses when normal accesses might not * be sufficient to maintain fast DRAM response. * * Bit fields: * 31-0: Keep-warm buffer physical base address [35:4], must be 4K aligned */ #define IWM_FH_KW_MEM_ADDR_REG (IWM_FH_MEM_LOWER_BOUND + 0x97C) /** * TFD Circular Buffers Base (CBBC) addresses * * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) * (see struct iwm_tfd_frame). These 16 pointer registers are offset by 0x04 * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte * aligned (address bits 0-7 must be 0). * Later devices have 20 (5000 series) or 30 (higher) queues, but the registers * for them are in different places. * * Bit fields in each pointer register: * 27-0: TFD CB physical base address [35:8], must be 256-byte aligned */ #define IWM_FH_MEM_CBBC_0_15_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x9D0) #define IWM_FH_MEM_CBBC_0_15_UPPER_BOUN (IWM_FH_MEM_LOWER_BOUND + 0xA10) #define IWM_FH_MEM_CBBC_16_19_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xBF0) #define IWM_FH_MEM_CBBC_16_19_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xC00) #define IWM_FH_MEM_CBBC_20_31_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xB20) #define IWM_FH_MEM_CBBC_20_31_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xB80) /* Find TFD CB base pointer for given queue */ static inline unsigned int IWM_FH_MEM_CBBC_QUEUE(unsigned int chnl) { if (chnl < 16) return IWM_FH_MEM_CBBC_0_15_LOWER_BOUND + 4 * chnl; if (chnl < 20) return IWM_FH_MEM_CBBC_16_19_LOWER_BOUND + 4 * (chnl - 16); return IWM_FH_MEM_CBBC_20_31_LOWER_BOUND + 4 * (chnl - 20); } /** * Rx SRAM Control and Status Registers (RSCSR) * * These registers provide handshake between driver and device for the Rx queue * (this queue handles *all* command responses, notifications, Rx data, etc. * sent from uCode to host driver). Unlike Tx, there is only one Rx * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 * mapping between RBDs and RBs. * * Driver must allocate host DRAM memory for the following, and set the * physical address of each into device registers: * * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 * entries (although any power of 2, up to 4096, is selectable by driver). * Each entry (1 dword) points to a receive buffer (RB) of consistent size * (typically 4K, although 8K or 16K are also selectable by driver). * Driver sets up RB size and number of RBDs in the CB via Rx config * register IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG. * * Bit fields within one RBD: * 27-0: Receive Buffer physical address bits [35:8], 256-byte aligned * * Driver sets physical address [35:8] of base of RBD circular buffer * into IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. * * 2) Rx status buffer, 8 bytes, in which uCode indicates which Rx Buffers * (RBs) have been filled, via a "write pointer", actually the index of * the RB's corresponding RBD within the circular buffer. Driver sets * physical address [35:4] into IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. * * Bit fields in lower dword of Rx status buffer (upper dword not used * by driver: * 31-12: Not used by driver * 11- 0: Index of last filled Rx buffer descriptor * (device writes, driver reads this value) * * As the driver prepares Receive Buffers (RBs) for device to fill, driver must * enter pointers to these RBs into contiguous RBD circular buffer entries, * and update the device's "write" index register, * IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG. * * This "write" index corresponds to the *next* RBD that the driver will make * available, i.e. one RBD past the tail of the ready-to-fill RBDs within * the circular buffer. This value should initially be 0 (before preparing any * RBs), should be 8 after preparing the first 8 RBs (for example), and must * wrap back to 0 at the end of the circular buffer (but don't wrap before * "read" index has advanced past 1! See below). * NOTE: DEVICE EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. * * As the device fills RBs (referenced from contiguous RBDs within the circular * buffer), it updates the Rx status buffer in host DRAM, 2) described above, * to tell the driver the index of the latest filled RBD. The driver must * read this "read" index from DRAM after receiving an Rx interrupt from device * * The driver must also internally keep track of a third index, which is the * next RBD to process. When receiving an Rx interrupt, driver should process * all filled but unprocessed RBs up to, but not including, the RB * corresponding to the "read" index. For example, if "read" index becomes "1", * driver may process the RB pointed to by RBD 0. Depending on volume of * traffic, there may be many RBs to process. * * If read index == write index, device thinks there is no room to put new data. * Due to this, the maximum number of filled RBs is 255, instead of 256. To * be safe, make sure that there is a gap of at least 2 RBDs between "write" * and "read" indexes; that is, make sure that there are no more than 254 * buffers waiting to be filled. */ #define IWM_FH_MEM_RSCSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xBC0) #define IWM_FH_MEM_RSCSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xC00) #define IWM_FH_MEM_RSCSR_CHNL0 (IWM_FH_MEM_RSCSR_LOWER_BOUND) /** * Physical base address of 8-byte Rx Status buffer. * Bit fields: * 31-0: Rx status buffer physical base address [35:4], must 16-byte aligned. */ #define IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG (IWM_FH_MEM_RSCSR_CHNL0) /** * Physical base address of Rx Buffer Descriptor Circular Buffer. * Bit fields: * 27-0: RBD CD physical base address [35:8], must be 256-byte aligned. */ #define IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG (IWM_FH_MEM_RSCSR_CHNL0 + 0x004) /** * Rx write pointer (index, really!). * Bit fields: * 11-0: Index of driver's most recent prepared-to-be-filled RBD, + 1. * NOTE: For 256-entry circular buffer, use only bits [7:0]. */ #define IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG (IWM_FH_MEM_RSCSR_CHNL0 + 0x008) #define IWM_FH_RSCSR_CHNL0_WPTR (IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG) #define IWM_FW_RSCSR_CHNL0_RXDCB_RDPTR_REG (IWM_FH_MEM_RSCSR_CHNL0 + 0x00c) #define IWM_FH_RSCSR_CHNL0_RDPTR IWM_FW_RSCSR_CHNL0_RXDCB_RDPTR_REG /** * Rx Config/Status Registers (RCSR) * Rx Config Reg for channel 0 (only channel used) * * Driver must initialize IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for * normal operation (see bit fields). * * Clearing IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA. * Driver should poll IWM_FH_MEM_RSSR_RX_STATUS_REG for * IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing. * * Bit fields: * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame, * '10' operate normally * 29-24: reserved * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal), * min "5" for 32 RBDs, max "12" for 4096 RBDs. * 19-18: reserved * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K, * '10' 12K, '11' 16K. * 15-14: reserved * 13-12: IRQ destination; '00' none, '01' host driver (normal operation) * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec) * typical value 0x10 (about 1/2 msec) * 3- 0: reserved */ #define IWM_FH_MEM_RCSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xC00) #define IWM_FH_MEM_RCSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xCC0) #define IWM_FH_MEM_RCSR_CHNL0 (IWM_FH_MEM_RCSR_LOWER_BOUND) #define IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG (IWM_FH_MEM_RCSR_CHNL0) #define IWM_FH_MEM_RCSR_CHNL0_RBDCB_WPTR (IWM_FH_MEM_RCSR_CHNL0 + 0x8) #define IWM_FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ (IWM_FH_MEM_RCSR_CHNL0 + 0x10) #define IWM_FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK (0x00001000) /* bits 12 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK (0x00008000) /* bit 15 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MSK (0x00030000) /* bits 16-17 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MSK (0x00F00000) /* bits 20-23 */ #define IWM_FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MSK (0xC0000000) /* bits 30-31*/ #define IWM_FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS (20) #define IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS (4) #define IWM_RX_RB_TIMEOUT (0x11) #define IWM_FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) #define IWM_FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) #define IWM_FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) #define IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) #define IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K (0x00010000) #define IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000) #define IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000) #define IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY (0x00000004) #define IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) #define IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) /** * Rx Shared Status Registers (RSSR) * * After stopping Rx DMA channel (writing 0 to * IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG), driver must poll * IWM_FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle. * * Bit fields: * 24: 1 = Channel 0 is idle * * IWM_FH_MEM_RSSR_SHARED_CTRL_REG and IWM_FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV * contain default values that should not be altered by the driver. */ #define IWM_FH_MEM_RSSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xC40) #define IWM_FH_MEM_RSSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xD00) #define IWM_FH_MEM_RSSR_SHARED_CTRL_REG (IWM_FH_MEM_RSSR_LOWER_BOUND) #define IWM_FH_MEM_RSSR_RX_STATUS_REG (IWM_FH_MEM_RSSR_LOWER_BOUND + 0x004) #define IWM_FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV\ (IWM_FH_MEM_RSSR_LOWER_BOUND + 0x008) #define IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) #define IWM_FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 /* TFDB Area - TFDs buffer table */ #define IWM_FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) #define IWM_FH_TFDIB_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x900) #define IWM_FH_TFDIB_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x958) #define IWM_FH_TFDIB_CTRL0_REG(_chnl) (IWM_FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) #define IWM_FH_TFDIB_CTRL1_REG(_chnl) (IWM_FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) /** * Transmit DMA Channel Control/Status Registers (TCSR) * * Device has one configuration register for each of 8 Tx DMA/FIFO channels * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. * * To use a Tx DMA channel, driver must initialize its * IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with: * * IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | * IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL * * All other bits should be 0. * * Bit fields: * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame, * '10' operate normally * 29- 4: Reserved, set to "0" * 3: Enable internal DMA requests (1, normal operation), disable (0) * 2- 0: Reserved, set to "0" */ #define IWM_FH_TCSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xD00) #define IWM_FH_TCSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xE60) /* Find Control/Status reg for given Tx DMA/FIFO channel */ #define IWM_FH_TCSR_CHNL_NUM (8) /* TCSR: tx_config register values */ #define IWM_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ (IWM_FH_TCSR_LOWER_BOUND + 0x20 * (_chnl)) #define IWM_FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ (IWM_FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ (IWM_FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV (0x00000001) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE (0x00000008) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) #define IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) #define IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) /** * Tx Shared Status Registers (TSSR) * * After stopping Tx DMA channel (writing 0 to * IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll * IWM_FH_TSSR_TX_STATUS_REG until selected Tx channel is idle * (channel's buffers empty | no pending requests). * * Bit fields: * 31-24: 1 = Channel buffers empty (channel 7:0) * 23-16: 1 = No pending requests (channel 7:0) */ #define IWM_FH_TSSR_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xEA0) #define IWM_FH_TSSR_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0xEC0) #define IWM_FH_TSSR_TX_STATUS_REG (IWM_FH_TSSR_LOWER_BOUND + 0x010) /** * Bit fields for TSSR(Tx Shared Status & Control) error status register: * 31: Indicates an address error when accessed to internal memory * uCode/driver must write "1" in order to clear this flag * 30: Indicates that Host did not send the expected number of dwords to FH * uCode/driver must write "1" in order to clear this flag * 16-9:Each status bit is for one channel. Indicates that an (Error) ActDMA * command was received from the scheduler while the TRB was already full * with previous command * uCode/driver must write "1" in order to clear this flag * 7-0: Each status bit indicates a channel's TxCredit error. When an error * bit is set, it indicates that the FH has received a full indication * from the RTC TxFIFO and the current value of the TxCredit counter was * not equal to zero. This mean that the credit mechanism was not * synchronized to the TxFIFO status * uCode/driver must write "1" in order to clear this flag */ #define IWM_FH_TSSR_TX_ERROR_REG (IWM_FH_TSSR_LOWER_BOUND + 0x018) #define IWM_FH_TSSR_TX_MSG_CONFIG_REG (IWM_FH_TSSR_LOWER_BOUND + 0x008) #define IWM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) ((1 << (_chnl)) << 16) /* Tx service channels */ #define IWM_FH_SRVC_CHNL (9) #define IWM_FH_SRVC_LOWER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x9C8) #define IWM_FH_SRVC_UPPER_BOUND (IWM_FH_MEM_LOWER_BOUND + 0x9D0) #define IWM_FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ (IWM_FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4) #define IWM_FH_TX_CHICKEN_BITS_REG (IWM_FH_MEM_LOWER_BOUND + 0xE98) #define IWM_FH_TX_TRB_REG(_chan) (IWM_FH_MEM_LOWER_BOUND + 0x958 + \ (_chan) * 4) /* Instruct FH to increment the retry count of a packet when * it is brought from the memory to TX-FIFO */ #define IWM_FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002) #define IWM_RX_QUEUE_SIZE 256 #define IWM_RX_QUEUE_MASK 255 #define IWM_RX_QUEUE_SIZE_LOG 8 /* * RX related structures and functions */ #define IWM_RX_FREE_BUFFERS 64 #define IWM_RX_LOW_WATERMARK 8 /** * struct iwm_rb_status - reseve buffer status * host memory mapped FH registers * @closed_rb_num [0:11] - Indicates the index of the RB which was closed * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed * @finished_rb_num [0:11] - Indicates the index of the current RB * in which the last frame was written to * @finished_fr_num [0:11] - Indicates the index of the RX Frame * which was transferred */ struct iwm_rb_status { uint16_t closed_rb_num; uint16_t closed_fr_num; uint16_t finished_rb_num; uint16_t finished_fr_nam; uint32_t unused; } __packed; #define IWM_TFD_QUEUE_SIZE_MAX (256) #define IWM_TFD_QUEUE_SIZE_BC_DUP (64) #define IWM_TFD_QUEUE_BC_SIZE (IWM_TFD_QUEUE_SIZE_MAX + \ IWM_TFD_QUEUE_SIZE_BC_DUP) #define IWM_TX_DMA_MASK DMA_BIT_MASK(36) #define IWM_NUM_OF_TBS 20 static inline uint8_t iwm_get_dma_hi_addr(bus_addr_t addr) { return (sizeof(addr) > sizeof(uint32_t) ? (addr >> 16) >> 16 : 0) & 0xF; } /** * struct iwm_tfd_tb transmit buffer descriptor within transmit frame descriptor * * This structure contains dma address and length of transmission address * * @lo: low [31:0] portion of the dma address of TX buffer * every even is unaligned on 16 bit boundary * @hi_n_len 0-3 [35:32] portion of dma * 4-15 length of the tx buffer */ struct iwm_tfd_tb { uint32_t lo; uint16_t hi_n_len; } __packed; /** * struct iwm_tfd * * Transmit Frame Descriptor (TFD) * * @ __reserved1[3] reserved * @ num_tbs 0-4 number of active tbs * 5 reserved * 6-7 padding (not used) * @ tbs[20] transmit frame buffer descriptors * @ __pad padding * * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. * Both driver and device share these circular buffers, each of which must be * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes * * Driver must indicate the physical address of the base of each * circular buffer via the IWM_FH_MEM_CBBC_QUEUE registers. * * Each TFD contains pointer/size information for up to 20 data buffers * in host DRAM. These buffers collectively contain the (one) frame described * by the TFD. Each buffer must be a single contiguous block of memory within * itself, but buffers may be scattered in host DRAM. Each buffer has max size * of (4K - 4). The concatenates all of a TFD's buffers into a single * Tx frame, up to 8 KBytes in size. * * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. */ struct iwm_tfd { uint8_t __reserved1[3]; uint8_t num_tbs; struct iwm_tfd_tb tbs[IWM_NUM_OF_TBS]; uint32_t __pad; } __packed; /* Keep Warm Size */ #define IWM_KW_SIZE 0x1000 /* 4k */ /* Fixed (non-configurable) rx data from phy */ /** * struct iwm_agn_schedq_bc_tbl scheduler byte count table * base physical address provided by IWM_SCD_DRAM_BASE_ADDR * @tfd_offset 0-12 - tx command byte count * 12-16 - station index */ struct iwm_agn_scd_bc_tbl { uint16_t tfd_offset[IWM_TFD_QUEUE_BC_SIZE]; } __packed; /* Maximum number of Tx queues. */ #define IWM_MAX_QUEUES 31 /** * DQA - Dynamic Queue Allocation -introduction * * Dynamic Queue Allocation (AKA "DQA") is a feature implemented in iwlwifi * to allow dynamic allocation of queues on-demand, rather than allocate them * statically ahead of time. Ideally, we would like to allocate one queue * per RA/TID, thus allowing an AP - for example - to send BE traffic to STA2 * even if it also needs to send traffic to a sleeping STA1, without being * blocked by the sleeping station. * * Although the queues in DQA mode are dynamically allocated, there are still * some queues that are statically allocated: * TXQ #0 - command queue * TXQ #1 - aux frames * TXQ #2 - P2P device frames * TXQ #3 - P2P GO/SoftAP GCAST/BCAST frames * TXQ #4 - BSS DATA frames queue * TXQ #5-8 - non-QoS data, QoS no-data, and MGMT frames queue pool * TXQ #9 - P2P GO/SoftAP probe responses * TXQ #10-31 - QoS DATA frames queue pool (for Tx aggregation) */ /* static DQA Tx queue numbers */ #define IWM_DQA_CMD_QUEUE 0 #define IWM_DQA_AUX_QUEUE 1 #define IWM_DQA_P2P_DEVICE_QUEUE 2 #define IWM_DQA_INJECT_MONITOR_QUEUE 2 #define IWM_DQA_GCAST_QUEUE 3 #define IWM_DQA_BSS_CLIENT_QUEUE 4 #define IWM_DQA_MIN_MGMT_QUEUE 5 #define IWM_DQA_MAX_MGMT_QUEUE 8 #define IWM_DQA_AP_PROBE_RESP_QUEUE 9 #define IWM_DQA_MIN_DATA_QUEUE 10 #define IWM_DQA_MAX_DATA_QUEUE 31 /* Reserve 8 DQA Tx queues, from 10 up to 17, for A-MPDU aggregation. */ #define IWM_MAX_TID_COUNT 8 #define IWM_FIRST_AGG_TX_QUEUE IWM_DQA_MIN_DATA_QUEUE #define IWM_LAST_AGG_TX_QUEUE (IWM_FIRST_AGG_TX_QUEUE + IWM_MAX_TID_COUNT - 1) /* legacy non-DQA queues; the legacy command queue uses a different number! */ #define IWM_OFFCHANNEL_QUEUE 8 #define IWM_CMD_QUEUE 9 #define IWM_AUX_QUEUE 15 #define IWM_TX_FIFO_BK 0 #define IWM_TX_FIFO_BE 1 #define IWM_TX_FIFO_VI 2 #define IWM_TX_FIFO_VO 3 #define IWM_TX_FIFO_MCAST 5 #define IWM_TX_FIFO_CMD 7 #define IWM_STATION_COUNT 16 /* * Commands */ #define IWM_ALIVE 0x1 #define IWM_REPLY_ERROR 0x2 #define IWM_INIT_COMPLETE_NOTIF 0x4 /* PHY context commands */ #define IWM_PHY_CONTEXT_CMD 0x8 #define IWM_DBG_CFG 0x9 /* UMAC scan commands */ #define IWM_SCAN_ITERATION_COMPLETE_UMAC 0xb5 #define IWM_SCAN_CFG_CMD 0xc #define IWM_SCAN_REQ_UMAC 0xd #define IWM_SCAN_ABORT_UMAC 0xe #define IWM_SCAN_COMPLETE_UMAC 0xf /* station table */ #define IWM_ADD_STA_KEY 0x17 #define IWM_ADD_STA 0x18 #define IWM_REMOVE_STA 0x19 /* TX */ #define IWM_TX_CMD 0x1c #define IWM_TXPATH_FLUSH 0x1e #define IWM_MGMT_MCAST_KEY 0x1f /* scheduler config */ #define IWM_SCD_QUEUE_CFG 0x1d /* Available options for the SCD_QUEUE_CFG HCMD */ #define IWM_SCD_CFG_DISABLE_QUEUE 0 #define IWM_SCD_CFG_ENABLE_QUEUE 1 #define IWM_SCD_CFG_UPDATE_QUEUE_TID 2 /* global key */ #define IWM_WEP_KEY 0x20 /* MAC and Binding commands */ #define IWM_MAC_CONTEXT_CMD 0x28 #define IWM_TIME_EVENT_CMD 0x29 /* both CMD and response */ #define IWM_TIME_EVENT_NOTIFICATION 0x2a #define IWM_BINDING_CONTEXT_CMD 0x2b #define IWM_TIME_QUOTA_CMD 0x2c #define IWM_NON_QOS_TX_COUNTER_CMD 0x2d #define IWM_LQ_CMD 0x4e /* Calibration */ #define IWM_TEMPERATURE_NOTIFICATION 0x62 #define IWM_CALIBRATION_CFG_CMD 0x65 #define IWM_CALIBRATION_RES_NOTIFICATION 0x66 #define IWM_CALIBRATION_COMPLETE_NOTIFICATION 0x67 #define IWM_RADIO_VERSION_NOTIFICATION 0x68 /* paging block to FW cpu2 */ #define IWM_FW_PAGING_BLOCK_CMD 0x4f /* Scan offload */ #define IWM_SCAN_OFFLOAD_REQUEST_CMD 0x51 #define IWM_SCAN_OFFLOAD_ABORT_CMD 0x52 #define IWM_HOT_SPOT_CMD 0x53 #define IWM_SCAN_OFFLOAD_COMPLETE 0x6d #define IWM_SCAN_OFFLOAD_UPDATE_PROFILES_CMD 0x6e #define IWM_SCAN_OFFLOAD_CONFIG_CMD 0x6f #define IWM_MATCH_FOUND_NOTIFICATION 0xd9 #define IWM_SCAN_ITERATION_COMPLETE 0xe7 /* Phy */ #define IWM_PHY_CONFIGURATION_CMD 0x6a #define IWM_CALIB_RES_NOTIF_PHY_DB 0x6b #define IWM_PHY_DB_CMD 0x6c /* Power - legacy power table command */ #define IWM_POWER_TABLE_CMD 0x77 #define IWM_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION 0x78 #define IWM_LTR_CONFIG 0xee /* Thermal Throttling*/ #define IWM_REPLY_THERMAL_MNG_BACKOFF 0x7e /* NVM */ #define IWM_NVM_ACCESS_CMD 0x88 #define IWM_SET_CALIB_DEFAULT_CMD 0x8e #define IWM_BEACON_NOTIFICATION 0x90 #define IWM_BEACON_TEMPLATE_CMD 0x91 #define IWM_TX_ANT_CONFIGURATION_CMD 0x98 #define IWM_BT_CONFIG 0x9b #define IWM_STATISTICS_NOTIFICATION 0x9d #define IWM_REDUCE_TX_POWER_CMD 0x9f /* RF-KILL commands and notifications */ #define IWM_CARD_STATE_CMD 0xa0 #define IWM_CARD_STATE_NOTIFICATION 0xa1 #define IWM_MISSED_BEACONS_NOTIFICATION 0xa2 #define IWM_MFUART_LOAD_NOTIFICATION 0xb1 /* Power - new power table command */ #define IWM_MAC_PM_POWER_TABLE 0xa9 #define IWM_REPLY_RX_PHY_CMD 0xc0 #define IWM_REPLY_RX_MPDU_CMD 0xc1 #define IWM_BA_NOTIF 0xc5 /* Location Aware Regulatory */ #define IWM_MCC_UPDATE_CMD 0xc8 #define IWM_MCC_CHUB_UPDATE_CMD 0xc9 /* BT Coex */ #define IWM_BT_COEX_PRIO_TABLE 0xcc #define IWM_BT_COEX_PROT_ENV 0xcd #define IWM_BT_PROFILE_NOTIFICATION 0xce #define IWM_BT_COEX_CI 0x5d #define IWM_REPLY_SF_CFG_CMD 0xd1 #define IWM_REPLY_BEACON_FILTERING_CMD 0xd2 /* DTS measurements */ #define IWM_CMD_DTS_MEASUREMENT_TRIGGER 0xdc #define IWM_DTS_MEASUREMENT_NOTIFICATION 0xdd #define IWM_REPLY_DEBUG_CMD 0xf0 #define IWM_DEBUG_LOG_MSG 0xf7 #define IWM_MCAST_FILTER_CMD 0xd0 /* D3 commands/notifications */ #define IWM_D3_CONFIG_CMD 0xd3 #define IWM_PROT_OFFLOAD_CONFIG_CMD 0xd4 #define IWM_OFFLOADS_QUERY_CMD 0xd5 #define IWM_REMOTE_WAKE_CONFIG_CMD 0xd6 /* for WoWLAN in particular */ #define IWM_WOWLAN_PATTERNS 0xe0 #define IWM_WOWLAN_CONFIGURATION 0xe1 #define IWM_WOWLAN_TSC_RSC_PARAM 0xe2 #define IWM_WOWLAN_TKIP_PARAM 0xe3 #define IWM_WOWLAN_KEK_KCK_MATERIAL 0xe4 #define IWM_WOWLAN_GET_STATUSES 0xe5 #define IWM_WOWLAN_TX_POWER_PER_DB 0xe6 /* and for NetDetect */ #define IWM_NET_DETECT_CONFIG_CMD 0x54 #define IWM_NET_DETECT_PROFILES_QUERY_CMD 0x56 #define IWM_NET_DETECT_PROFILES_CMD 0x57 #define IWM_NET_DETECT_HOTSPOTS_CMD 0x58 #define IWM_NET_DETECT_HOTSPOTS_QUERY_CMD 0x59 /* system group command IDs */ #define IWM_FSEQ_VER_MISMATCH_NOTIFICATION 0xff #define IWM_REPLY_MAX 0xff /* PHY_OPS subcommand IDs */ #define IWM_CMD_DTS_MEASUREMENT_TRIGGER_WIDE 0x0 #define IWM_CTDP_CONFIG_CMD 0x03 #define IWM_TEMP_REPORTING_THRESHOLDS_CMD 0x04 #define IWM_CT_KILL_NOTIFICATION 0xFE #define IWM_DTS_MEASUREMENT_NOTIF_WIDE 0xFF /* command groups */ #define IWM_LEGACY_GROUP 0x0 #define IWM_LONG_GROUP 0x1 #define IWM_SYSTEM_GROUP 0x2 #define IWM_MAC_CONF_GROUP 0x3 #define IWM_PHY_OPS_GROUP 0x4 #define IWM_DATA_PATH_GROUP 0x5 #define IWM_PROT_OFFLOAD_GROUP 0xb /* SYSTEM_GROUP group subcommand IDs */ #define IWM_SHARED_MEM_CFG_CMD 0x00 #define IWM_SOC_CONFIGURATION_CMD 0x01 #define IWM_INIT_EXTENDED_CFG_CMD 0x03 #define IWM_FW_ERROR_RECOVERY_CMD 0x07 /* DATA_PATH group subcommand IDs */ #define IWM_DQA_ENABLE_CMD 0x00 /* * struct iwm_dqa_enable_cmd * @cmd_queue: the TXQ number of the command queue */ struct iwm_dqa_enable_cmd { uint32_t cmd_queue; } __packed; /* DQA_CONTROL_CMD_API_S_VER_1 */ /** * struct iwm_cmd_response - generic response struct for most commands * @status: status of the command asked, changes for each one */ struct iwm_cmd_response { uint32_t status; }; /* * struct iwm_tx_ant_cfg_cmd * @valid: valid antenna configuration */ struct iwm_tx_ant_cfg_cmd { uint32_t valid; } __packed; /** * struct iwm_reduce_tx_power_cmd - TX power reduction command * IWM_REDUCE_TX_POWER_CMD = 0x9f * @flags: (reserved for future implementation) * @mac_context_id: id of the mac ctx for which we are reducing TX power. * @pwr_restriction: TX power restriction in dBms. */ struct iwm_reduce_tx_power_cmd { uint8_t flags; uint8_t mac_context_id; uint16_t pwr_restriction; } __packed; /* IWM_TX_REDUCED_POWER_API_S_VER_1 */ /* * Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to * flow triggers. * @event_trigger: bitmap for which calibrations to perform according to * event triggers. */ struct iwm_calib_ctrl { uint32_t flow_trigger; uint32_t event_trigger; } __packed; /* This defines the bitmap of various calibrations to enable in both * init ucode and runtime ucode through IWM_CALIBRATION_CFG_CMD. */ #define IWM_CALIB_CFG_XTAL_IDX (1 << 0) #define IWM_CALIB_CFG_TEMPERATURE_IDX (1 << 1) #define IWM_CALIB_CFG_VOLTAGE_READ_IDX (1 << 2) #define IWM_CALIB_CFG_PAPD_IDX (1 << 3) #define IWM_CALIB_CFG_TX_PWR_IDX (1 << 4) #define IWM_CALIB_CFG_DC_IDX (1 << 5) #define IWM_CALIB_CFG_BB_FILTER_IDX (1 << 6) #define IWM_CALIB_CFG_LO_LEAKAGE_IDX (1 << 7) #define IWM_CALIB_CFG_TX_IQ_IDX (1 << 8) #define IWM_CALIB_CFG_TX_IQ_SKEW_IDX (1 << 9) #define IWM_CALIB_CFG_RX_IQ_IDX (1 << 10) #define IWM_CALIB_CFG_RX_IQ_SKEW_IDX (1 << 11) #define IWM_CALIB_CFG_SENSITIVITY_IDX (1 << 12) #define IWM_CALIB_CFG_CHAIN_NOISE_IDX (1 << 13) #define IWM_CALIB_CFG_DISCONNECTED_ANT_IDX (1 << 14) #define IWM_CALIB_CFG_ANT_COUPLING_IDX (1 << 15) #define IWM_CALIB_CFG_DAC_IDX (1 << 16) #define IWM_CALIB_CFG_ABS_IDX (1 << 17) #define IWM_CALIB_CFG_AGC_IDX (1 << 18) /* * Phy configuration command. */ struct iwm_phy_cfg_cmd { uint32_t phy_cfg; struct iwm_calib_ctrl calib_control; } __packed; #define IWM_PHY_CFG_RADIO_TYPE ((1 << 0) | (1 << 1)) #define IWM_PHY_CFG_RADIO_STEP ((1 << 2) | (1 << 3)) #define IWM_PHY_CFG_RADIO_DASH ((1 << 4) | (1 << 5)) #define IWM_PHY_CFG_PRODUCT_NUMBER ((1 << 6) | (1 << 7)) #define IWM_PHY_CFG_TX_CHAIN_A (1 << 8) #define IWM_PHY_CFG_TX_CHAIN_B (1 << 9) #define IWM_PHY_CFG_TX_CHAIN_C (1 << 10) #define IWM_PHY_CFG_RX_CHAIN_A (1 << 12) #define IWM_PHY_CFG_RX_CHAIN_B (1 << 13) #define IWM_PHY_CFG_RX_CHAIN_C (1 << 14) #define IWM_MAX_DTS_TRIPS 8 /** * struct iwm_ct_kill_notif - CT-kill entry notification * * @temperature: the current temperature in celsius * @reserved: reserved */ struct iwm_ct_kill_notif { uint16_t temperature; uint16_t reserved; } __packed; /* GRP_PHY_CT_KILL_NTF */ /** * struct iwm_temp_report_ths_cmd - set temperature thresholds * (IWM_TEMP_REPORTING_THRESHOLDS_CMD) * * @num_temps: number of temperature thresholds passed * @thresholds: array with the thresholds to be configured */ struct iwm_temp_report_ths_cmd { uint32_t num_temps; uint16_t thresholds[IWM_MAX_DTS_TRIPS]; } __packed; /* GRP_PHY_TEMP_REPORTING_THRESHOLDS_CMD */ /* * PHY db */ #define IWM_PHY_DB_CFG 1 #define IWM_PHY_DB_CALIB_NCH 2 #define IWM_PHY_DB_UNUSED 3 #define IWM_PHY_DB_CALIB_CHG_PAPD 4 #define IWM_PHY_DB_CALIB_CHG_TXP 5 #define IWM_PHY_DB_MAX 6 /* * phy db - configure operational ucode */ struct iwm_phy_db_cmd { uint16_t type; uint16_t length; uint8_t data[]; } __packed; /* for parsing of tx power channel group data that comes from the firmware*/ struct iwm_phy_db_chg_txp { uint32_t space; uint16_t max_channel_idx; } __packed; /* * phy db - Receive phy db chunk after calibrations */ struct iwm_calib_res_notif_phy_db { uint16_t type; uint16_t length; uint8_t data[]; } __packed; /* 7k family NVM HW-Section offset (in words) definitions */ #define IWM_HW_ADDR 0x15 /* 7k family NVM SW-Section offset (in words) definitions */ #define IWM_NVM_SW_SECTION 0x1C0 #define IWM_NVM_VERSION 0 #define IWM_RADIO_CFG 1 #define IWM_SKU 2 #define IWM_N_HW_ADDRS 3 #define IWM_NVM_CHANNELS 0x1E0 - IWM_NVM_SW_SECTION /* 7k family NVM calibration section offset (in words) definitions */ #define IWM_NVM_CALIB_SECTION 0x2B8 #define IWM_XTAL_CALIB (0x316 - IWM_NVM_CALIB_SECTION) /* 8k family NVM HW-Section offset (in words) definitions */ #define IWM_HW_ADDR0_WFPM_8000 0x12 #define IWM_HW_ADDR1_WFPM_8000 0x16 #define IWM_HW_ADDR0_PCIE_8000 0x8A #define IWM_HW_ADDR1_PCIE_8000 0x8E #define IWM_MAC_ADDRESS_OVERRIDE_8000 1 /* 8k family NVM SW-Section offset (in words) definitions */ #define IWM_NVM_SW_SECTION_8000 0x1C0 #define IWM_NVM_VERSION_8000 0 #define IWM_RADIO_CFG_8000 0 #define IWM_SKU_8000 2 #define IWM_N_HW_ADDRS_8000 3 /* 8k family NVM REGULATORY -Section offset (in words) definitions */ #define IWM_NVM_CHANNELS_8000 0 #define IWM_NVM_LAR_OFFSET_8000_OLD 0x4C7 #define IWM_NVM_LAR_OFFSET_8000 0x507 #define IWM_NVM_LAR_ENABLED_8000 0x7 /* 8k family NVM calibration section offset (in words) definitions */ #define IWM_NVM_CALIB_SECTION_8000 0x2B8 #define IWM_XTAL_CALIB_8000 (0x316 - IWM_NVM_CALIB_SECTION_8000) /* SKU Capabilities (actual values from NVM definition) */ #define IWM_NVM_SKU_CAP_BAND_24GHZ (1 << 0) #define IWM_NVM_SKU_CAP_BAND_52GHZ (1 << 1) #define IWM_NVM_SKU_CAP_11N_ENABLE (1 << 2) #define IWM_NVM_SKU_CAP_11AC_ENABLE (1 << 3) #define IWM_NVM_SKU_CAP_MIMO_DISABLE (1 << 5) /* radio config bits (actual values from NVM definition) */ #define IWM_NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ #define IWM_NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ #define IWM_NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ #define IWM_NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ #define IWM_NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ #define IWM_NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ #define IWM_NVM_RF_CFG_PNUM_MSK_8000(x) (x & 0xF) #define IWM_NVM_RF_CFG_DASH_MSK_8000(x) ((x >> 4) & 0xF) #define IWM_NVM_RF_CFG_STEP_MSK_8000(x) ((x >> 8) & 0xF) #define IWM_NVM_RF_CFG_TYPE_MSK_8000(x) ((x >> 12) & 0xFFF) #define IWM_NVM_RF_CFG_TX_ANT_MSK_8000(x) ((x >> 24) & 0xF) #define IWM_NVM_RF_CFG_RX_ANT_MSK_8000(x) ((x >> 28) & 0xF) /* * channel flags in NVM * @IWM_NVM_CHANNEL_VALID: channel is usable for this SKU/geo * @IWM_NVM_CHANNEL_IBSS: usable as an IBSS channel * @IWM_NVM_CHANNEL_ACTIVE: active scanning allowed * @IWM_NVM_CHANNEL_RADAR: radar detection required * @IWM_NVM_CHANNEL_DFS: dynamic freq selection candidate * @IWM_NVM_CHANNEL_WIDE: 20 MHz channel okay (?) * @IWM_NVM_CHANNEL_40MHZ: 40 MHz channel okay (?) * @IWM_NVM_CHANNEL_80MHZ: 80 MHz channel okay (?) * @IWM_NVM_CHANNEL_160MHZ: 160 MHz channel okay (?) */ #define IWM_NVM_CHANNEL_VALID (1 << 0) #define IWM_NVM_CHANNEL_IBSS (1 << 1) #define IWM_NVM_CHANNEL_ACTIVE (1 << 3) #define IWM_NVM_CHANNEL_RADAR (1 << 4) #define IWM_NVM_CHANNEL_DFS (1 << 7) #define IWM_NVM_CHANNEL_WIDE (1 << 8) #define IWM_NVM_CHANNEL_40MHZ (1 << 9) #define IWM_NVM_CHANNEL_80MHZ (1 << 10) #define IWM_NVM_CHANNEL_160MHZ (1 << 11) /* Target of the IWM_NVM_ACCESS_CMD */ #define IWM_NVM_ACCESS_TARGET_CACHE 0 #define IWM_NVM_ACCESS_TARGET_OTP 1 #define IWM_NVM_ACCESS_TARGET_EEPROM 2 /* Section types for IWM_NVM_ACCESS_CMD */ #define IWM_NVM_SECTION_TYPE_HW 0 #define IWM_NVM_SECTION_TYPE_SW 1 #define IWM_NVM_SECTION_TYPE_PAPD 2 #define IWM_NVM_SECTION_TYPE_REGULATORY 3 #define IWM_NVM_SECTION_TYPE_CALIBRATION 4 #define IWM_NVM_SECTION_TYPE_PRODUCTION 5 #define IWM_NVM_SECTION_TYPE_POST_FCS_CALIB 6 /* 7 unknown */ #define IWM_NVM_SECTION_TYPE_REGULATORY_SDP 8 /* 9 unknown */ #define IWM_NVM_SECTION_TYPE_HW_8000 10 #define IWM_NVM_SECTION_TYPE_MAC_OVERRIDE 11 #define IWM_NVM_SECTION_TYPE_PHY_SKU 12 #define IWM_NVM_NUM_OF_SECTIONS 13 /** * enum iwm_nvm_type - nvm formats * @IWM_NVM: the regular format * @IWM_NVM_EXT: extended NVM format * @IWM_NVM_SDP: NVM format used by 3168 series */ enum iwm_nvm_type { IWM_NVM, IWM_NVM_EXT, IWM_NVM_SDP, }; /** * struct iwm_nvm_access_cmd_ver2 - Request the device to send an NVM section * @op_code: 0 - read, 1 - write * @target: IWM_NVM_ACCESS_TARGET_* * @type: IWM_NVM_SECTION_TYPE_* * @offset: offset in bytes into the section * @length: in bytes, to read/write * @data: if write operation, the data to write. On read its empty */ struct iwm_nvm_access_cmd { uint8_t op_code; uint8_t target; uint16_t type; uint16_t offset; uint16_t length; uint8_t data[]; } __packed; /* IWM_NVM_ACCESS_CMD_API_S_VER_2 */ /* * Block paging calculations */ #define IWM_PAGE_2_EXP_SIZE 12 /* 4K == 2^12 */ #define IWM_FW_PAGING_SIZE (1 << IWM_PAGE_2_EXP_SIZE) /* page size is 4KB */ #define IWM_PAGE_PER_GROUP_2_EXP_SIZE 3 /* 8 pages per group */ #define IWM_NUM_OF_PAGE_PER_GROUP (1 << IWM_PAGE_PER_GROUP_2_EXP_SIZE) /* don't change, support only 32KB size */ #define IWM_PAGING_BLOCK_SIZE (IWM_NUM_OF_PAGE_PER_GROUP * IWM_FW_PAGING_SIZE) /* 32K == 2^15 */ #define IWM_BLOCK_2_EXP_SIZE (IWM_PAGE_2_EXP_SIZE + IWM_PAGE_PER_GROUP_2_EXP_SIZE) /* * Image paging calculations */ #define IWM_BLOCK_PER_IMAGE_2_EXP_SIZE 5 /* 2^5 == 32 blocks per image */ #define IWM_NUM_OF_BLOCK_PER_IMAGE (1 << IWM_BLOCK_PER_IMAGE_2_EXP_SIZE) /* maximum image size 1024KB */ #define IWM_MAX_PAGING_IMAGE_SIZE (IWM_NUM_OF_BLOCK_PER_IMAGE * IWM_PAGING_BLOCK_SIZE) /* Virtual address signature */ #define IWM_PAGING_ADDR_SIG 0xAA000000 #define IWM_PAGING_CMD_IS_SECURED (1 << 9) #define IWM_PAGING_CMD_IS_ENABLED (1 << 8) #define IWM_PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS 0 #define IWM_PAGING_TLV_SECURE_MASK 1 #define IWM_NUM_OF_FW_PAGING_BLOCKS 33 /* 32 for data and 1 block for CSS */ /* * struct iwm_fw_paging_cmd - paging layout * * (IWM_FW_PAGING_BLOCK_CMD = 0x4f) * * Send to FW the paging layout in the driver. * * @flags: various flags for the command * @block_size: the block size in powers of 2 * @block_num: number of blocks specified in the command. * @device_phy_addr: virtual addresses from device side */ struct iwm_fw_paging_cmd { uint32_t flags; uint32_t block_size; uint32_t block_num; uint32_t device_phy_addr[IWM_NUM_OF_FW_PAGING_BLOCKS]; } __packed; /* IWM_FW_PAGING_BLOCK_CMD_API_S_VER_1 */ /** * struct iwm_nvm_access_resp_ver2 - response to IWM_NVM_ACCESS_CMD * @offset: offset in bytes into the section * @length: in bytes, either how much was written or read * @type: IWM_NVM_SECTION_TYPE_* * @status: 0 for success, fail otherwise * @data: if read operation, the data returned. Empty on write. */ struct iwm_nvm_access_resp { uint16_t offset; uint16_t length; uint16_t type; uint16_t status; uint8_t data[]; } __packed; /* IWM_NVM_ACCESS_CMD_RESP_API_S_VER_2 */ /* IWM_ALIVE 0x1 */ /* alive response is_valid values */ #define IWM_ALIVE_RESP_UCODE_OK (1 << 0) #define IWM_ALIVE_RESP_RFKILL (1 << 1) /* alive response ver_type values */ #define IWM_FW_TYPE_HW 0 #define IWM_FW_TYPE_PROT 1 #define IWM_FW_TYPE_AP 2 #define IWM_FW_TYPE_WOWLAN 3 #define IWM_FW_TYPE_TIMING 4 #define IWM_FW_TYPE_WIPAN 5 /* alive response ver_subtype values */ #define IWM_FW_SUBTYPE_FULL_FEATURE 0 #define IWM_FW_SUBTYPE_BOOTSRAP 1 /* Not valid */ #define IWM_FW_SUBTYPE_REDUCED 2 #define IWM_FW_SUBTYPE_ALIVE_ONLY 3 #define IWM_FW_SUBTYPE_WOWLAN 4 #define IWM_FW_SUBTYPE_AP_SUBTYPE 5 #define IWM_FW_SUBTYPE_WIPAN 6 #define IWM_FW_SUBTYPE_INITIALIZE 9 #define IWM_ALIVE_STATUS_ERR 0xDEAD #define IWM_ALIVE_STATUS_OK 0xCAFE #define IWM_ALIVE_FLG_RFKILL (1 << 0) struct iwm_alive_resp_v1 { uint16_t status; uint16_t flags; uint8_t ucode_minor; uint8_t ucode_major; uint16_t id; uint8_t api_minor; uint8_t api_major; uint8_t ver_subtype; uint8_t ver_type; uint8_t mac; uint8_t opt; uint16_t reserved2; uint32_t timestamp; uint32_t error_event_table_ptr; /* SRAM address for error log */ uint32_t log_event_table_ptr; /* SRAM address for event log */ uint32_t cpu_register_ptr; uint32_t dbgm_config_ptr; uint32_t alive_counter_ptr; uint32_t scd_base_ptr; /* SRAM address for SCD */ } __packed; /* IWM_ALIVE_RES_API_S_VER_1 */ struct iwm_alive_resp_v2 { uint16_t status; uint16_t flags; uint8_t ucode_minor; uint8_t ucode_major; uint16_t id; uint8_t api_minor; uint8_t api_major; uint8_t ver_subtype; uint8_t ver_type; uint8_t mac; uint8_t opt; uint16_t reserved2; uint32_t timestamp; uint32_t error_event_table_ptr; /* SRAM address for error log */ uint32_t log_event_table_ptr; /* SRAM address for LMAC event log */ uint32_t cpu_register_ptr; uint32_t dbgm_config_ptr; uint32_t alive_counter_ptr; uint32_t scd_base_ptr; /* SRAM address for SCD */ uint32_t st_fwrd_addr; /* pointer to Store and forward */ uint32_t st_fwrd_size; uint8_t umac_minor; /* UMAC version: minor */ uint8_t umac_major; /* UMAC version: major */ uint16_t umac_id; /* UMAC version: id */ uint32_t error_info_addr; /* SRAM address for UMAC error log */ uint32_t dbg_print_buff_addr; } __packed; /* ALIVE_RES_API_S_VER_2 */ struct iwm_alive_resp_v3 { uint16_t status; uint16_t flags; uint32_t ucode_minor; uint32_t ucode_major; uint8_t ver_subtype; uint8_t ver_type; uint8_t mac; uint8_t opt; uint32_t timestamp; uint32_t error_event_table_ptr; /* SRAM address for error log */ uint32_t log_event_table_ptr; /* SRAM address for LMAC event log */ uint32_t cpu_register_ptr; uint32_t dbgm_config_ptr; uint32_t alive_counter_ptr; uint32_t scd_base_ptr; /* SRAM address for SCD */ uint32_t st_fwrd_addr; /* pointer to Store and forward */ uint32_t st_fwrd_size; uint32_t umac_minor; /* UMAC version: minor */ uint32_t umac_major; /* UMAC version: major */ uint32_t error_info_addr; /* SRAM address for UMAC error log */ uint32_t dbg_print_buff_addr; } __packed; /* ALIVE_RES_API_S_VER_3 */ #define IWM_SOC_CONFIG_CMD_FLAGS_DISCRETE (1 << 0) #define IWM_SOC_CONFIG_CMD_FLAGS_LOW_LATENCY (1 << 1) #define IWM_SOC_FLAGS_LTR_APPLY_DELAY_MASK 0xc #define IWM_SOC_FLAGS_LTR_APPLY_DELAY_NONE 0 #define IWM_SOC_FLAGS_LTR_APPLY_DELAY_200 1 #define IWM_SOC_FLAGS_LTR_APPLY_DELAY_2500 2 #define IWM_SOC_FLAGS_LTR_APPLY_DELAY_1820 3 /** * struct iwm_soc_configuration_cmd - Set device stabilization latency * * @flags: soc settings flags. In VER_1, we can only set the DISCRETE * flag, because the FW treats the whole value as an integer. In * VER_2, we can set the bits independently. * @latency: time for SOC to ensure stable power & XTAL */ struct iwm_soc_configuration_cmd { uint32_t flags; uint32_t latency; } __packed; /* * SOC_CONFIGURATION_CMD_S_VER_1 (see description above) * SOC_CONFIGURATION_CMD_S_VER_2 */ /* Error response/notification */ #define IWM_FW_ERR_UNKNOWN_CMD 0x0 #define IWM_FW_ERR_INVALID_CMD_PARAM 0x1 #define IWM_FW_ERR_SERVICE 0x2 #define IWM_FW_ERR_ARC_MEMORY 0x3 #define IWM_FW_ERR_ARC_CODE 0x4 #define IWM_FW_ERR_WATCH_DOG 0x5 #define IWM_FW_ERR_WEP_GRP_KEY_INDX 0x10 #define IWM_FW_ERR_WEP_KEY_SIZE 0x11 #define IWM_FW_ERR_OBSOLETE_FUNC 0x12 #define IWM_FW_ERR_UNEXPECTED 0xFE #define IWM_FW_ERR_FATAL 0xFF /** * struct iwm_error_resp - FW error indication * ( IWM_REPLY_ERROR = 0x2 ) * @error_type: one of IWM_FW_ERR_* * @cmd_id: the command ID for which the error occured * @bad_cmd_seq_num: sequence number of the erroneous command * @error_service: which service created the error, applicable only if * error_type = 2, otherwise 0 * @timestamp: TSF in usecs. */ struct iwm_error_resp { uint32_t error_type; uint8_t cmd_id; uint8_t reserved1; uint16_t bad_cmd_seq_num; uint32_t error_service; uint64_t timestamp; } __packed; #define IWM_FW_CMD_VER_UNKNOWN 99 /** * struct iwm_fw_cmd_version - firmware command version entry * @cmd: command ID * @group: group ID * @cmd_ver: command version * @notif_ver: notification version */ struct iwm_fw_cmd_version { uint8_t cmd; uint8_t group; uint8_t cmd_ver; uint8_t notif_ver; } __packed; /* Common PHY, MAC and Bindings definitions */ #define IWM_MAX_MACS_IN_BINDING (3) #define IWM_MAX_BINDINGS (4) #define IWM_AUX_BINDING_INDEX (3) #define IWM_MAX_PHYS (4) /* Used to extract ID and color from the context dword */ #define IWM_FW_CTXT_ID_POS (0) #define IWM_FW_CTXT_ID_MSK (0xff << IWM_FW_CTXT_ID_POS) #define IWM_FW_CTXT_COLOR_POS (8) #define IWM_FW_CTXT_COLOR_MSK (0xff << IWM_FW_CTXT_COLOR_POS) #define IWM_FW_CTXT_INVALID (0xffffffff) #define IWM_FW_CMD_ID_AND_COLOR(_id, _color) ((_id << IWM_FW_CTXT_ID_POS) |\ (_color << IWM_FW_CTXT_COLOR_POS)) /* Possible actions on PHYs, MACs and Bindings */ #define IWM_FW_CTXT_ACTION_STUB 0 #define IWM_FW_CTXT_ACTION_ADD 1 #define IWM_FW_CTXT_ACTION_MODIFY 2 #define IWM_FW_CTXT_ACTION_REMOVE 3 #define IWM_FW_CTXT_ACTION_NUM 4 /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ /* Time Events */ /* Time Event types, according to MAC type */ /* BSS Station Events */ #define IWM_TE_BSS_STA_AGGRESSIVE_ASSOC 0 #define IWM_TE_BSS_STA_ASSOC 1 #define IWM_TE_BSS_EAP_DHCP_PROT 2 #define IWM_TE_BSS_QUIET_PERIOD 3 /* P2P Device Events */ #define IWM_TE_P2P_DEVICE_DISCOVERABLE 4 #define IWM_TE_P2P_DEVICE_LISTEN 5 #define IWM_TE_P2P_DEVICE_ACTION_SCAN 6 #define IWM_TE_P2P_DEVICE_FULL_SCAN 7 /* P2P Client Events */ #define IWM_TE_P2P_CLIENT_AGGRESSIVE_ASSOC 8 #define IWM_TE_P2P_CLIENT_ASSOC 9 #define IWM_TE_P2P_CLIENT_QUIET_PERIOD 10 /* P2P GO Events */ #define IWM_TE_P2P_GO_ASSOC_PROT 11 #define IWM_TE_P2P_GO_REPETITIVE_NOA 12 #define IWM_TE_P2P_GO_CT_WINDOW 13 /* WiDi Sync Events */ #define IWM_TE_WIDI_TX_SYNC 14 #define IWM_TE_MAX 15 /* IWM_MAC_EVENT_TYPE_API_E_VER_1 */ /* Time event - defines for command API v1 */ /* * @IWM_TE_V1_FRAG_NONE: fragmentation of the time event is NOT allowed. * @IWM_TE_V1_FRAG_SINGLE: fragmentation of the time event is allowed, but only * the first fragment is scheduled. * @IWM_TE_V1_FRAG_DUAL: fragmentation of the time event is allowed, but only * the first 2 fragments are scheduled. * @IWM_TE_V1_FRAG_ENDLESS: fragmentation of the time event is allowed, and any * number of fragments are valid. * * Other than the constant defined above, specifying a fragmentation value 'x' * means that the event can be fragmented but only the first 'x' will be * scheduled. */ #define IWM_TE_V1_FRAG_NONE 0 #define IWM_TE_V1_FRAG_SINGLE 1 #define IWM_TE_V1_FRAG_DUAL 2 #define IWM_TE_V1_FRAG_ENDLESS 0xffffffff /* If a Time Event can be fragmented, this is the max number of fragments */ #define IWM_TE_V1_FRAG_MAX_MSK 0x0fffffff /* Repeat the time event endlessly (until removed) */ #define IWM_TE_V1_REPEAT_ENDLESS 0xffffffff /* If a Time Event has bounded repetitions, this is the maximal value */ #define IWM_TE_V1_REPEAT_MAX_MSK_V1 0x0fffffff /* Time Event dependencies: none, on another TE, or in a specific time */ #define IWM_TE_V1_INDEPENDENT 0 #define IWM_TE_V1_DEP_OTHER (1 << 0) #define IWM_TE_V1_DEP_TSF (1 << 1) #define IWM_TE_V1_EVENT_SOCIOPATHIC (1 << 2) /* IWM_MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ /* * @IWM_TE_V1_NOTIF_NONE: no notifications * @IWM_TE_V1_NOTIF_HOST_EVENT_START: request/receive notification on event start * @IWM_TE_V1_NOTIF_HOST_EVENT_END:request/receive notification on event end * @IWM_TE_V1_NOTIF_INTERNAL_EVENT_START: internal FW use * @IWM_TE_V1_NOTIF_INTERNAL_EVENT_END: internal FW use. * @IWM_TE_V1_NOTIF_HOST_FRAG_START: request/receive notification on frag start * @IWM_TE_V1_NOTIF_HOST_FRAG_END:request/receive notification on frag end * @IWM_TE_V1_NOTIF_INTERNAL_FRAG_START: internal FW use. * @IWM_TE_V1_NOTIF_INTERNAL_FRAG_END: internal FW use. * * Supported Time event notifications configuration. * A notification (both event and fragment) includes a status indicating weather * the FW was able to schedule the event or not. For fragment start/end * notification the status is always success. There is no start/end fragment * notification for monolithic events. */ #define IWM_TE_V1_NOTIF_NONE 0 #define IWM_TE_V1_NOTIF_HOST_EVENT_START (1 << 0) #define IWM_TE_V1_NOTIF_HOST_EVENT_END (1 << 1) #define IWM_TE_V1_NOTIF_INTERNAL_EVENT_START (1 << 2) #define IWM_TE_V1_NOTIF_INTERNAL_EVENT_END (1 << 3) #define IWM_TE_V1_NOTIF_HOST_FRAG_START (1 << 4) #define IWM_TE_V1_NOTIF_HOST_FRAG_END (1 << 5) #define IWM_TE_V1_NOTIF_INTERNAL_FRAG_START (1 << 6) #define IWM_TE_V1_NOTIF_INTERNAL_FRAG_END (1 << 7) /* IWM_MAC_EVENT_ACTION_API_E_VER_2 */ /* Time event - defines for command API */ /** * DOC: Time Events - what is it? * * Time Events are a fw feature that allows the driver to control the presence * of the device on the channel. Since the fw supports multiple channels * concurrently, the fw may choose to jump to another channel at any time. * In order to make sure that the fw is on a specific channel at a certain time * and for a certain duration, the driver needs to issue a time event. * * The simplest example is for BSS association. The driver issues a time event, * waits for it to start, and only then tells mac80211 that we can start the * association. This way, we make sure that the association will be done * smoothly and won't be interrupted by channel switch decided within the fw. */ /** * DOC: The flow against the fw * * When the driver needs to make sure we are in a certain channel, at a certain * time and for a certain duration, it sends a Time Event. The flow against the * fw goes like this: * 1) Driver sends a TIME_EVENT_CMD to the fw * 2) Driver gets the response for that command. This response contains the * Unique ID (UID) of the event. * 3) The fw sends notification when the event starts. * * Of course the API provides various options that allow to cover parameters * of the flow. * What is the duration of the event? * What is the start time of the event? * Is there an end-time for the event? * How much can the event be delayed? * Can the event be split? * If yes what is the maximal number of chunks? * etc... */ /* * @IWM_TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed. * @IWM_TE_V2_FRAG_SINGLE: fragmentation of the time event is allowed, but only * the first fragment is scheduled. * @IWM_TE_V2_FRAG_DUAL: fragmentation of the time event is allowed, but only * the first 2 fragments are scheduled. * @IWM_TE_V2_FRAG_ENDLESS: fragmentation of the time event is allowed, and any * number of fragments are valid. * * Other than the constant defined above, specifying a fragmentation value 'x' * means that the event can be fragmented but only the first 'x' will be * scheduled. */ #define IWM_TE_V2_FRAG_NONE 0 #define IWM_TE_V2_FRAG_SINGLE 1 #define IWM_TE_V2_FRAG_DUAL 2 #define IWM_TE_V2_FRAG_MAX 0xfe #define IWM_TE_V2_FRAG_ENDLESS 0xff /* Repeat the time event endlessly (until removed) */ #define IWM_TE_V2_REPEAT_ENDLESS 0xff /* If a Time Event has bounded repetitions, this is the maximal value */ #define IWM_TE_V2_REPEAT_MAX 0xfe #define IWM_TE_V2_PLACEMENT_POS 12 #define IWM_TE_V2_ABSENCE_POS 15 /* Time event policy values * A notification (both event and fragment) includes a status indicating weather * the FW was able to schedule the event or not. For fragment start/end * notification the status is always success. There is no start/end fragment * notification for monolithic events. * * @IWM_TE_V2_DEFAULT_POLICY: independent, social, present, unoticable * @IWM_TE_V2_NOTIF_HOST_EVENT_START: request/receive notification on event start * @IWM_TE_V2_NOTIF_HOST_EVENT_END:request/receive notification on event end * @IWM_TE_V2_NOTIF_INTERNAL_EVENT_START: internal FW use * @IWM_TE_V2_NOTIF_INTERNAL_EVENT_END: internal FW use. * @IWM_TE_V2_NOTIF_HOST_FRAG_START: request/receive notification on frag start * @IWM_TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end * @IWM_TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. * @IWM_TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. * @IWM_TE_V2_DEP_OTHER: depends on another time event * @IWM_TE_V2_DEP_TSF: depends on a specific time * @IWM_TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC * @IWM_TE_V2_ABSENCE: are we present or absent during the Time Event. */ #define IWM_TE_V2_DEFAULT_POLICY 0x0 /* notifications (event start/stop, fragment start/stop) */ #define IWM_TE_V2_NOTIF_HOST_EVENT_START (1 << 0) #define IWM_TE_V2_NOTIF_HOST_EVENT_END (1 << 1) #define IWM_TE_V2_NOTIF_INTERNAL_EVENT_START (1 << 2) #define IWM_TE_V2_NOTIF_INTERNAL_EVENT_END (1 << 3) #define IWM_TE_V2_NOTIF_HOST_FRAG_START (1 << 4) #define IWM_TE_V2_NOTIF_HOST_FRAG_END (1 << 5) #define IWM_TE_V2_NOTIF_INTERNAL_FRAG_START (1 << 6) #define IWM_TE_V2_NOTIF_INTERNAL_FRAG_END (1 << 7) #define IWM_T2_V2_START_IMMEDIATELY (1 << 11) #define IWM_TE_V2_NOTIF_MSK 0xff /* placement characteristics */ #define IWM_TE_V2_DEP_OTHER (1 << IWM_TE_V2_PLACEMENT_POS) #define IWM_TE_V2_DEP_TSF (1 << (IWM_TE_V2_PLACEMENT_POS + 1)) #define IWM_TE_V2_EVENT_SOCIOPATHIC (1 << (IWM_TE_V2_PLACEMENT_POS + 2)) /* are we present or absent during the Time Event. */ #define IWM_TE_V2_ABSENCE (1 << IWM_TE_V2_ABSENCE_POS) /** * struct iwm_time_event_cmd_api - configuring Time Events * with struct IWM_MAC_TIME_EVENT_DATA_API_S_VER_2 (see also * with version 1. determined by IWM_UCODE_TLV_FLAGS) * ( IWM_TIME_EVENT_CMD = 0x29 ) * @id_and_color: ID and color of the relevant MAC * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @id: this field has two meanings, depending on the action: * If the action is ADD, then it means the type of event to add. * For all other actions it is the unique event ID assigned when the * event was added by the FW. * @apply_time: When to start the Time Event (in GP2) * @max_delay: maximum delay to event's start (apply time), in TU * @depends_on: the unique ID of the event we depend on (if any) * @interval: interval between repetitions, in TU * @duration: duration of event in TU * @repeat: how many repetitions to do, can be IWM_TE_REPEAT_ENDLESS * @max_frags: maximal number of fragments the Time Event can be divided to * @policy: defines whether uCode shall notify the host or other uCode modules * on event and/or fragment start and/or end * using one of IWM_TE_INDEPENDENT, IWM_TE_DEP_OTHER, IWM_TE_DEP_TSF * IWM_TE_EVENT_SOCIOPATHIC * using IWM_TE_ABSENCE and using IWM_TE_NOTIF_* */ struct iwm_time_event_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; uint32_t id; /* IWM_MAC_TIME_EVENT_DATA_API_S_VER_2 */ uint32_t apply_time; uint32_t max_delay; uint32_t depends_on; uint32_t interval; uint32_t duration; uint8_t repeat; uint8_t max_frags; uint16_t policy; } __packed; /* IWM_MAC_TIME_EVENT_CMD_API_S_VER_2 */ /** * struct iwm_time_event_resp - response structure to iwm_time_event_cmd * @status: bit 0 indicates success, all others specify errors * @id: the Time Event type * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE * @id_and_color: ID and color of the relevant MAC */ struct iwm_time_event_resp { uint32_t status; uint32_t id; uint32_t unique_id; uint32_t id_and_color; } __packed; /* IWM_MAC_TIME_EVENT_RSP_API_S_VER_1 */ /** * struct iwm_time_event_notif - notifications of time event start/stop * ( IWM_TIME_EVENT_NOTIFICATION = 0x2a ) * @timestamp: action timestamp in GP2 * @session_id: session's unique id * @unique_id: unique id of the Time Event itself * @id_and_color: ID and color of the relevant MAC * @action: one of IWM_TE_NOTIF_START or IWM_TE_NOTIF_END * @status: true if scheduled, false otherwise (not executed) */ struct iwm_time_event_notif { uint32_t timestamp; uint32_t session_id; uint32_t unique_id; uint32_t id_and_color; uint32_t action; uint32_t status; } __packed; /* IWM_MAC_TIME_EVENT_NTFY_API_S_VER_1 */ /* Bindings and Time Quota */ /** * struct iwm_binding_cmd_v1 - configuring bindings * ( IWM_BINDING_CONTEXT_CMD = 0x2b ) * @id_and_color: ID and color of the relevant Binding * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @macs: array of MAC id and colors which belong to the binding * @phy: PHY id and color which belongs to the binding * @lmac_id: the lmac id the binding belongs to */ struct iwm_binding_cmd_v1 { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWM_BINDING_DATA_API_S_VER_1 */ uint32_t macs[IWM_MAX_MACS_IN_BINDING]; uint32_t phy; } __packed; /* IWM_BINDING_CMD_API_S_VER_1 */ /** * struct iwm_binding_cmd - configuring bindings * ( IWM_BINDING_CONTEXT_CMD = 0x2b ) * @id_and_color: ID and color of the relevant Binding * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @macs: array of MAC id and colors which belong to the binding * @phy: PHY id and color which belongs to the binding * @lmac_id: the lmac id the binding belongs to */ struct iwm_binding_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWM_BINDING_DATA_API_S_VER_1 */ uint32_t macs[IWM_MAX_MACS_IN_BINDING]; uint32_t phy; uint32_t lmac_id; } __packed; /* IWM_BINDING_CMD_API_S_VER_2 */ #define IWM_LMAC_24G_INDEX 0 #define IWM_LMAC_5G_INDEX 1 /* The maximal number of fragments in the FW's schedule session */ #define IWM_MAX_QUOTA 128 /** * struct iwm_time_quota_data - configuration of time quota per binding * @id_and_color: ID and color of the relevant Binding * @quota: absolute time quota in TU. The scheduler will try to divide the * remainig quota (after Time Events) according to this quota. * @max_duration: max uninterrupted context duration in TU */ struct iwm_time_quota_data_v1 { uint32_t id_and_color; uint32_t quota; uint32_t max_duration; } __packed; /* IWM_TIME_QUOTA_DATA_API_S_VER_1 */ /** * struct iwm_time_quota_cmd - configuration of time quota between bindings * ( IWM_TIME_QUOTA_CMD = 0x2c ) * @quotas: allocations per binding */ struct iwm_time_quota_cmd_v1 { struct iwm_time_quota_data_v1 quotas[IWM_MAX_BINDINGS]; } __packed; /* IWM_TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */ #define IWM_QUOTA_LOW_LATENCY_NONE 0 #define IWM_QUOTA_LOW_LATENCY_TX (1 << 0) #define IWM_QUOTA_LOW_LATENCY_RX (1 << 1) /** * struct iwm_time_quota_data - configuration of time quota per binding * @id_and_color: ID and color of the relevant Binding. * @quota: absolute time quota in TU. The scheduler will try to divide the * remainig quota (after Time Events) according to this quota. * @max_duration: max uninterrupted context duration in TU * @low_latency: low latency status IWM_QUOTA_LOW_LATENCY_* */ struct iwm_time_quota_data { uint32_t id_and_color; uint32_t quota; uint32_t max_duration; uint32_t low_latency; }; /* TIME_QUOTA_DATA_API_S_VER_2 */ /** * struct iwm_time_quota_cmd - configuration of time quota between bindings * ( TIME_QUOTA_CMD = 0x2c ) * Note: on non-CDB the fourth one is the auxilary mac and is essentially zero. * On CDB the fourth one is a regular binding. * * @quotas: allocations per binding */ struct iwm_time_quota_cmd { struct iwm_time_quota_data quotas[IWM_MAX_BINDINGS]; } __packed; /* IWM_TIME_QUOTA_ALLOCATION_CMD_API_S_VER_2 */ /* PHY context */ /* Supported bands */ #define IWM_PHY_BAND_5 (0) #define IWM_PHY_BAND_24 (1) /* Supported channel width, vary if there is VHT support */ #define IWM_PHY_VHT_CHANNEL_MODE20 (0x0) #define IWM_PHY_VHT_CHANNEL_MODE40 (0x1) #define IWM_PHY_VHT_CHANNEL_MODE80 (0x2) #define IWM_PHY_VHT_CHANNEL_MODE160 (0x3) /* * Control channel position: * For legacy set bit means upper channel, otherwise lower. * For VHT - bit-2 marks if the control is lower/upper relative to center-freq * bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0. * center_freq * | * 40Mhz |_______|_______| * 80Mhz |_______|_______|_______|_______| * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______| * code 011 010 001 000 | 100 101 110 111 */ #define IWM_PHY_VHT_CTRL_POS_1_BELOW (0x0) #define IWM_PHY_VHT_CTRL_POS_2_BELOW (0x1) #define IWM_PHY_VHT_CTRL_POS_3_BELOW (0x2) #define IWM_PHY_VHT_CTRL_POS_4_BELOW (0x3) #define IWM_PHY_VHT_CTRL_POS_1_ABOVE (0x4) #define IWM_PHY_VHT_CTRL_POS_2_ABOVE (0x5) #define IWM_PHY_VHT_CTRL_POS_3_ABOVE (0x6) #define IWM_PHY_VHT_CTRL_POS_4_ABOVE (0x7) /* * @band: IWM_PHY_BAND_* * @channel: channel number * @width: PHY_[VHT|LEGACY]_CHANNEL_* * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* */ struct iwm_fw_channel_info_v1 { uint8_t band; uint8_t channel; uint8_t width; uint8_t ctrl_pos; } __packed; /* CHANNEL_CONFIG_API_S_VER_1 */ /* * struct iwm_fw_channel_info - channel information * * @channel: channel number * @band: PHY_BAND_* * @width: PHY_[VHT|LEGACY]_CHANNEL_* * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* * @reserved: for future use and alignment */ struct iwm_fw_channel_info { uint32_t channel; uint8_t band; uint8_t width; uint8_t ctrl_pos; uint8_t reserved; } __packed; /* CHANNEL_CONFIG_API_S_VER_2 */ #define IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS (0) #define IWM_PHY_RX_CHAIN_DRIVER_FORCE_MSK \ (0x1 << IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS) #define IWM_PHY_RX_CHAIN_VALID_POS (1) #define IWM_PHY_RX_CHAIN_VALID_MSK \ (0x7 << IWM_PHY_RX_CHAIN_VALID_POS) #define IWM_PHY_RX_CHAIN_FORCE_SEL_POS (4) #define IWM_PHY_RX_CHAIN_FORCE_SEL_MSK \ (0x7 << IWM_PHY_RX_CHAIN_FORCE_SEL_POS) #define IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS (7) #define IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK \ (0x7 << IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS) #define IWM_PHY_RX_CHAIN_CNT_POS (10) #define IWM_PHY_RX_CHAIN_CNT_MSK \ (0x3 << IWM_PHY_RX_CHAIN_CNT_POS) #define IWM_PHY_RX_CHAIN_MIMO_CNT_POS (12) #define IWM_PHY_RX_CHAIN_MIMO_CNT_MSK \ (0x3 << IWM_PHY_RX_CHAIN_MIMO_CNT_POS) #define IWM_PHY_RX_CHAIN_MIMO_FORCE_POS (14) #define IWM_PHY_RX_CHAIN_MIMO_FORCE_MSK \ (0x1 << IWM_PHY_RX_CHAIN_MIMO_FORCE_POS) /* TODO: fix the value, make it depend on firmware at runtime? */ #define IWM_NUM_PHY_CTX 3 /* TODO: complete missing documentation */ /** * struct iwm_phy_context_cmd - config of the PHY context * ( IWM_PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @apply_time: 0 means immediate apply and context switch. * other value means apply new params after X usecs * @tx_param_color: ??? * @channel_info: * @txchain_info: ??? * @rxchain_info: ??? * @acquisition_data: ??? * @dsp_cfg_flags: set to 0 */ /* * XXX Intel forgot to bump the PHY_CONTEXT command API when they increased * the size of fw_channel_info from v1 to v2. * To keep things simple we define two versions of this struct, and both * are labled as CMD_API_VER_1. (The Linux iwlwifi driver performs dark * magic with pointers to struct members instead.) */ /* This version must be used if IWM_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS is set: */ struct iwm_phy_context_cmd_uhb { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWM_PHY_CONTEXT_DATA_API_S_VER_1 */ uint32_t apply_time; uint32_t tx_param_color; struct iwm_fw_channel_info ci; uint32_t txchain_info; uint32_t rxchain_info; uint32_t acquisition_data; uint32_t dsp_cfg_flags; } __packed; /* IWM_PHY_CONTEXT_CMD_API_VER_1 */ /* This version must be used otherwise: */ struct iwm_phy_context_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWM_PHY_CONTEXT_DATA_API_S_VER_1 */ uint32_t apply_time; uint32_t tx_param_color; struct iwm_fw_channel_info_v1 ci; uint32_t txchain_info; uint32_t rxchain_info; uint32_t acquisition_data; uint32_t dsp_cfg_flags; } __packed; /* IWM_PHY_CONTEXT_CMD_API_VER_1 */ #define IWM_RX_INFO_PHY_CNT 8 #define IWM_RX_INFO_ENERGY_ANT_ABC_IDX 1 #define IWM_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff #define IWM_RX_INFO_ENERGY_ANT_B_MSK 0x0000ff00 #define IWM_RX_INFO_ENERGY_ANT_C_MSK 0x00ff0000 #define IWM_RX_INFO_ENERGY_ANT_A_POS 0 #define IWM_RX_INFO_ENERGY_ANT_B_POS 8 #define IWM_RX_INFO_ENERGY_ANT_C_POS 16 #define IWM_RX_INFO_AGC_IDX 1 #define IWM_RX_INFO_RSSI_AB_IDX 2 #define IWM_OFDM_AGC_A_MSK 0x0000007f #define IWM_OFDM_AGC_A_POS 0 #define IWM_OFDM_AGC_B_MSK 0x00003f80 #define IWM_OFDM_AGC_B_POS 7 #define IWM_OFDM_AGC_CODE_MSK 0x3fe00000 #define IWM_OFDM_AGC_CODE_POS 20 #define IWM_OFDM_RSSI_INBAND_A_MSK 0x00ff #define IWM_OFDM_RSSI_A_POS 0 #define IWM_OFDM_RSSI_ALLBAND_A_MSK 0xff00 #define IWM_OFDM_RSSI_ALLBAND_A_POS 8 #define IWM_OFDM_RSSI_INBAND_B_MSK 0xff0000 #define IWM_OFDM_RSSI_B_POS 16 #define IWM_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 #define IWM_OFDM_RSSI_ALLBAND_B_POS 24 /** * struct iwm_rx_phy_info - phy info * (IWM_REPLY_RX_PHY_CMD = 0xc0) * @non_cfg_phy_cnt: non configurable DSP phy data byte count * @cfg_phy_cnt: configurable DSP phy data byte count * @stat_id: configurable DSP phy data set ID * @reserved1: * @system_timestamp: GP2 at on air rise * @timestamp: TSF at on air rise * @beacon_time_stamp: beacon at on-air rise * @phy_flags: general phy flags: band, modulation, ... * @channel: channel number * @non_cfg_phy_buf: for various implementations of non_cfg_phy * @rate_n_flags: IWM_RATE_MCS_* * @byte_count: frame's byte-count * @frame_time: frame's time on the air, based on byte count and frame rate * calculation * @mac_active_msk: what MACs were active when the frame was received * * Before each Rx, the device sends this data. It contains PHY information * about the reception of the packet. */ struct iwm_rx_phy_info { uint8_t non_cfg_phy_cnt; uint8_t cfg_phy_cnt; uint8_t stat_id; uint8_t reserved1; uint32_t system_timestamp; uint64_t timestamp; uint32_t beacon_time_stamp; uint16_t phy_flags; #define IWM_PHY_INFO_FLAG_SHPREAMBLE (1 << 2) uint16_t channel; uint32_t non_cfg_phy[IWM_RX_INFO_PHY_CNT]; uint32_t rate_n_flags; uint32_t byte_count; uint16_t mac_active_msk; uint16_t frame_time; } __packed; struct iwm_rx_mpdu_res_start { uint16_t byte_count; uint16_t reserved; } __packed; /** * Values to parse %iwm_rx_phy_info phy_flags * @IWM_RX_RES_PHY_FLAGS_BAND_24: true if the packet was received on 2.4 band * @IWM_RX_RES_PHY_FLAGS_MOD_CCK: * @IWM_RX_RES_PHY_FLAGS_SHORT_PREAMBLE: true if packet's preamble was short * @IWM_RX_RES_PHY_FLAGS_NARROW_BAND: * @IWM_RX_RES_PHY_FLAGS_ANTENNA: antenna on which the packet was received * @IWM_RX_RES_PHY_FLAGS_AGG: set if the packet was part of an A-MPDU * @IWM_RX_RES_PHY_FLAGS_OFDM_HT: The frame was an HT frame * @IWM_RX_RES_PHY_FLAGS_OFDM_GF: The frame used GF preamble * @IWM_RX_RES_PHY_FLAGS_OFDM_VHT: The frame was a VHT frame */ #define IWM_RX_RES_PHY_FLAGS_BAND_24 (1 << 0) #define IWM_RX_RES_PHY_FLAGS_MOD_CCK (1 << 1) #define IWM_RX_RES_PHY_FLAGS_SHORT_PREAMBLE (1 << 2) #define IWM_RX_RES_PHY_FLAGS_NARROW_BAND (1 << 3) #define IWM_RX_RES_PHY_FLAGS_ANTENNA (0x7 << 4) #define IWM_RX_RES_PHY_FLAGS_ANTENNA_POS 4 #define IWM_RX_RES_PHY_FLAGS_AGG (1 << 7) #define IWM_RX_RES_PHY_FLAGS_OFDM_HT (1 << 8) #define IWM_RX_RES_PHY_FLAGS_OFDM_GF (1 << 9) #define IWM_RX_RES_PHY_FLAGS_OFDM_VHT (1 << 10) /** * Values written by fw for each Rx packet * @IWM_RX_MPDU_RES_STATUS_CRC_OK: CRC is fine * @IWM_RX_MPDU_RES_STATUS_OVERRUN_OK: there was no RXE overflow * @IWM_RX_MPDU_RES_STATUS_SRC_STA_FOUND: * @IWM_RX_MPDU_RES_STATUS_KEY_VALID: * @IWM_RX_MPDU_RES_STATUS_KEY_PARAM_OK: * @IWM_RX_MPDU_RES_STATUS_ICV_OK: ICV is fine, if not, the packet is destroyed * @IWM_RX_MPDU_RES_STATUS_MIC_OK: used for CCM alg only. TKIP MIC is checked * in the driver. * @IWM_RX_MPDU_RES_STATUS_TTAK_OK: TTAK is fine * @IWM_RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR: valid for alg = CCM_CMAC or * alg = CCM only. Checks replay attack for 11w frames. Relevant only if * %IWM_RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME is set. * @IWM_RX_MPDU_RES_STATUS_SEC_NO_ENC: this frame is not encrypted * @IWM_RX_MPDU_RES_STATUS_SEC_WEP_ENC: this frame is encrypted using WEP * @IWM_RX_MPDU_RES_STATUS_SEC_CCM_ENC: this frame is encrypted using CCM * @IWM_RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP * @IWM_RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC * @IWM_RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted * @IWM_RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm * @IWM_RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted * @IWM_RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP: * @IWM_RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: * @IWM_RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: * @IWM_RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame * @IWM_RX_MPDU_RES_STATUS_HASH_INDEX_MSK: * @IWM_RX_MPDU_RES_STATUS_STA_ID_MSK: * @IWM_RX_MPDU_RES_STATUS_RRF_KILL: * @IWM_RX_MPDU_RES_STATUS_FILTERING_MSK: * @IWM_RX_MPDU_RES_STATUS2_FILTERING_MSK: */ #define IWM_RX_MPDU_RES_STATUS_CRC_OK (1 << 0) #define IWM_RX_MPDU_RES_STATUS_OVERRUN_OK (1 << 1) #define IWM_RX_MPDU_RES_STATUS_SRC_STA_FOUND (1 << 2) #define IWM_RX_MPDU_RES_STATUS_KEY_VALID (1 << 3) #define IWM_RX_MPDU_RES_STATUS_KEY_PARAM_OK (1 << 4) #define IWM_RX_MPDU_RES_STATUS_ICV_OK (1 << 5) #define IWM_RX_MPDU_RES_STATUS_MIC_OK (1 << 6) #define IWM_RX_MPDU_RES_STATUS_TTAK_OK (1 << 7) #define IWM_RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR (1 << 7) #define IWM_RX_MPDU_RES_STATUS_SEC_NO_ENC (0 << 8) #define IWM_RX_MPDU_RES_STATUS_SEC_WEP_ENC (1 << 8) #define IWM_RX_MPDU_RES_STATUS_SEC_CCM_ENC (2 << 8) #define IWM_RX_MPDU_RES_STATUS_SEC_TKIP_ENC (3 << 8) #define IWM_RX_MPDU_RES_STATUS_SEC_EXT_ENC (4 << 8) #define IWM_RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC (6 << 8) #define IWM_RX_MPDU_RES_STATUS_SEC_ENC_ERR (7 << 8) #define IWM_RX_MPDU_RES_STATUS_SEC_ENC_MSK (7 << 8) #define IWM_RX_MPDU_RES_STATUS_DEC_DONE (1 << 11) #define IWM_RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP (1 << 12) #define IWM_RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP (1 << 13) #define IWM_RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT (1 << 14) #define IWM_RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME (1 << 15) #define IWM_RX_MPDU_RES_STATUS_HASH_INDEX_MSK (0x3F0000) #define IWM_RX_MPDU_RES_STATUS_STA_ID_MSK (0x1f000000) #define IWM_RX_MPDU_RES_STATUS_RRF_KILL (1 << 29) #define IWM_RX_MPDU_RES_STATUS_FILTERING_MSK (0xc00000) #define IWM_RX_MPDU_RES_STATUS2_FILTERING_MSK (0xc0000000) #define IWM_RX_MPDU_MFLG1_ADDRTYPE_MASK 0x03 #define IWM_RX_MPDU_MFLG1_MIC_CRC_LEN_MASK 0xf0 #define IWM_RX_MPDU_MFLG1_MIC_CRC_LEN_SHIFT 3 #define IWM_RX_MPDU_MFLG2_HDR_LEN_MASK 0x1f #define IWM_RX_MPDU_MFLG2_PAD 0x20 #define IWM_RX_MPDU_MFLG2_AMSDU 0x40 #define IWM_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK 0x7f #define IWM_RX_MPDU_AMSDU_LAST_SUBFRAME 0x80 #define IWM_RX_MPDU_PHY_AMPDU (1 << 5) #define IWM_RX_MPDU_PHY_AMPDU_TOGGLE (1 << 6) #define IWM_RX_MPDU_PHY_SHORT_PREAMBLE (1 << 7) #define IWM_RX_MPDU_PHY_NCCK_ADDTL_NTFY (1 << 7) #define IWM_RX_MPDU_PHY_TSF_OVERLOAD (1 << 8) struct iwm_rx_mpdu_desc_v1 { union { uint32_t rss_hash; uint32_t phy_data2; }; union { uint32_t filter_match; uint32_t phy_data3; }; uint32_t rate_n_flags; uint8_t energy_a; uint8_t energy_b; uint8_t channel; uint8_t mac_context; uint32_t gp2_on_air_rise; union { uint64_t tsf_on_air_rise; struct { uint32_t phy_data0; uint32_t phy_data1; }; }; } __packed; #define IWM_RX_REORDER_DATA_INVALID_BAID 0x7f #define IWM_RX_MPDU_REORDER_NSSN_MASK 0x00000fff #define IWM_RX_MPDU_REORDER_SN_MASK 0x00fff000 #define IWM_RX_MPDU_REORDER_SN_SHIFT 12 #define IWM_RX_MPDU_REORDER_BAID_MASK 0x7f000000 #define IWM_RX_MPDU_REORDER_BAID_SHIFT 24 #define IWM_RX_MPDU_REORDER_BA_OLD_SN 0x80000000 struct iwm_rx_mpdu_desc { uint16_t mpdu_len; uint8_t mac_flags1; uint8_t mac_flags2; uint8_t amsdu_info; uint16_t phy_info; uint8_t mac_phy_idx; uint16_t raw_csum; union { uint16_t l3l4_flags; uint16_t phy_data4; }; uint16_t status; uint8_t hash_filter; uint8_t sta_id_flags; uint32_t reorder_data; struct iwm_rx_mpdu_desc_v1 v1; } __packed; /** * struct iwm_radio_version_notif - information on the radio version * ( IWM_RADIO_VERSION_NOTIFICATION = 0x68 ) * @radio_flavor: * @radio_step: * @radio_dash: */ struct iwm_radio_version_notif { uint32_t radio_flavor; uint32_t radio_step; uint32_t radio_dash; } __packed; /* IWM_RADIO_VERSION_NOTOFICATION_S_VER_1 */ #define IWM_CARD_ENABLED 0x00 #define IWM_HW_CARD_DISABLED 0x01 #define IWM_SW_CARD_DISABLED 0x02 #define IWM_CT_KILL_CARD_DISABLED 0x04 #define IWM_HALT_CARD_DISABLED 0x08 #define IWM_CARD_DISABLED_MSK 0x0f #define IWM_CARD_IS_RX_ON 0x10 /** * struct iwm_radio_version_notif - information on the radio version * (IWM_CARD_STATE_NOTIFICATION = 0xa1 ) * @flags: %iwm_card_state_flags */ struct iwm_card_state_notif { uint32_t flags; } __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ /** * struct iwm_missed_beacons_notif - information on missed beacons * ( IWM_MISSED_BEACONS_NOTIFICATION = 0xa2 ) * @mac_id: interface ID * @consec_missed_beacons_since_last_rx: number of consecutive missed * beacons since last RX. * @consec_missed_beacons: number of consecutive missed beacons * @num_expected_beacons: * @num_recvd_beacons: */ struct iwm_missed_beacons_notif { uint32_t mac_id; uint32_t consec_missed_beacons_since_last_rx; uint32_t consec_missed_beacons; uint32_t num_expected_beacons; uint32_t num_recvd_beacons; } __packed; /* IWM_MISSED_BEACON_NTFY_API_S_VER_3 */ /** * struct iwm_mfuart_load_notif - mfuart image version & status * ( IWM_MFUART_LOAD_NOTIFICATION = 0xb1 ) * @installed_ver: installed image version * @external_ver: external image version * @status: MFUART loading status * @duration: MFUART loading time */ struct iwm_mfuart_load_notif { uint32_t installed_ver; uint32_t external_ver; uint32_t status; uint32_t duration; } __packed; /*MFU_LOADER_NTFY_API_S_VER_1*/ /** * struct iwm_set_calib_default_cmd - set default value for calibration. * ( IWM_SET_CALIB_DEFAULT_CMD = 0x8e ) * @calib_index: the calibration to set value for * @length: of data * @data: the value to set for the calibration result */ struct iwm_set_calib_default_cmd { uint16_t calib_index; uint16_t length; uint8_t data[0]; } __packed; /* IWM_PHY_CALIB_OVERRIDE_VALUES_S */ #define IWM_MAX_PORT_ID_NUM 2 #define IWM_MAX_MCAST_FILTERING_ADDRESSES 256 /** * struct iwm_mcast_filter_cmd - configure multicast filter. * @filter_own: Set 1 to filter out multicast packets sent by station itself * @port_id: Multicast MAC addresses array specifier. This is a strange way * to identify network interface adopted in host-device IF. * It is used by FW as index in array of addresses. This array has * IWM_MAX_PORT_ID_NUM members. * @count: Number of MAC addresses in the array * @pass_all: Set 1 to pass all multicast packets. * @bssid: current association BSSID. * @addr_list: Place holder for array of MAC addresses. * IMPORTANT: add padding if necessary to ensure DWORD alignment. */ struct iwm_mcast_filter_cmd { uint8_t filter_own; uint8_t port_id; uint8_t count; uint8_t pass_all; uint8_t bssid[6]; uint8_t reserved[2]; uint8_t addr_list[0]; } __packed; /* IWM_MCAST_FILTERING_CMD_API_S_VER_1 */ struct iwm_statistics_dbg { uint32_t burst_check; uint32_t burst_count; uint32_t wait_for_silence_timeout_cnt; uint32_t reserved[3]; } __packed; /* IWM_STATISTICS_DEBUG_API_S_VER_2 */ struct iwm_statistics_div { uint32_t tx_on_a; uint32_t tx_on_b; uint32_t exec_time; uint32_t probe_time; uint32_t rssi_ant; uint32_t reserved2; } __packed; /* IWM_STATISTICS_SLOW_DIV_API_S_VER_2 */ struct iwm_statistics_general_common { uint32_t temperature; /* radio temperature */ uint32_t temperature_m; /* radio voltage */ struct iwm_statistics_dbg dbg; uint32_t sleep_time; uint32_t slots_out; uint32_t slots_idle; uint32_t ttl_timestamp; struct iwm_statistics_div div; uint32_t rx_enable_counter; /* * num_of_sos_states: * count the number of times we have to re-tune * in order to get out of bad PHY status */ uint32_t num_of_sos_states; } __packed; /* IWM_STATISTICS_GENERAL_API_S_VER_5 */ struct iwm_statistics_rx_non_phy { uint32_t bogus_cts; /* CTS received when not expecting CTS */ uint32_t bogus_ack; /* ACK received when not expecting ACK */ uint32_t non_bssid_frames; /* number of frames with BSSID that * doesn't belong to the STA BSSID */ uint32_t filtered_frames; /* count frames that were dumped in the * filtering process */ uint32_t non_channel_beacons; /* beacons with our bss id but not on * our serving channel */ uint32_t channel_beacons; /* beacons with our bss id and in our * serving channel */ uint32_t num_missed_bcon; /* number of missed beacons */ uint32_t adc_rx_saturation_time; /* count in 0.8us units the time the * ADC was in saturation */ uint32_t ina_detection_search_time;/* total time (in 0.8us) searched * for INA */ uint32_t beacon_silence_rssi[3];/* RSSI silence after beacon frame */ uint32_t interference_data_flag; /* flag for interference data * availability. 1 when data is * available. */ uint32_t channel_load; /* counts RX Enable time in uSec */ uint32_t dsp_false_alarms; /* DSP false alarm (both OFDM * and CCK) counter */ uint32_t beacon_rssi_a; uint32_t beacon_rssi_b; uint32_t beacon_rssi_c; uint32_t beacon_energy_a; uint32_t beacon_energy_b; uint32_t beacon_energy_c; uint32_t num_bt_kills; uint32_t mac_id; uint32_t directed_data_mpdu; } __packed; /* IWM_STATISTICS_RX_NON_PHY_API_S_VER_3 */ struct iwm_statistics_rx_phy { uint32_t ina_cnt; uint32_t fina_cnt; uint32_t plcp_err; uint32_t crc32_err; uint32_t overrun_err; uint32_t early_overrun_err; uint32_t crc32_good; uint32_t false_alarm_cnt; uint32_t fina_sync_err_cnt; uint32_t sfd_timeout; uint32_t fina_timeout; uint32_t unresponded_rts; uint32_t rxe_frame_limit_overrun; uint32_t sent_ack_cnt; uint32_t sent_cts_cnt; uint32_t sent_ba_rsp_cnt; uint32_t dsp_self_kill; uint32_t mh_format_err; uint32_t re_acq_main_rssi_sum; uint32_t reserved; } __packed; /* IWM_STATISTICS_RX_PHY_API_S_VER_2 */ struct iwm_statistics_rx_ht_phy { uint32_t plcp_err; uint32_t overrun_err; uint32_t early_overrun_err; uint32_t crc32_good; uint32_t crc32_err; uint32_t mh_format_err; uint32_t agg_crc32_good; uint32_t agg_mpdu_cnt; uint32_t agg_cnt; uint32_t unsupport_mcs; } __packed; /* IWM_STATISTICS_HT_RX_PHY_API_S_VER_1 */ #define IWM_MAX_CHAINS 3 struct iwm_statistics_tx_non_phy_agg { uint32_t ba_timeout; uint32_t ba_reschedule_frames; uint32_t scd_query_agg_frame_cnt; uint32_t scd_query_no_agg; uint32_t scd_query_agg; uint32_t scd_query_mismatch; uint32_t frame_not_ready; uint32_t underrun; uint32_t bt_prio_kill; uint32_t rx_ba_rsp_cnt; int8_t txpower[IWM_MAX_CHAINS]; int8_t reserved; uint32_t reserved2; } __packed; /* IWM_STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */ struct iwm_statistics_tx_channel_width { uint32_t ext_cca_narrow_ch20[1]; uint32_t ext_cca_narrow_ch40[2]; uint32_t ext_cca_narrow_ch80[3]; uint32_t ext_cca_narrow_ch160[4]; uint32_t last_tx_ch_width_indx; uint32_t rx_detected_per_ch_width[4]; uint32_t success_per_ch_width[4]; uint32_t fail_per_ch_width[4]; }; /* IWM_STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ struct iwm_statistics_tx { uint32_t preamble_cnt; uint32_t rx_detected_cnt; uint32_t bt_prio_defer_cnt; uint32_t bt_prio_kill_cnt; uint32_t few_bytes_cnt; uint32_t cts_timeout; uint32_t ack_timeout; uint32_t expected_ack_cnt; uint32_t actual_ack_cnt; uint32_t dump_msdu_cnt; uint32_t burst_abort_next_frame_mismatch_cnt; uint32_t burst_abort_missing_next_frame_cnt; uint32_t cts_timeout_collision; uint32_t ack_or_ba_timeout_collision; struct iwm_statistics_tx_non_phy_agg agg; struct iwm_statistics_tx_channel_width channel_width; } __packed; /* IWM_STATISTICS_TX_API_S_VER_4 */ struct iwm_statistics_bt_activity { uint32_t hi_priority_tx_req_cnt; uint32_t hi_priority_tx_denied_cnt; uint32_t lo_priority_tx_req_cnt; uint32_t lo_priority_tx_denied_cnt; uint32_t hi_priority_rx_req_cnt; uint32_t hi_priority_rx_denied_cnt; uint32_t lo_priority_rx_req_cnt; uint32_t lo_priority_rx_denied_cnt; } __packed; /* IWM_STATISTICS_BT_ACTIVITY_API_S_VER_1 */ struct iwm_statistics_general { struct iwm_statistics_general_common common; uint32_t beacon_filtered; uint32_t missed_beacons; int8_t beacon_filter_average_energy; int8_t beacon_filter_reason; int8_t beacon_filter_current_energy; int8_t beacon_filter_reserved; uint32_t beacon_filter_delta_time; struct iwm_statistics_bt_activity bt_activity; } __packed; /* IWM_STATISTICS_GENERAL_API_S_VER_5 */ struct iwm_statistics_rx { struct iwm_statistics_rx_phy ofdm; struct iwm_statistics_rx_phy cck; struct iwm_statistics_rx_non_phy general; struct iwm_statistics_rx_ht_phy ofdm_ht; } __packed; /* IWM_STATISTICS_RX_API_S_VER_3 */ /* * IWM_STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) * * By default, uCode issues this notification after receiving a beacon * while associated. To disable this behavior, set DISABLE_NOTIF flag in the * IWM_REPLY_STATISTICS_CMD 0x9c, above. * * Statistics counters continue to increment beacon after beacon, but are * cleared when changing channels or when driver issues IWM_REPLY_STATISTICS_CMD * 0x9c with CLEAR_STATS bit set (see above). * * uCode also issues this notification during scans. uCode clears statistics * appropriately so that each notification contains statistics for only the * one channel that has just been scanned. */ struct iwm_notif_statistics { /* IWM_STATISTICS_NTFY_API_S_VER_8 */ uint32_t flag; struct iwm_statistics_rx rx; struct iwm_statistics_tx tx; struct iwm_statistics_general general; } __packed; /*********************************** * Smart Fifo API ***********************************/ /* Smart Fifo state */ #define IWM_SF_LONG_DELAY_ON 0 /* should never be called by driver */ #define IWM_SF_FULL_ON 1 #define IWM_SF_UNINIT 2 #define IWM_SF_INIT_OFF 3 #define IWM_SF_HW_NUM_STATES 4 /* Smart Fifo possible scenario */ #define IWM_SF_SCENARIO_SINGLE_UNICAST 0 #define IWM_SF_SCENARIO_AGG_UNICAST 1 #define IWM_SF_SCENARIO_MULTICAST 2 #define IWM_SF_SCENARIO_BA_RESP 3 #define IWM_SF_SCENARIO_TX_RESP 4 #define IWM_SF_NUM_SCENARIO 5 #define IWM_SF_TRANSIENT_STATES_NUMBER 2 /* IWM_SF_LONG_DELAY_ON and IWM_SF_FULL_ON */ #define IWM_SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */ /* smart FIFO default values */ #define IWM_SF_W_MARK_SISO 4096 #define IWM_SF_W_MARK_MIMO2 8192 #define IWM_SF_W_MARK_MIMO3 6144 #define IWM_SF_W_MARK_LEGACY 4096 #define IWM_SF_W_MARK_SCAN 4096 /* SF Scenarios timers for default configuration (aligned to 32 uSec) */ #define IWM_SF_SINGLE_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWM_SF_SINGLE_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWM_SF_AGG_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWM_SF_AGG_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWM_SF_MCAST_IDLE_TIMER_DEF 160 /* 150 mSec */ #define IWM_SF_MCAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWM_SF_BA_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWM_SF_BA_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWM_SF_TX_RE_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWM_SF_TX_RE_AGING_TIMER_DEF 400 /* 0.4 mSec */ /* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */ #define IWM_SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */ #define IWM_SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */ #define IWM_SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */ #define IWM_SF_AGG_UNICAST_AGING_TIMER 2016 /* 2 mSec */ #define IWM_SF_MCAST_IDLE_TIMER 2016 /* 2 mSec */ #define IWM_SF_MCAST_AGING_TIMER 10016 /* 10 mSec */ #define IWM_SF_BA_IDLE_TIMER 320 /* 300 uSec */ #define IWM_SF_BA_AGING_TIMER 2016 /* 2 mSec */ #define IWM_SF_TX_RE_IDLE_TIMER 320 /* 300 uSec */ #define IWM_SF_TX_RE_AGING_TIMER 2016 /* 2 mSec */ #define IWM_SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ #define IWM_SF_CFG_DUMMY_NOTIF_OFF (1 << 16) /** * Smart Fifo configuration command. * @state: smart fifo state, types listed in enum %iwm_sf_state. * @watermark: Minimum allowed availabe free space in RXF for transient state. * @long_delay_timeouts: aging and idle timer values for each scenario * in long delay state. * @full_on_timeouts: timer values for each scenario in full on state. */ struct iwm_sf_cfg_cmd { uint32_t state; uint32_t watermark[IWM_SF_TRANSIENT_STATES_NUMBER]; uint32_t long_delay_timeouts[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES]; uint32_t full_on_timeouts[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES]; } __packed; /* IWM_SF_CFG_API_S_VER_2 */ /* * The first MAC indices (starting from 0) * are available to the driver, AUX follows */ #define IWM_MAC_INDEX_AUX 4 #define IWM_MAC_INDEX_MIN_DRIVER 0 #define IWM_NUM_MAC_INDEX_DRIVER IWM_MAC_INDEX_AUX #define IWM_AC_BK 0 #define IWM_AC_BE 1 #define IWM_AC_VI 2 #define IWM_AC_VO 3 #define IWM_AC_NUM 4 /** * MAC context flags * @IWM_MAC_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames, * this will require CCK RTS/CTS2self. * RTS/CTS will protect full burst time. * @IWM_MAC_PROT_FLG_HT_PROT: enable HT protection * @IWM_MAC_PROT_FLG_FAT_PROT: protect 40 MHz transmissions * @IWM_MAC_PROT_FLG_SELF_CTS_EN: allow CTS2self */ #define IWM_MAC_PROT_FLG_TGG_PROTECT (1 << 3) #define IWM_MAC_PROT_FLG_HT_PROT (1 << 23) #define IWM_MAC_PROT_FLG_FAT_PROT (1 << 24) #define IWM_MAC_PROT_FLG_SELF_CTS_EN (1 << 30) #define IWM_MAC_FLG_SHORT_SLOT (1 << 4) #define IWM_MAC_FLG_SHORT_PREAMBLE (1 << 5) /** * Supported MAC types * @IWM_FW_MAC_TYPE_FIRST: lowest supported MAC type * @IWM_FW_MAC_TYPE_AUX: Auxiliary MAC (internal) * @IWM_FW_MAC_TYPE_LISTENER: monitor MAC type (?) * @IWM_FW_MAC_TYPE_PIBSS: Pseudo-IBSS * @IWM_FW_MAC_TYPE_IBSS: IBSS * @IWM_FW_MAC_TYPE_BSS_STA: BSS (managed) station * @IWM_FW_MAC_TYPE_P2P_DEVICE: P2P Device * @IWM_FW_MAC_TYPE_P2P_STA: P2P client * @IWM_FW_MAC_TYPE_GO: P2P GO * @IWM_FW_MAC_TYPE_TEST: ? * @IWM_FW_MAC_TYPE_MAX: highest support MAC type */ #define IWM_FW_MAC_TYPE_FIRST 1 #define IWM_FW_MAC_TYPE_AUX IWM_FW_MAC_TYPE_FIRST #define IWM_FW_MAC_TYPE_LISTENER 2 #define IWM_FW_MAC_TYPE_PIBSS 3 #define IWM_FW_MAC_TYPE_IBSS 4 #define IWM_FW_MAC_TYPE_BSS_STA 5 #define IWM_FW_MAC_TYPE_P2P_DEVICE 6 #define IWM_FW_MAC_TYPE_P2P_STA 7 #define IWM_FW_MAC_TYPE_GO 8 #define IWM_FW_MAC_TYPE_TEST 9 #define IWM_FW_MAC_TYPE_MAX IWM_FW_MAC_TYPE_TEST /* IWM_MAC_CONTEXT_TYPE_API_E_VER_1 */ /** * TSF hw timer ID * @IWM_TSF_ID_A: use TSF A * @IWM_TSF_ID_B: use TSF B * @IWM_TSF_ID_C: use TSF C * @IWM_TSF_ID_D: use TSF D * @IWM_NUM_TSF_IDS: number of TSF timers available */ #define IWM_TSF_ID_A 0 #define IWM_TSF_ID_B 1 #define IWM_TSF_ID_C 2 #define IWM_TSF_ID_D 3 #define IWM_NUM_TSF_IDS 4 /* IWM_TSF_ID_API_E_VER_1 */ /** * struct iwm_mac_data_ap - configuration data for AP MAC context * @beacon_time: beacon transmit time in system time * @beacon_tsf: beacon transmit time in TSF * @bi: beacon interval in TU * @bi_reciprocal: 2^32 / bi * @dtim_interval: dtim transmit time in TU * @dtim_reciprocal: 2^32 / dtim_interval * @mcast_qid: queue ID for multicast traffic * NOTE: obsolete from VER2 and on * @beacon_template: beacon template ID */ struct iwm_mac_data_ap { uint32_t beacon_time; uint64_t beacon_tsf; uint32_t bi; uint32_t bi_reciprocal; uint32_t dtim_interval; uint32_t dtim_reciprocal; uint32_t mcast_qid; uint32_t beacon_template; } __packed; /* AP_MAC_DATA_API_S_VER_2 */ /** * struct iwm_mac_data_ibss - configuration data for IBSS MAC context * @beacon_time: beacon transmit time in system time * @beacon_tsf: beacon transmit time in TSF * @bi: beacon interval in TU * @bi_reciprocal: 2^32 / bi * @beacon_template: beacon template ID */ struct iwm_mac_data_ibss { uint32_t beacon_time; uint64_t beacon_tsf; uint32_t bi; uint32_t bi_reciprocal; uint32_t beacon_template; } __packed; /* IBSS_MAC_DATA_API_S_VER_1 */ /** * struct iwm_mac_data_sta - configuration data for station MAC context * @is_assoc: 1 for associated state, 0 otherwise * @dtim_time: DTIM arrival time in system time * @dtim_tsf: DTIM arrival time in TSF * @bi: beacon interval in TU, applicable only when associated * @bi_reciprocal: 2^32 / bi , applicable only when associated * @dtim_interval: DTIM interval in TU, applicable only when associated * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated * @listen_interval: in beacon intervals, applicable only when associated * @assoc_id: unique ID assigned by the AP during association */ struct iwm_mac_data_sta { uint32_t is_assoc; uint32_t dtim_time; uint64_t dtim_tsf; uint32_t bi; uint32_t bi_reciprocal; uint32_t dtim_interval; uint32_t dtim_reciprocal; uint32_t listen_interval; uint32_t assoc_id; uint32_t assoc_beacon_arrive_time; } __packed; /* IWM_STA_MAC_DATA_API_S_VER_1 */ /** * struct iwm_mac_data_go - configuration data for P2P GO MAC context * @ap: iwm_mac_data_ap struct with most config data * @ctwin: client traffic window in TU (period after TBTT when GO is present). * 0 indicates that there is no CT window. * @opp_ps_enabled: indicate that opportunistic PS allowed */ struct iwm_mac_data_go { struct iwm_mac_data_ap ap; uint32_t ctwin; uint32_t opp_ps_enabled; } __packed; /* GO_MAC_DATA_API_S_VER_1 */ /** * struct iwm_mac_data_p2p_sta - configuration data for P2P client MAC context * @sta: iwm_mac_data_sta struct with most config data * @ctwin: client traffic window in TU (period after TBTT when GO is present). * 0 indicates that there is no CT window. */ struct iwm_mac_data_p2p_sta { struct iwm_mac_data_sta sta; uint32_t ctwin; } __packed; /* P2P_STA_MAC_DATA_API_S_VER_1 */ /** * struct iwm_mac_data_pibss - Pseudo IBSS config data * @stats_interval: interval in TU between statistics notifications to host. */ struct iwm_mac_data_pibss { uint32_t stats_interval; } __packed; /* PIBSS_MAC_DATA_API_S_VER_1 */ /* * struct iwm_mac_data_p2p_dev - configuration data for the P2P Device MAC * context. * @is_disc_extended: if set to true, P2P Device discoverability is enabled on * other channels as well. This should be to true only in case that the * device is discoverable and there is an active GO. Note that setting this * field when not needed, will increase the number of interrupts and have * effect on the platform power, as this setting opens the Rx filters on * all macs. */ struct iwm_mac_data_p2p_dev { uint32_t is_disc_extended; } __packed; /* _P2P_DEV_MAC_DATA_API_S_VER_1 */ /** * MAC context filter flags * @IWM_MAC_FILTER_IN_PROMISC: accept all data frames * @IWM_MAC_FILTER_IN_CONTROL_AND_MGMT: pass all mangement and * control frames to the host * @IWM_MAC_FILTER_ACCEPT_GRP: accept multicast frames * @IWM_MAC_FILTER_DIS_DECRYPT: don't decrypt unicast frames * @IWM_MAC_FILTER_DIS_GRP_DECRYPT: don't decrypt multicast frames * @IWM_MAC_FILTER_IN_BEACON: transfer foreign BSS's beacons to host * (in station mode when associated) * @IWM_MAC_FILTER_OUT_BCAST: filter out all broadcast frames * @IWM_MAC_FILTER_IN_CRC32: extract FCS and append it to frames * @IWM_MAC_FILTER_IN_PROBE_REQUEST: pass probe requests to host */ #define IWM_MAC_FILTER_IN_PROMISC (1 << 0) #define IWM_MAC_FILTER_IN_CONTROL_AND_MGMT (1 << 1) #define IWM_MAC_FILTER_ACCEPT_GRP (1 << 2) #define IWM_MAC_FILTER_DIS_DECRYPT (1 << 3) #define IWM_MAC_FILTER_DIS_GRP_DECRYPT (1 << 4) #define IWM_MAC_FILTER_IN_BEACON (1 << 6) #define IWM_MAC_FILTER_OUT_BCAST (1 << 8) #define IWM_MAC_FILTER_IN_CRC32 (1 << 11) #define IWM_MAC_FILTER_IN_PROBE_REQUEST (1 << 12) /** * QoS flags * @IWM_MAC_QOS_FLG_UPDATE_EDCA: ? * @IWM_MAC_QOS_FLG_TGN: HT is enabled * @IWM_MAC_QOS_FLG_TXOP_TYPE: ? * */ #define IWM_MAC_QOS_FLG_UPDATE_EDCA (1 << 0) #define IWM_MAC_QOS_FLG_TGN (1 << 1) #define IWM_MAC_QOS_FLG_TXOP_TYPE (1 << 4) /** * struct iwm_ac_qos - QOS timing params for IWM_MAC_CONTEXT_CMD * @cw_min: Contention window, start value in numbers of slots. * Should be a power-of-2, minus 1. Device's default is 0x0f. * @cw_max: Contention window, max value in numbers of slots. * Should be a power-of-2, minus 1. Device's default is 0x3f. * @aifsn: Number of slots in Arbitration Interframe Space (before * performing random backoff timing prior to Tx). Device default 1. * @fifos_mask: FIFOs used by this MAC for this AC * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0. * * One instance of this config struct for each of 4 EDCA access categories * in struct iwm_qosparam_cmd. * * Device will automatically increase contention window by (2*CW) + 1 for each * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW * value, to cap the CW value. */ struct iwm_ac_qos { uint16_t cw_min; uint16_t cw_max; uint8_t aifsn; uint8_t fifos_mask; uint16_t edca_txop; } __packed; /* IWM_AC_QOS_API_S_VER_2 */ /** * struct iwm_mac_ctx_cmd - command structure to configure MAC contexts * ( IWM_MAC_CONTEXT_CMD = 0x28 ) * @id_and_color: ID and color of the MAC * @action: action to perform, one of IWM_FW_CTXT_ACTION_* * @mac_type: one of IWM_FW_MAC_TYPE_* * @tsf_id: TSF HW timer, one of IWM_TSF_ID_* * @node_addr: MAC address * @bssid_addr: BSSID * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM * @protection_flags: combination of IWM_MAC_PROT_FLG_FLAG_* * @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise * @short_slot: 0x10 for enabling short slots, 0 otherwise * @filter_flags: combination of IWM_MAC_FILTER_* * @qos_flags: from IWM_MAC_QOS_FLG_* * @ac: one iwm_mac_qos configuration for each AC * @mac_specific: one of struct iwm_mac_data_*, according to mac_type */ struct iwm_mac_ctx_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWM_MAC_CONTEXT_COMMON_DATA_API_S_VER_1 */ uint32_t mac_type; uint32_t tsf_id; uint8_t node_addr[6]; uint16_t reserved_for_node_addr; uint8_t bssid_addr[6]; uint16_t reserved_for_bssid_addr; uint32_t cck_rates; uint32_t ofdm_rates; uint32_t protection_flags; uint32_t cck_short_preamble; uint32_t short_slot; uint32_t filter_flags; /* IWM_MAC_QOS_PARAM_API_S_VER_1 */ uint32_t qos_flags; struct iwm_ac_qos ac[IWM_AC_NUM+1]; /* IWM_MAC_CONTEXT_COMMON_DATA_API_S */ union { struct iwm_mac_data_ap ap; struct iwm_mac_data_go go; struct iwm_mac_data_sta sta; struct iwm_mac_data_p2p_sta p2p_sta; struct iwm_mac_data_p2p_dev p2p_dev; struct iwm_mac_data_pibss pibss; struct iwm_mac_data_ibss ibss; }; } __packed; /* IWM_MAC_CONTEXT_CMD_API_S_VER_1 */ static inline uint32_t iwm_reciprocal(uint32_t v) { if (!v) return 0; return 0xFFFFFFFF / v; } #define IWM_NONQOS_SEQ_GET 0x1 #define IWM_NONQOS_SEQ_SET 0x2 struct iwm_nonqos_seq_query_cmd { uint32_t get_set_flag; uint32_t mac_id_n_color; uint16_t value; uint16_t reserved; } __packed; /* IWM_NON_QOS_TX_COUNTER_GET_SET_API_S_VER_1 */ /* Power Management Commands, Responses, Notifications */ /** * masks for LTR config command flags * @IWM_LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status * @IWM_LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow * memory access * @IWM_LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR * reg change * @IWM_LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from * D0 to D3 * @IWM_LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register * @IWM_LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register * @IWM_LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD */ #define IWM_LTR_CFG_FLAG_FEATURE_ENABLE 0x00000001 #define IWM_LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS 0x00000002 #define IWM_LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH 0x00000004 #define IWM_LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 0x00000008 #define IWM_LTR_CFG_FLAG_SW_SET_SHORT 0x00000010 #define IWM_LTR_CFG_FLAG_SW_SET_LONG 0x00000020 #define IWM_LTR_CFG_FLAG_DENIE_C10_ON_PD 0x00000040 /** * struct iwm_ltr_config_cmd_v1 - configures the LTR * @flags: See %enum iwm_ltr_config_flags */ struct iwm_ltr_config_cmd_v1 { uint32_t flags; uint32_t static_long; uint32_t static_short; } __packed; /* LTR_CAPABLE_API_S_VER_1 */ #define IWM_LTR_VALID_STATES_NUM 4 /** * struct iwm_ltr_config_cmd - configures the LTR * @flags: See %enum iwm_ltr_config_flags * @static_long: * @static_short: * @ltr_cfg_values: * @ltr_short_idle_timeout: */ struct iwm_ltr_config_cmd { uint32_t flags; uint32_t static_long; uint32_t static_short; uint32_t ltr_cfg_values[IWM_LTR_VALID_STATES_NUM]; uint32_t ltr_short_idle_timeout; } __packed; /* LTR_CAPABLE_API_S_VER_2 */ /* Radio LP RX Energy Threshold measured in dBm */ #define IWM_POWER_LPRX_RSSI_THRESHOLD 75 #define IWM_POWER_LPRX_RSSI_THRESHOLD_MAX 94 #define IWM_POWER_LPRX_RSSI_THRESHOLD_MIN 30 /** * Masks for iwm_mac_power_cmd command flags * @IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off * receiver and transmitter. '0' - does not allow. * @IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, * '1' Driver enables PM (use rest of parameters) * @IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, * '1' PM could sleep over DTIM till listen Interval. * @IWM_POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all * access categories are both delivery and trigger enabled. * @IWM_POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and * PBW Snoozing enabled * @IWM_POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask * @IWM_POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. * @IWM_POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving * detection enablement */ #define IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK (1 << 0) #define IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK (1 << 1) #define IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK (1 << 2) #define IWM_POWER_FLAGS_SNOOZE_ENA_MSK (1 << 5) #define IWM_POWER_FLAGS_BT_SCO_ENA (1 << 8) #define IWM_POWER_FLAGS_ADVANCE_PM_ENA_MSK (1 << 9) #define IWM_POWER_FLAGS_LPRX_ENA_MSK (1 << 11) #define IWM_POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK (1 << 12) #define IWM_POWER_VEC_SIZE 5 /** * Masks for device power command flags * @IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK: * '1' Allow to save power by turning off receiver and transmitter. * '0' Do not allow. This flag should be always set to '1' unless * one needs to disable actual power down for debug purposes. * @IWM_DEVICE_POWER_FLAGS_CAM_MSK: * '1' CAM (Continuous Active Mode) is set, power management is disabled. * '0' Power management is enabled, one of the power schemes is applied. */ #define IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK (1 << 0) #define IWM_DEVICE_POWER_FLAGS_CAM_MSK (1 << 13) /** * struct iwm_device_power_cmd - device wide power command. * IWM_POWER_TABLE_CMD = 0x77 (command, has simple generic response) * * @flags: Power table command flags from IWM_DEVICE_POWER_FLAGS_* */ struct iwm_device_power_cmd { /* PM_POWER_TABLE_CMD_API_S_VER_6 */ uint16_t flags; uint16_t reserved; } __packed; /** * struct iwm_mac_power_cmd - New power command containing uAPSD support * IWM_MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) * @id_and_color: MAC contex identifier * @flags: Power table command flags from POWER_FLAGS_* * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. * Minimum allowed:- 3 * DTIM. Keep alive period must be * set regardless of power scheme or current power state. * FW use this value also when PM is disabled. * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to * PSM transition - legacy PM * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to * PSM transition - legacy PM * @sleep_interval: not in use * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag * is set. For example, if it is required to skip over * one DTIM, this value need to be set to 2 (DTIM periods). * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to * PSM transition - uAPSD * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to * PSM transition - uAPSD * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. * Default: 80dbm * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set * @snooze_interval: Maximum time between attempts to retrieve buffered data * from the AP [msec] * @snooze_window: A window of time in which PBW snoozing insures that all * packets received. It is also the minimum time from last * received unicast RX packet, before client stops snoozing * for data. [msec] * @snooze_step: TBD * @qndp_tid: TID client shall use for uAPSD QNDP triggers * @uapsd_ac_flags: Set trigger-enabled and delivery-enabled indication for * each corresponding AC. * Use IEEE80211_WMM_IE_STA_QOSINFO_AC* for correct values. * @uapsd_max_sp: Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct * values. * @heavy_tx_thld_packets: TX threshold measured in number of packets * @heavy_rx_thld_packets: RX threshold measured in number of packets * @heavy_tx_thld_percentage: TX threshold measured in load's percentage * @heavy_rx_thld_percentage: RX threshold measured in load's percentage * @limited_ps_threshold: */ struct iwm_mac_power_cmd { /* CONTEXT_DESC_API_T_VER_1 */ uint32_t id_and_color; /* CLIENT_PM_POWER_TABLE_S_VER_1 */ uint16_t flags; uint16_t keep_alive_seconds; uint32_t rx_data_timeout; uint32_t tx_data_timeout; uint32_t rx_data_timeout_uapsd; uint32_t tx_data_timeout_uapsd; uint8_t lprx_rssi_threshold; uint8_t skip_dtim_periods; uint16_t snooze_interval; uint16_t snooze_window; uint8_t snooze_step; uint8_t qndp_tid; uint8_t uapsd_ac_flags; uint8_t uapsd_max_sp; uint8_t heavy_tx_thld_packets; uint8_t heavy_rx_thld_packets; uint8_t heavy_tx_thld_percentage; uint8_t heavy_rx_thld_percentage; uint8_t limited_ps_threshold; uint8_t reserved; } __packed; #define IWM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * 1000) #define IWM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * 1000) /* * struct iwm_uapsd_misbehaving_ap_notif - FW sends this notification when * associated AP is identified as improperly implementing uAPSD protocol. * IWM_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78 * @sta_id: index of station in uCode's station table - associated AP ID in * this context. */ struct iwm_uapsd_misbehaving_ap_notif { uint32_t sta_id; uint8_t mac_id; uint8_t reserved[3]; } __packed; /** * struct iwm_beacon_filter_cmd * IWM_REPLY_BEACON_FILTERING_CMD = 0xd2 (command) * @id_and_color: MAC contex identifier * @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon * to driver if delta in Energy values calculated for this and last * passed beacon is greater than this threshold. Zero value means that * the Energy change is ignored for beacon filtering, and beacon will * not be forced to be sent to driver regardless of this delta. Typical * energy delta 5dB. * @bf_roaming_energy_delta: Used for RSSI filtering, if in 'roaming' state. * Send beacon to driver if delta in Energy values calculated for this * and last passed beacon is greater than this threshold. Zero value * means that the Energy change is ignored for beacon filtering while in * Roaming state, typical energy delta 1dB. * @bf_roaming_state: Used for RSSI filtering. If absolute Energy values * calculated for current beacon is less than the threshold, use * Roaming Energy Delta Threshold, otherwise use normal Energy Delta * Threshold. Typical energy threshold is -72dBm. * @bf_temp_threshold: This threshold determines the type of temperature * filtering (Slow or Fast) that is selected (Units are in Celsuis): * If the current temperature is above this threshold - Fast filter * will be used, If the current temperature is below this threshold - * Slow filter will be used. * @bf_temp_fast_filter: Send Beacon to driver if delta in temperature values * calculated for this and the last passed beacon is greater than this * threshold. Zero value means that the temperature change is ignored for * beacon filtering; beacons will not be forced to be sent to driver * regardless of whether its temerature has been changed. * @bf_temp_slow_filter: Send Beacon to driver if delta in temperature values * calculated for this and the last passed beacon is greater than this * threshold. Zero value means that the temperature change is ignored for * beacon filtering; beacons will not be forced to be sent to driver * regardless of whether its temerature has been changed. * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled. * @bf_escape_timer: Send beacons to driver if no beacons were passed * for a specific period of time. Units: Beacons. * @ba_escape_timer: Fully receive and parse beacon if no beacons were passed * for a longer period of time then this escape-timeout. Units: Beacons. * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled. */ struct iwm_beacon_filter_cmd { uint32_t bf_energy_delta; uint32_t bf_roaming_energy_delta; uint32_t bf_roaming_state; uint32_t bf_temp_threshold; uint32_t bf_temp_fast_filter; uint32_t bf_temp_slow_filter; uint32_t bf_enable_beacon_filter; uint32_t bf_debug_flag; uint32_t bf_escape_timer; uint32_t ba_escape_timer; uint32_t ba_enable_beacon_abort; } __packed; /* Beacon filtering and beacon abort */ #define IWM_BF_ENERGY_DELTA_DEFAULT 5 #define IWM_BF_ENERGY_DELTA_MAX 255 #define IWM_BF_ENERGY_DELTA_MIN 0 #define IWM_BF_ROAMING_ENERGY_DELTA_DEFAULT 1 #define IWM_BF_ROAMING_ENERGY_DELTA_MAX 255 #define IWM_BF_ROAMING_ENERGY_DELTA_MIN 0 #define IWM_BF_ROAMING_STATE_DEFAULT 72 #define IWM_BF_ROAMING_STATE_MAX 255 #define IWM_BF_ROAMING_STATE_MIN 0 #define IWM_BF_TEMP_THRESHOLD_DEFAULT 112 #define IWM_BF_TEMP_THRESHOLD_MAX 255 #define IWM_BF_TEMP_THRESHOLD_MIN 0 #define IWM_BF_TEMP_FAST_FILTER_DEFAULT 1 #define IWM_BF_TEMP_FAST_FILTER_MAX 255 #define IWM_BF_TEMP_FAST_FILTER_MIN 0 #define IWM_BF_TEMP_SLOW_FILTER_DEFAULT 5 #define IWM_BF_TEMP_SLOW_FILTER_MAX 255 #define IWM_BF_TEMP_SLOW_FILTER_MIN 0 #define IWM_BF_ENABLE_BEACON_FILTER_DEFAULT 1 #define IWM_BF_DEBUG_FLAG_DEFAULT 0 #define IWM_BF_ESCAPE_TIMER_DEFAULT 50 #define IWM_BF_ESCAPE_TIMER_MAX 1024 #define IWM_BF_ESCAPE_TIMER_MIN 0 #define IWM_BA_ESCAPE_TIMER_DEFAULT 6 #define IWM_BA_ESCAPE_TIMER_D3 9 #define IWM_BA_ESCAPE_TIMER_MAX 1024 #define IWM_BA_ESCAPE_TIMER_MIN 0 #define IWM_BA_ENABLE_BEACON_ABORT_DEFAULT 1 #define IWM_BF_CMD_CONFIG_DEFAULTS \ .bf_energy_delta = htole32(IWM_BF_ENERGY_DELTA_DEFAULT), \ .bf_roaming_energy_delta = \ htole32(IWM_BF_ROAMING_ENERGY_DELTA_DEFAULT), \ .bf_roaming_state = htole32(IWM_BF_ROAMING_STATE_DEFAULT), \ .bf_temp_threshold = htole32(IWM_BF_TEMP_THRESHOLD_DEFAULT), \ .bf_temp_fast_filter = htole32(IWM_BF_TEMP_FAST_FILTER_DEFAULT), \ .bf_temp_slow_filter = htole32(IWM_BF_TEMP_SLOW_FILTER_DEFAULT), \ .bf_debug_flag = htole32(IWM_BF_DEBUG_FLAG_DEFAULT), \ .bf_escape_timer = htole32(IWM_BF_ESCAPE_TIMER_DEFAULT), \ .ba_escape_timer = htole32(IWM_BA_ESCAPE_TIMER_DEFAULT) /* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C */ #define IWM_RATE_MCS_ANT_POS 14 #define IWM_RATE_MCS_ANT_A_MSK (1 << IWM_RATE_MCS_ANT_POS) #define IWM_RATE_MCS_ANT_B_MSK (2 << IWM_RATE_MCS_ANT_POS) #define IWM_RATE_MCS_ANT_C_MSK (4 << IWM_RATE_MCS_ANT_POS) #define IWM_RATE_MCS_ANT_AB_MSK (IWM_RATE_MCS_ANT_A_MSK | \ IWM_RATE_MCS_ANT_B_MSK) #define IWM_RATE_MCS_ANT_ABC_MSK (IWM_RATE_MCS_ANT_AB_MSK | \ IWM_RATE_MCS_ANT_C_MSK) #define IWM_RATE_MCS_ANT_MSK IWM_RATE_MCS_ANT_ABC_MSK #define IWM_RATE_MCS_ANT_NUM 3 /* # entries in rate scale table to support Tx retries */ #define IWM_LQ_MAX_RETRY_NUM 16 /* Antenna flags. */ #define IWM_ANT_A (1 << 0) #define IWM_ANT_B (1 << 1) #define IWM_ANT_C (1 << 2) /* Shortcuts. */ #define IWM_ANT_AB (IWM_ANT_A | IWM_ANT_B) #define IWM_ANT_BC (IWM_ANT_B | IWM_ANT_C) #define IWM_ANT_ABC (IWM_ANT_A | IWM_ANT_B | IWM_ANT_C) /** * struct iwm_lq_cmd - link quality command * @sta_id: station to update * @control: not used * @flags: combination of IWM_LQ_FLAG_* * @mimo_delim: the first SISO index in rs_table, which separates MIMO * and SISO rates * @single_stream_ant_msk: best antenna for SISO (can be dual in CDD). * Should be IWM_ANT_[ABC] * @dual_stream_ant_msk: best antennas for MIMO, combination of IWM_ANT_[ABC] * @initial_rate_index: first index from rs_table per AC category * @agg_time_limit: aggregation max time threshold in usec/100, meaning * value of 100 is one usec. Range is 100 to 8000 * @agg_disable_start_th: try-count threshold for starting aggregation. * If a frame has higher try-count, it should not be selected for * starting an aggregation sequence. * @agg_frame_cnt_limit: max frame count in an aggregation. * 0: no limit * 1: no aggregation (one frame per aggregation) * 2 - 0x3f: maximal number of frames (up to 3f == 63) * @rs_table: array of rates for each TX try, each is rate_n_flags, * meaning it is a combination of IWM_RATE_MCS_* and IWM_RATE_*_PLCP * @ss_params: single stream features. declare whether STBC or BFER are allowed. */ struct iwm_lq_cmd { uint8_t sta_id; uint8_t reduced_tpc; uint16_t control; /* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */ uint8_t flags; uint8_t mimo_delim; uint8_t single_stream_ant_msk; uint8_t dual_stream_ant_msk; uint8_t initial_rate_index[IWM_AC_NUM]; /* LINK_QUAL_AGG_PARAMS_API_S_VER_1 */ uint16_t agg_time_limit; uint8_t agg_disable_start_th; uint8_t agg_frame_cnt_limit; uint32_t reserved2; uint32_t rs_table[IWM_LQ_MAX_RETRY_NUM]; uint32_t ss_params; }; /* LINK_QUALITY_CMD_API_S_VER_1 */ /** * bitmasks for tx_flags in TX command * @IWM_TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame * @IWM_TX_CMD_FLG_ACK: expect ACK from receiving station * @IWM_TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command. * Otherwise, use rate_n_flags from the TX command * @IWM_TX_CMD_FLG_BA: this frame is a block ack * @IWM_TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected * Must set IWM_TX_CMD_FLG_ACK with this flag. * @IWM_TX_CMD_FLG_TXOP_PROT: protect frame with full TXOP protection * @IWM_TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence * @IWM_TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence * @IWM_TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) * @IWM_TX_CMD_FLG_BT_DIS: disable BT priority for this frame * @IWM_TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control. * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command * @IWM_TX_CMD_FLG_MORE_FRAG: this frame is non-last MPDU * @IWM_TX_CMD_FLG_NEXT_FRAME: this frame includes information of the next frame * @IWM_TX_CMD_FLG_TSF: FW should calculate and insert TSF in the frame * Should be set for beacons and probe responses * @IWM_TX_CMD_FLG_CALIB: activate PA TX power calibrations * @IWM_TX_CMD_FLG_KEEP_SEQ_CTL: if seq_ctl is set, don't increase inner seq count * @IWM_TX_CMD_FLG_AGG_START: allow this frame to start aggregation * @IWM_TX_CMD_FLG_MH_PAD: driver inserted 2 byte padding after MAC header. * Should be set for 26/30 length MAC headers * @IWM_TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW * @IWM_TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration * @IWM_TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation * @IWM_TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id * @IWM_TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped * @IWM_TX_CMD_FLG_EXEC_PAPD: execute PAPD * @IWM_TX_CMD_FLG_PAPD_TYPE: 0 for reference power, 1 for nominal power * @IWM_TX_CMD_FLG_HCCA_CHUNK: mark start of TSPEC chunk */ #define IWM_TX_CMD_FLG_PROT_REQUIRE (1 << 0) #define IWM_TX_CMD_FLG_ACK (1 << 3) #define IWM_TX_CMD_FLG_STA_RATE (1 << 4) #define IWM_TX_CMD_FLG_BA (1 << 5) #define IWM_TX_CMD_FLG_BAR (1 << 6) #define IWM_TX_CMD_FLG_TXOP_PROT (1 << 7) #define IWM_TX_CMD_FLG_VHT_NDPA (1 << 8) #define IWM_TX_CMD_FLG_HT_NDPA (1 << 9) #define IWM_TX_CMD_FLG_CSI_FDBK2HOST (1 << 10) #define IWM_TX_CMD_FLG_BT_PRIO_POS 11 #define IWM_TX_CMD_FLG_BT_DIS (1 << 12) #define IWM_TX_CMD_FLG_SEQ_CTL (1 << 13) #define IWM_TX_CMD_FLG_MORE_FRAG (1 << 14) #define IWM_TX_CMD_FLG_NEXT_FRAME (1 << 15) #define IWM_TX_CMD_FLG_TSF (1 << 16) #define IWM_TX_CMD_FLG_CALIB (1 << 17) #define IWM_TX_CMD_FLG_KEEP_SEQ_CTL (1 << 18) #define IWM_TX_CMD_FLG_AGG_START (1 << 19) #define IWM_TX_CMD_FLG_MH_PAD (1 << 20) #define IWM_TX_CMD_FLG_RESP_TO_DRV (1 << 21) #define IWM_TX_CMD_FLG_CCMP_AGG (1 << 22) #define IWM_TX_CMD_FLG_TKIP_MIC_DONE (1 << 23) #define IWM_TX_CMD_FLG_DUR (1 << 25) #define IWM_TX_CMD_FLG_FW_DROP (1 << 26) #define IWM_TX_CMD_FLG_EXEC_PAPD (1 << 27) #define IWM_TX_CMD_FLG_PAPD_TYPE (1 << 28) #define IWM_TX_CMD_FLG_HCCA_CHUNK (1U << 31) /* IWM_TX_FLAGS_BITS_API_S_VER_1 */ /* * TX command security control */ #define IWM_TX_CMD_SEC_WEP 0x01 #define IWM_TX_CMD_SEC_CCM 0x02 #define IWM_TX_CMD_SEC_TKIP 0x03 #define IWM_TX_CMD_SEC_EXT 0x04 #define IWM_TX_CMD_SEC_MSK 0x07 #define IWM_TX_CMD_SEC_WEP_KEY_IDX_POS 6 #define IWM_TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 #define IWM_TX_CMD_SEC_KEY128 0x08 /* TODO: how does these values are OK with only 16 bit variable??? */ /* * TX command next frame info * * bits 0:2 - security control (IWM_TX_CMD_SEC_*) * bit 3 - immediate ACK required * bit 4 - rate is taken from STA table * bit 5 - frame belongs to BA stream * bit 6 - immediate BA response expected * bit 7 - unused * bits 8:15 - Station ID * bits 16:31 - rate */ #define IWM_TX_CMD_NEXT_FRAME_ACK_MSK (0x8) #define IWM_TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10) #define IWM_TX_CMD_NEXT_FRAME_BA_MSK (0x20) #define IWM_TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40) #define IWM_TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8) #define IWM_TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00) #define IWM_TX_CMD_NEXT_FRAME_STA_ID_POS (8) #define IWM_TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000) #define IWM_TX_CMD_NEXT_FRAME_RATE_POS (16) /* * TX command Frame life time in us - to be written in pm_frame_timeout */ #define IWM_TX_CMD_LIFE_TIME_INFINITE 0xFFFFFFFF #define IWM_TX_CMD_LIFE_TIME_DEFAULT 2000000 /* 2000 ms*/ #define IWM_TX_CMD_LIFE_TIME_PROBE_RESP 40000 /* 40 ms */ #define IWM_TX_CMD_LIFE_TIME_EXPIRED_FRAME 0 #define RX_REORDER_BUF_TIMEOUT_MQ_USEC (100000ULL) /* * TID for non QoS frames - to be written in tid_tspec */ #define IWM_MAX_TID_COUNT 8 #define IWM_TID_NON_QOS 0 #define IWM_TID_MGMT 15 /* * Limits on the retransmissions - to be written in {data,rts}_retry_limit */ #define IWM_DEFAULT_TX_RETRY 15 #define IWM_MGMT_DFAULT_RETRY_LIMIT 3 #define IWM_RTS_DFAULT_RETRY_LIMIT 3 #define IWM_BAR_DFAULT_RETRY_LIMIT 60 #define IWM_LOW_RETRY_LIMIT 7 /** * %iwl_tx_cmd offload_assist values * @TX_CMD_OFFLD_IP_HDR: offset to start of IP header (in words) * from mac header end. For normal case it is 4 words for SNAP. * note: tx_cmd, mac header and pad are not counted in the offset. * This is used to help the offload in case there is tunneling such as * IPv6 in IPv4, in such case the ip header offset should point to the * inner ip header and IPv4 checksum of the external header should be * calculated by driver. * @TX_CMD_OFFLD_L4_EN: enable TCP/UDP checksum * @TX_CMD_OFFLD_L3_EN: enable IP header checksum * @TX_CMD_OFFLD_MH_SIZE: size of the mac header in words. Includes the IV * field. Doesn't include the pad. * @TX_CMD_OFFLD_PAD: mark 2-byte pad was inserted after the mac header for * alignment * @TX_CMD_OFFLD_AMSDU: mark TX command is A-MSDU */ #define IWM_TX_CMD_OFFLD_IP_HDR(x) ((x) << 0) #define IWM_TX_CMD_OFFLD_L4_EN (1 << 6) #define IWM_TX_CMD_OFFLD_L3_EN (1 << 7) #define IWM_TX_CMD_OFFLD_MH_SIZE(x) ((x) << 8) #define IWM_TX_CMD_OFFLD_PAD (1 << 13) #define IWM_TX_CMD_OFFLD_AMSDU (1 << 14) #define IWM_TX_CMD_OFFLD_MH_MASK 0x1f #define IWM_TX_CMD_OFFLD_IP_HDR_MASK 0x3f /* TODO: complete documentation for try_cnt and btkill_cnt */ /** * struct iwm_tx_cmd - TX command struct to FW * ( IWM_TX_CMD = 0x1c ) * @len: in bytes of the payload, see below for details * @offload_assist: TX offload configuration * @tx_flags: combination of IWM_TX_CMD_FLG_* * @rate_n_flags: rate for *all* Tx attempts, if IWM_TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of IWM_RATE_MCS_* * @sta_id: index of destination station in FW station table * @sec_ctl: security control, IWM_TX_CMD_SEC_* * @initial_rate_index: index into the rate table for initial TX attempt. * Applied if IWM_TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames. * @key: security key * @next_frame_flags: IWM_TX_CMD_SEC_* and IWM_TX_CMD_NEXT_FRAME_* * @life_time: frame life time (usecs??) * @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt + * btkill_cnd + reserved), first 32 bits. "0" disables usage. * @dram_msb_ptr: upper bits of the scratch physical address * @rts_retry_limit: max attempts for RTS * @data_retry_limit: max attempts to send the data packet * @tid_spec: TID/tspec * @pm_frame_timeout: PM TX frame timeout * @driver_txop: duration od EDCA TXOP, in 32-usec units. Set this if not * specified by HCCA protocol * * The byte count (both len and next_frame_len) includes MAC header * (24/26/30/32 bytes) * + 2 bytes pad if 26/30 header size * + 8 byte IV for CCM or TKIP (not used for WEP) * + Data payload * + 8-byte MIC (not used for CCM/WEP) * It does not include post-MAC padding, i.e., * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes. * Range of len: 14-2342 bytes. * * After the struct fields the MAC header is placed, plus any padding, * and then the actial payload. */ struct iwm_tx_cmd { uint16_t len; uint16_t offload_assist; uint32_t tx_flags; struct { uint8_t try_cnt; uint8_t btkill_cnt; uint16_t reserved; } scratch; /* DRAM_SCRATCH_API_U_VER_1 */ uint32_t rate_n_flags; uint8_t sta_id; uint8_t sec_ctl; uint8_t initial_rate_index; uint8_t reserved2; uint8_t key[16]; uint16_t next_frame_flags; uint16_t reserved3; uint32_t life_time; uint32_t dram_lsb_ptr; uint8_t dram_msb_ptr; uint8_t rts_retry_limit; uint8_t data_retry_limit; uint8_t tid_tspec; uint16_t pm_frame_timeout; uint16_t driver_txop; uint8_t payload[0]; struct ieee80211_frame hdr[0]; } __packed; /* IWM_TX_CMD_API_S_VER_3 */ /* For aggregation queues, index must be aligned to frame sequence number. */ #define IWM_AGG_SSN_TO_TXQ_IDX(x) ((x) & (IWM_TX_RING_COUNT - 1)) /* * TX response related data */ /* * status that is returned by the fw after attempts to Tx * @IWM_TX_STATUS_FAIL_STA_COLOR_MISMATCH: mismatch between color of Tx cmd and * STA table * Valid only if frame_count =1 */ #define IWM_TX_STATUS_MSK 0x000000ff #define IWM_TX_STATUS_SUCCESS 0x01 #define IWM_TX_STATUS_DIRECT_DONE 0x02 /* postpone TX */ #define IWM_TX_STATUS_POSTPONE_DELAY 0x40 #define IWM_TX_STATUS_POSTPONE_FEW_BYTES 0x41 #define IWM_TX_STATUS_POSTPONE_BT_PRIO 0x42 #define IWM_TX_STATUS_POSTPONE_QUIET_PERIOD 0x43 #define IWM_TX_STATUS_POSTPONE_CALC_TTAK 0x44 /* abort TX */ #define IWM_TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY 0x81 #define IWM_TX_STATUS_FAIL_SHORT_LIMIT 0x82 #define IWM_TX_STATUS_FAIL_LONG_LIMIT 0x83 #define IWM_TX_STATUS_FAIL_UNDERRUN 0x84 #define IWM_TX_STATUS_FAIL_DRAIN_FLOW 0x85 #define IWM_TX_STATUS_FAIL_RFKILL_FLUSH 0x86 #define IWM_TX_STATUS_FAIL_LIFE_EXPIRE 0x87 #define IWM_TX_STATUS_FAIL_DEST_PS 0x88 #define IWM_TX_STATUS_FAIL_HOST_ABORTED 0x89 #define IWM_TX_STATUS_FAIL_BT_RETRY 0x8a #define IWM_TX_STATUS_FAIL_STA_INVALID 0x8b #define IWM_TX_STATUS_FAIL_FRAG_DROPPED 0x8c #define IWM_TX_STATUS_FAIL_TID_DISABLE 0x8d #define IWM_TX_STATUS_FAIL_FIFO_FLUSHED 0x8e #define IWM_TX_STATUS_FAIL_SMALL_CF_POLL 0x8f #define IWM_TX_STATUS_FAIL_FW_DROP 0x90 #define IWM_TX_STATUS_FAIL_STA_COLOR_MISMATCH 0x91 #define IWM_TX_STATUS_INTERNAL_ABORT 0x92 #define IWM_TX_MODE_MSK 0x00000f00 #define IWM_TX_MODE_NO_BURST 0x00000000 #define IWM_TX_MODE_IN_BURST_SEQ 0x00000100 #define IWM_TX_MODE_FIRST_IN_BURST 0x00000200 #define IWM_TX_QUEUE_NUM_MSK 0x0001f000 #define IWM_TX_NARROW_BW_MSK 0x00060000 #define IWM_TX_NARROW_BW_1DIV2 0x00020000 #define IWM_TX_NARROW_BW_1DIV4 0x00040000 #define IWM_TX_NARROW_BW_1DIV8 0x00060000 /* * TX aggregation status * @IWM_AGG_TX_STATE_TRY_CNT_MSK: Retry count for 1st frame in aggregation (retries * occur if tx failed for this frame when it was a member of a previous * aggregation block). If rate scaling is used, retry count indicates the * rate table entry used for all frames in the new agg. */ #define IWM_AGG_TX_STATE_STATUS_MSK 0x0fff #define IWM_AGG_TX_STATE_TRANSMITTED 0x0000 #define IWM_AGG_TX_STATE_UNDERRUN 0x0001 #define IWM_AGG_TX_STATE_BT_PRIO 0x0002 #define IWM_AGG_TX_STATE_FEW_BYTES 0x0004 #define IWM_AGG_TX_STATE_ABORT 0x0008 #define IWM_AGG_TX_STATE_TX_ON_AIR_DROP 0x0010 #define IWM_AGG_TX_STATE_LAST_SENT_TRY_CNT 0x0020 #define IWM_AGG_TX_STATE_LAST_SENT_BT_KILL 0x0040 #define IWM_AGG_TX_STATE_SCD_QUERY 0x0080 #define IWM_AGG_TX_STATE_TEST_BAD_CRC32 0x0100 #define IWM_AGG_TX_STATE_RESPONSE 0x01ff #define IWM_AGG_TX_STATE_DUMP_TX 0x0200 #define IWM_AGG_TX_STATE_DELAY_TX 0x0400 #define IWM_AGG_TX_STATE_TRY_CNT_POS 12 #define IWM_AGG_TX_STATE_TRY_CNT_MSK (0xf << IWM_AGG_TX_STATE_TRY_CNT_POS) #define IWM_AGG_TX_STATE_LAST_SENT_MSK (IWM_AGG_TX_STATE_LAST_SENT_TTL| \ IWM_AGG_TX_STATE_LAST_SENT_TRY_CNT| \ IWM_AGG_TX_STATE_LAST_SENT_BT_KILL) /* * The mask below describes a status where we are absolutely sure that the MPDU * wasn't sent. For BA/Underrun we cannot be that sure. All we know that we've * written the bytes to the TXE, but we know nothing about what the DSP did. */ #define IWM_AGG_TX_STAT_FRAME_NOT_SENT (IWM_AGG_TX_STATE_FEW_BYTES | \ IWM_AGG_TX_STATE_ABORT | \ IWM_AGG_TX_STATE_SCD_QUERY) /* * IWM_REPLY_TX = 0x1c (response) * * This response may be in one of two slightly different formats, indicated * by the frame_count field: * * 1) No aggregation (frame_count == 1). This reports Tx results for a single * frame. Multiple attempts, at various bit rates, may have been made for * this frame. * * 2) Aggregation (frame_count > 1). This reports Tx results for two or more * frames that used block-acknowledge. All frames were transmitted at * same rate. Rate scaling may have been used if first frame in this new * agg block failed in previous agg block(s). * * Note that, for aggregation, ACK (block-ack) status is not delivered * here; block-ack has not been received by the time the device records * this status. * This status relates to reasons the tx might have been blocked or aborted * within the device, rather than whether it was received successfully by * the destination station. */ /** * struct iwm_agg_tx_status - per packet TX aggregation status * @status: IWM_AGG_TX_STATE_* * @idx: Tx queue index of this frame * @qid: Tx queue ID of this frame */ struct iwm_agg_tx_status { uint16_t status; uint8_t idx; uint8_t qid; } __packed; /* * definitions for initial rate index field * bits [3:0] initial rate index * bits [6:4] rate table color, used for the initial rate * bit-7 invalid rate indication */ #define IWM_TX_RES_INIT_RATE_INDEX_MSK 0x0f #define IWM_TX_RES_RATE_TABLE_COLOR_MSK 0x70 #define IWM_TX_RES_INV_RATE_INDEX_MSK 0x80 #define IWM_TX_RES_GET_TID(_ra_tid) ((_ra_tid) & 0x0f) #define IWM_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4) /** * struct iwm_tx_resp - notifies that fw is TXing a packet * ( IWM_REPLY_TX = 0x1c ) * @frame_count: 1 no aggregation, >1 aggregation * @bt_kill_count: num of times blocked by bluetooth (unused for agg) * @failure_rts: num of failures due to unsuccessful RTS * @failure_frame: num failures due to no ACK (unused for agg) * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the * Tx of all the batch. IWM_RATE_MCS_* * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK. * for agg: RTS + CTS + aggregation tx time + block-ack time. * in usec. * @pa_status: tx power info * @pa_integ_res_a: tx power info * @pa_integ_res_b: tx power info * @pa_integ_res_c: tx power info * @measurement_req_id: tx power info * @tfd_info: TFD information set by the FH * @seq_ctl: sequence control field from IEEE80211 frame header * @byte_cnt: byte count from the Tx cmd * @tlc_info: TLC rate info * @ra_tid: bits [3:0] = ra, bits [7:4] = tid * @frame_ctrl: frame control * @status: for non-agg: frame status IWM_TX_STATUS_* * for agg: status of 1st frame, IWM_AGG_TX_STATE_*; other frame status fields * follow this one, up to frame_count. * * After the array of statuses comes the SSN of the SCD. Look at * %iwm_get_scd_ssn for more details. */ struct iwm_tx_resp { uint8_t frame_count; uint8_t bt_kill_count; uint8_t failure_rts; uint8_t failure_frame; uint32_t initial_rate; uint16_t wireless_media_time; uint8_t pa_status; uint8_t pa_integ_res_a[3]; uint8_t pa_integ_res_b[3]; uint8_t pa_integ_res_c[3]; uint16_t measurement_req_id; uint8_t reduced_tpc; uint8_t reserved; uint32_t tfd_info; uint16_t seq_ctl; uint16_t byte_cnt; uint8_t tlc_info; uint8_t ra_tid; uint16_t frame_ctrl; struct iwm_agg_tx_status status[]; } __packed; /* IWM_TX_RSP_API_S_VER_3 */ /** * struct iwm_ba_notif - notifies about reception of BA * ( IWM_BA_NOTIF = 0xc5 ) * @sta_addr: MAC address * @sta_id: Index of recipient (BA-sending) station in fw's station table * @tid: tid of the session * @seq_ctl: sequence control field from IEEE80211 frame header (the first * bit in @bitmap corresponds to the sequence number stored here) * @bitmap: the bitmap of the BA notification as seen in the air * @scd_flow: the tx queue this BA relates to * @scd_ssn: the index of the last contiguously sent packet * @txed: number of Txed frames in this batch * @txed_2_done: number of Acked frames in this batch * @reduced_txp: power reduced according to TPC. This is the actual value and * not a copy from the LQ command. Thus, if not the first rate was used * for Tx-ing then this value will be set to 0 by FW. * @reserved1: reserved */ struct iwm_ba_notif { uint8_t sta_addr[ETHER_ADDR_LEN]; uint16_t reserved; uint8_t sta_id; uint8_t tid; uint16_t seq_ctl; uint64_t bitmap; uint16_t scd_flow; uint16_t scd_ssn; uint8_t txed; uint8_t txed_2_done; uint8_t reduced_txp; uint8_t reserved1; } __packed; /* * struct iwm_mac_beacon_cmd - beacon template command * @tx: the tx commands associated with the beacon frame * @template_id: currently equal to the mac context id of the coresponding * mac. * @tim_idx: the offset of the tim IE in the beacon * @tim_size: the length of the tim IE * @frame: the template of the beacon frame */ struct iwm_mac_beacon_cmd { struct iwm_tx_cmd tx; uint32_t template_id; uint32_t tim_idx; uint32_t tim_size; struct ieee80211_frame frame[0]; } __packed; struct iwm_beacon_notif { struct iwm_tx_resp beacon_notify_hdr; uint64_t tsf; uint32_t ibss_mgr_status; } __packed; /** * dump (flush) control flags * @IWM_DUMP_TX_FIFO_FLUSH: Dump MSDUs until the FIFO is empty * and the TFD queues are empty. */ #define IWM_DUMP_TX_FIFO_FLUSH (1 << 1) /** * struct iwm_tx_path_flush_cmd -- queue/FIFO flush command * @queues_ctl: bitmap of queues to flush * @flush_ctl: control flags * @reserved: reserved */ struct iwm_tx_path_flush_cmd_v1 { uint32_t queues_ctl; uint16_t flush_ctl; uint16_t reserved; } __packed; /* IWM_TX_PATH_FLUSH_CMD_API_S_VER_1 */ /** * struct iwl_tx_path_flush_cmd -- queue/FIFO flush command * @sta_id: station ID to flush * @tid_mask: TID mask to flush * @reserved: reserved */ struct iwm_tx_path_flush_cmd { uint32_t sta_id; uint16_t tid_mask; uint16_t reserved; } __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_2 */ /** * iwm_get_scd_ssn - returns the SSN of the SCD * @tx_resp: the Tx response from the fw (agg or non-agg) * * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since * it can't know that everything will go well until the end of the AMPDU, it * can't know in advance the number of MPDUs that will be sent in the current * batch. This is why it writes the agg Tx response while it fetches the MPDUs. * Hence, it can't know in advance what the SSN of the SCD will be at the end * of the batch. This is why the SSN of the SCD is written at the end of the * whole struct at a variable offset. This function knows how to cope with the * variable offset and returns the SSN of the SCD. */ static inline uint32_t iwm_get_scd_ssn(struct iwm_tx_resp *tx_resp) { return le32_to_cpup((uint32_t *)&tx_resp->status + tx_resp->frame_count) & 0xfff; } /** * struct iwm_scd_txq_cfg_cmd - New txq hw scheduler config command * @token: * @sta_id: station id * @tid: * @scd_queue: scheduler queue to confiug * @enable: 1 queue enable, 0 queue disable * @aggregate: 1 aggregated queue, 0 otherwise * @tx_fifo: %enum iwm_tx_fifo * @window: BA window size * @ssn: SSN for the BA agreement */ struct iwm_scd_txq_cfg_cmd { uint8_t token; uint8_t sta_id; uint8_t tid; uint8_t scd_queue; uint8_t enable; uint8_t aggregate; uint8_t tx_fifo; uint8_t window; uint16_t ssn; uint16_t reserved; } __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */ /** * struct iwm_scd_txq_cfg_rsp * @token: taken from the command * @sta_id: station id from the command * @tid: tid from the command * @scd_queue: scd_queue from the command */ struct iwm_scd_txq_cfg_rsp { uint8_t token; uint8_t sta_id; uint8_t tid; uint8_t scd_queue; } __packed; /* SCD_QUEUE_CFG_RSP_API_S_VER_1 */ struct iwm_txq_scd_cfg { uint8_t fifo; uint8_t sta_id; uint8_t tid; bool aggregate; int frame_limit; }; const uint8_t tid_to_mac80211_ac[] = { EDCA_AC_BE, EDCA_AC_BK, EDCA_AC_BK, EDCA_AC_BE, EDCA_AC_VI, EDCA_AC_VI, EDCA_AC_VO, EDCA_AC_VO, EDCA_AC_VO, /* We treat MGMT as TID 8, which is set as AC_VO */ }; /* Scan Commands, Responses, Notifications */ /* Max number of IEs for direct SSID scans in a command */ #define IWM_PROBE_OPTION_MAX 20 /** * struct iwm_ssid_ie - directed scan network information element * * Up to 20 of these may appear in IWM_REPLY_SCAN_CMD, * selected by "type" bit field in struct iwm_scan_channel; * each channel may select different ssids from among the 20 entries. * SSID IEs get transmitted in reverse order of entry. */ struct iwm_ssid_ie { uint8_t id; uint8_t len; uint8_t ssid[IEEE80211_NWID_LEN]; } __packed; /* IWM_SCAN_DIRECT_SSID_IE_API_S_VER_1 */ /* scan offload */ #define IWM_SCAN_MAX_BLACKLIST_LEN 64 #define IWM_SCAN_SHORT_BLACKLIST_LEN 16 #define IWM_SCAN_MAX_PROFILES 11 #define IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE 512 /* Default watchdog (in MS) for scheduled scan iteration */ #define IWM_SCHED_SCAN_WATCHDOG cpu_to_le16(15000) #define IWM_GOOD_CRC_TH_DEFAULT cpu_to_le16(1) #define IWM_CAN_ABORT_STATUS 1 #define IWM_FULL_SCAN_MULTIPLIER 5 #define IWM_FAST_SCHED_SCAN_ITERATIONS 3 #define IWM_MAX_SCHED_SCAN_PLANS 2 /** * iwm_scan_schedule_lmac - schedule of scan offload * @delay: delay between iterations, in seconds. * @iterations: num of scan iterations * @full_scan_mul: number of partial scans before each full scan */ struct iwm_scan_schedule_lmac { uint16_t delay; uint8_t iterations; uint8_t full_scan_mul; } __packed; /* SCAN_SCHEDULE_API_S */ /** * iwm_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S * @tx_flags: combination of TX_CMD_FLG_* * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* * @sta_id: index of destination station in FW station table * @reserved: for alignment and future use */ struct iwm_scan_req_tx_cmd { uint32_t tx_flags; uint32_t rate_n_flags; uint8_t sta_id; uint8_t reserved[3]; } __packed; #define IWM_UNIFIED_SCAN_CHANNEL_FULL (1 << 27) #define IWM_UNIFIED_SCAN_CHANNEL_PARTIAL (1 << 28) /** * iwm_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2 * @flags: bits 1-20: directed scan to i'th ssid * other bits &enum iwm_scan_channel_flags_lmac * @channel_number: channel number 1-13 etc * @iter_count: scan iteration on this channel * @iter_interval: interval in seconds between iterations on one channel */ struct iwm_scan_channel_cfg_lmac { uint32_t flags; uint16_t channel_num; uint16_t iter_count; uint32_t iter_interval; } __packed; /* * iwm_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1 * @offset: offset in the data block * @len: length of the segment */ struct iwm_scan_probe_segment { uint16_t offset; uint16_t len; } __packed; /* iwm_scan_probe_req - PROBE_REQUEST_FRAME_API_S_VER_2 * @mac_header: first (and common) part of the probe * @band_data: band specific data * @common_data: last (and common) part of the probe * @buf: raw data block */ struct iwm_scan_probe_req_v1 { struct iwm_scan_probe_segment mac_header; struct iwm_scan_probe_segment band_data[2]; struct iwm_scan_probe_segment common_data; uint8_t buf[IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE]; } __packed; /* iwl_scan_probe_req - PROBE_REQUEST_FRAME_API_S_VER_v2 * @mac_header: first (and common) part of the probe * @band_data: band specific data * @common_data: last (and common) part of the probe * @buf: raw data block */ struct iwm_scan_probe_req { struct iwm_scan_probe_segment mac_header; struct iwm_scan_probe_segment band_data[3]; struct iwm_scan_probe_segment common_data; uint8_t buf[IWM_SCAN_OFFLOAD_PROBE_REQ_SIZE]; } __packed; #define IWM_SCAN_CHANNEL_FLAG_EBS (1 << 0) #define IWM_SCAN_CHANNEL_FLAG_EBS_ACCURATE (1 << 1) #define IWM_SCAN_CHANNEL_FLAG_CACHE_ADD (1 << 2) /* iwm_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S * @flags: enum iwm_scan_channel_flags * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is * involved. * 1 - EBS is disabled. * 2 - every second scan will be full scan(and so on). */ struct iwm_scan_channel_opt { uint16_t flags; uint16_t non_ebs_ratio; } __packed; /** * LMAC scan flags * @IWM_LMAC_SCAN_FLAG_PASS_ALL: pass all beacons and probe responses * without filtering. * @IWM_LMAC_SCAN_FLAG_PASSIVE: force passive scan on all channels * @IWM_LMAC_SCAN_FLAG_PRE_CONNECTION: single channel scan * @IWM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification * @IWM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching * @IWM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented * @IWM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report * and DS parameter set IEs into probe requests. * @IWM_LMAC_SCAN_FLAG_EXTENDED_DWELL: use extended dwell time on channels * 1, 6 and 11. * @IWM_LMAC_SCAN_FLAG_MATCH: Send match found notification on matches */ #define IWM_LMAC_SCAN_FLAG_PASS_ALL (1 << 0) #define IWM_LMAC_SCAN_FLAG_PASSIVE (1 << 1) #define IWM_LMAC_SCAN_FLAG_PRE_CONNECTION (1 << 2) #define IWM_LMAC_SCAN_FLAG_ITER_COMPLETE (1 << 3) #define IWM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS (1 << 4) #define IWM_LMAC_SCAN_FLAG_FRAGMENTED (1 << 5) #define IWM_LMAC_SCAN_FLAGS_RRM_ENABLED (1 << 6) #define IWM_LMAC_SCAN_FLAG_EXTENDED_DWELL (1 << 7) #define IWM_LMAC_SCAN_FLAG_MATCH (1 << 9) #define IWM_SCAN_PRIORITY_LOW 0 #define IWM_SCAN_PRIORITY_MEDIUM 1 #define IWM_SCAN_PRIORITY_HIGH 2 /** * iwm_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1 * @reserved1: for alignment and future use * @channel_num: num of channels to scan * @active-dwell: dwell time for active channels * @passive-dwell: dwell time for passive channels * @fragmented-dwell: dwell time for fragmented passive scan * @extended_dwell: dwell time for channels 1, 6 and 11 (in certain cases) * @reserved2: for alignment and future use * @rx_chain_selct: PHY_RX_CHAIN_* flags * @scan_flags: &enum iwm_lmac_scan_flags * @max_out_time: max time (in TU) to be out of associated channel * @suspend_time: pause scan this long (TUs) when returning to service channel * @flags: RXON flags * @filter_flags: RXON filter * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz * @direct_scan: list of SSIDs for directed active scan * @scan_prio: enum iwm_scan_priority * @iter_num: number of scan iterations * @delay: delay in seconds before first iteration * @schedule: two scheduling plans. The first one is finite, the second one can * be infinite. * @channel_opt: channel optimization options, for full and partial scan * @data: channel configuration and probe request packet. */ struct iwm_scan_req_lmac { /* SCAN_REQUEST_FIXED_PART_API_S_VER_7 */ uint32_t reserved1; uint8_t n_channels; uint8_t active_dwell; uint8_t passive_dwell; uint8_t fragmented_dwell; uint8_t extended_dwell; uint8_t reserved2; uint16_t rx_chain_select; uint32_t scan_flags; uint32_t max_out_time; uint32_t suspend_time; /* RX_ON_FLAGS_API_S_VER_1 */ uint32_t flags; uint32_t filter_flags; struct iwm_scan_req_tx_cmd tx_cmd[2]; struct iwm_ssid_ie direct_scan[IWM_PROBE_OPTION_MAX]; uint32_t scan_prio; /* SCAN_REQ_PERIODIC_PARAMS_API_S */ uint32_t iter_num; uint32_t delay; struct iwm_scan_schedule_lmac schedule[IWM_MAX_SCHED_SCAN_PLANS]; struct iwm_scan_channel_opt channel_opt[2]; uint8_t data[]; } __packed; /** * iwm_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 * @last_schedule_line: last schedule line executed (fast or regular) * @last_schedule_iteration: last scan iteration executed before scan abort * @status: enum iwm_scan_offload_complete_status * @ebs_status: EBS success status &enum iwm_scan_ebs_status * @time_after_last_iter; time in seconds elapsed after last iteration */ struct iwm_periodic_scan_complete { uint8_t last_schedule_line; uint8_t last_schedule_iteration; uint8_t status; uint8_t ebs_status; uint32_t time_after_last_iter; uint32_t reserved; } __packed; /** * struct iwm_scan_results_notif - scan results for one channel - * SCAN_RESULT_NTF_API_S_VER_3 * @channel: which channel the results are from * @band: 0 for 5.2 GHz, 1 for 2.4 GHz * @probe_status: IWM_SCAN_PROBE_STATUS_*, indicates success of probe request * @num_probe_not_sent: # of request that weren't sent due to not enough time * @duration: duration spent in channel, in usecs */ struct iwm_scan_results_notif { uint8_t channel; uint8_t band; uint8_t probe_status; uint8_t num_probe_not_sent; uint32_t duration; } __packed; #define IWM_SCAN_CLIENT_SCHED_SCAN (1 << 0) #define IWM_SCAN_CLIENT_NETDETECT (1 << 1) #define IWM_SCAN_CLIENT_ASSET_TRACKING (1 << 2) /** * iwm_scan_offload_blacklist - IWM_SCAN_OFFLOAD_BLACKLIST_S * @ssid: MAC address to filter out * @reported_rssi: AP rssi reported to the host * @client_bitmap: clients ignore this entry - enum scan_framework_client */ struct iwm_scan_offload_blacklist { uint8_t ssid[ETHER_ADDR_LEN]; uint8_t reported_rssi; uint8_t client_bitmap; } __packed; #define IWM_NETWORK_TYPE_BSS 1 #define IWM_NETWORK_TYPE_IBSS 2 #define IWM_NETWORK_TYPE_ANY 3 #define IWM_SCAN_OFFLOAD_SELECT_2_4 0x4 #define IWM_SCAN_OFFLOAD_SELECT_5_2 0x8 #define IWM_SCAN_OFFLOAD_SELECT_ANY 0xc /** * iwm_scan_offload_profile - IWM_SCAN_OFFLOAD_PROFILE_S * @ssid_index: index to ssid list in fixed part * @unicast_cipher: encryption olgorithm to match - bitmap * @aut_alg: authentication olgorithm to match - bitmap * @network_type: enum iwm_scan_offload_network_type * @band_selection: enum iwm_scan_offload_band_selection * @client_bitmap: clients waiting for match - enum scan_framework_client */ struct iwm_scan_offload_profile { uint8_t ssid_index; uint8_t unicast_cipher; uint8_t auth_alg; uint8_t network_type; uint8_t band_selection; uint8_t client_bitmap; uint8_t reserved[2]; } __packed; /** * iwm_scan_offload_profile_cfg - IWM_SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1 * @blaclist: AP list to filter off from scan results * @profiles: profiles to search for match * @blacklist_len: length of blacklist * @num_profiles: num of profiles in the list * @match_notify: clients waiting for match found notification * @pass_match: clients waiting for the results * @active_clients: active clients bitmap - enum scan_framework_client * @any_beacon_notify: clients waiting for match notification without match */ struct iwm_scan_offload_profile_cfg { struct iwm_scan_offload_profile profiles[IWM_SCAN_MAX_PROFILES]; uint8_t blacklist_len; uint8_t num_profiles; uint8_t match_notify; uint8_t pass_match; uint8_t active_clients; uint8_t any_beacon_notify; uint8_t reserved[2]; } __packed; #define IWM_SCAN_OFFLOAD_COMPLETED 1 #define IWM_SCAN_OFFLOAD_ABORTED 2 /** * struct iwm_lmac_scan_complete_notif - notifies end of scanning (all channels) * SCAN_COMPLETE_NTF_API_S_VER_3 * @scanned_channels: number of channels scanned (and number of valid results) * @status: one of SCAN_COMP_STATUS_* * @bt_status: BT on/off status * @last_channel: last channel that was scanned * @tsf_low: TSF timer (lower half) in usecs * @tsf_high: TSF timer (higher half) in usecs * @results: an array of scan results, only "scanned_channels" of them are valid */ struct iwm_lmac_scan_complete_notif { uint8_t scanned_channels; uint8_t status; uint8_t bt_status; uint8_t last_channel; uint32_t tsf_low; uint32_t tsf_high; struct iwm_scan_results_notif results[]; } __packed; /* UMAC Scan API */ /* The maximum of either of these cannot exceed 8, because we use an * 8-bit mask (see IWM_SCAN_MASK). */ #define IWM_MAX_UMAC_SCANS 8 #define IWM_MAX_LMAC_SCANS 1 #define IWM_SCAN_CONFIG_FLAG_ACTIVATE (1 << 0) #define IWM_SCAN_CONFIG_FLAG_DEACTIVATE (1 << 1) #define IWM_SCAN_CONFIG_FLAG_FORBID_CHUB_REQS (1 << 2) #define IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS (1 << 3) #define IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS (1 << 8) #define IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS (1 << 9) #define IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID (1 << 10) #define IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES (1 << 11) #define IWM_SCAN_CONFIG_FLAG_SET_EFFECTIVE_TIMES (1 << 12) #define IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS (1 << 13) #define IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES (1 << 14) #define IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR (1 << 15) #define IWM_SCAN_CONFIG_FLAG_SET_FRAGMENTED (1 << 16) #define IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED (1 << 17) #define IWM_SCAN_CONFIG_FLAG_SET_CAM_MODE (1 << 18) #define IWM_SCAN_CONFIG_FLAG_CLEAR_CAM_MODE (1 << 19) #define IWM_SCAN_CONFIG_FLAG_SET_PROMISC_MODE (1 << 20) #define IWM_SCAN_CONFIG_FLAG_CLEAR_PROMISC_MODE (1 << 21) /* Bits 26-31 are for num of channels in channel_array */ #define IWM_SCAN_CONFIG_N_CHANNELS(n) ((n) << 26) /* OFDM basic rates */ #define IWM_SCAN_CONFIG_RATE_6M (1 << 0) #define IWM_SCAN_CONFIG_RATE_9M (1 << 1) #define IWM_SCAN_CONFIG_RATE_12M (1 << 2) #define IWM_SCAN_CONFIG_RATE_18M (1 << 3) #define IWM_SCAN_CONFIG_RATE_24M (1 << 4) #define IWM_SCAN_CONFIG_RATE_36M (1 << 5) #define IWM_SCAN_CONFIG_RATE_48M (1 << 6) #define IWM_SCAN_CONFIG_RATE_54M (1 << 7) /* CCK basic rates */ #define IWM_SCAN_CONFIG_RATE_1M (1 << 8) #define IWM_SCAN_CONFIG_RATE_2M (1 << 9) #define IWM_SCAN_CONFIG_RATE_5M (1 << 10) #define IWM_SCAN_CONFIG_RATE_11M (1 << 11) /* Bits 16-27 are for supported rates */ #define IWM_SCAN_CONFIG_SUPPORTED_RATE(rate) ((rate) << 16) #define IWM_CHANNEL_FLAG_EBS (1 << 0) #define IWM_CHANNEL_FLAG_ACCURATE_EBS (1 << 1) #define IWM_CHANNEL_FLAG_EBS_ADD (1 << 2) #define IWM_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE (1 << 3) /** * struct iwm_scan_config * @flags: enum scan_config_flags * @tx_chains: valid_tx antenna - ANT_* definitions * @rx_chains: valid_rx antenna - ANT_* definitions * @legacy_rates: default legacy rates - enum scan_config_rates * @out_of_channel_time: default max out of serving channel time * @suspend_time: default max suspend time * @dwell_active: default dwell time for active scan * @dwell_passive: default dwell time for passive scan * @dwell_fragmented: default dwell time for fragmented scan * @dwell_extended: default dwell time for channels 1, 6 and 11 * @mac_addr: default mac address to be used in probes * @bcast_sta_id: the index of the station in the fw * @channel_flags: default channel flags - enum iwm_channel_flags * scan_config_channel_flag * @channel_array: default supported channels */ struct iwm_scan_config { uint32_t flags; uint32_t tx_chains; uint32_t rx_chains; uint32_t legacy_rates; uint32_t out_of_channel_time; uint32_t suspend_time; uint8_t dwell_active; uint8_t dwell_passive; uint8_t dwell_fragmented; uint8_t dwell_extended; uint8_t mac_addr[ETHER_ADDR_LEN]; uint8_t bcast_sta_id; uint8_t channel_flags; uint8_t channel_array[]; } __packed; /* SCAN_CONFIG_DB_CMD_API_S */ /** * iwm_umac_scan_flags *@IWM_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request * can be preempted by other scan requests with higher priority. * The low priority scan will be resumed when the higher proirity scan is * completed. *@IWM_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver * when scan starts. */ #define IWM_UMAC_SCAN_FLAG_PREEMPTIVE (1 << 0) #define IWM_UMAC_SCAN_FLAG_START_NOTIF (1 << 1) #define IWM_UMAC_SCAN_UID_TYPE_OFFSET 0 #define IWM_UMAC_SCAN_UID_SEQ_OFFSET 8 #define IWM_UMAC_SCAN_GEN_FLAGS_PERIODIC (1 << 0) #define IWM_UMAC_SCAN_GEN_FLAGS_OVER_BT (1 << 1) #define IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL (1 << 2) #define IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE (1 << 3) #define IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT (1 << 4) #define IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE (1 << 5) #define IWM_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID (1 << 6) #define IWM_UMAC_SCAN_GEN_FLAGS_FRAGMENTED (1 << 7) #define IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED (1 << 8) #define IWM_UMAC_SCAN_GEN_FLAGS_MATCH (1 << 9) #define IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL (1 << 10) /* Extended dwell is obselete when adaptive dwell is used, making this * bit reusable. Hence, probe request defer is used only when adaptive * dwell is supported. */ #define IWM_UMAC_SCAN_GEN_FLAGS_PROB_REQ_DEFER_SUPP (1 << 10) #define IWM_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED (1 << 11) #define IWM_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL (1 << 13) #define IWM_UMAC_SCAN_GEN_FLAGS_MAX_CHNL_TIME (1 << 14) #define IWM_UMAC_SCAN_GEN_FLAGS_PROB_REQ_HIGH_TX_RATE (1 << 15) /** * UMAC scan general flags #2 * @IWM_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL: Whether to send a complete * notification per channel or not. * @IWM_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER: Whether to allow channel * reorder optimization or not. */ #define IWM_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL (1 << 0) #define IWM_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER (1 << 1) /** * struct iwm_scan_channel_cfg_umac * @flags: bitmap - 0-19: directed scan to i'th ssid. * @channel_num: channel number 1-13 etc. * @iter_count: repetition count for the channel. * @iter_interval: interval between two scan iterations on one channel. */ struct iwm_scan_channel_cfg_umac { uint32_t flags; uint8_t channel_num; uint8_t iter_count; uint16_t iter_interval; } __packed; /* SCAN_CHANNEL_CFG_S_VER1 */ /** * struct iwm_scan_umac_schedule * @interval: interval in seconds between scan iterations * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop * @reserved: for alignment and future use */ struct iwm_scan_umac_schedule { uint16_t interval; uint8_t iter_count; uint8_t reserved; } __packed; /* SCAN_SCHED_PARAM_API_S_VER_1 */ /** * struct iwm_scan_req_umac_tail - the rest of the UMAC scan request command * parameters following channels configuration array. * @schedule: two scheduling plans. * @delay: delay in TUs before starting the first scan iteration * @reserved: for future use and alignment * @preq: probe request with IEs blocks * @direct_scan: list of SSIDs for directed active scan */ struct iwm_scan_req_umac_tail_v1 { /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ struct iwm_scan_umac_schedule schedule[IWM_MAX_SCHED_SCAN_PLANS]; uint16_t delay; uint16_t reserved; /* SCAN_PROBE_PARAMS_API_S_VER_1 */ struct iwm_scan_probe_req_v1 preq; struct iwm_ssid_ie direct_scan[IWM_PROBE_OPTION_MAX]; } __packed; /** * struct iwm_scan_req_umac_tail - the rest of the UMAC scan request command * parameters following channels configuration array. * @schedule: two scheduling plans. * @delay: delay in TUs before starting the first scan iteration * @reserved: for future use and alignment * @preq: probe request with IEs blocks * @direct_scan: list of SSIDs for directed active scan */ struct iwm_scan_req_umac_tail_v2 { /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ struct iwm_scan_umac_schedule schedule[IWM_MAX_SCHED_SCAN_PLANS]; uint16_t delay; uint16_t reserved; /* SCAN_PROBE_PARAMS_API_S_VER_2 */ struct iwm_scan_probe_req preq; struct iwm_ssid_ie direct_scan[IWM_PROBE_OPTION_MAX]; } __packed; /** * struct iwm_scan_umac_chan_param * @flags: channel flags &enum iwl_scan_channel_flags * @count: num of channels in scan request * @reserved: for future use and alignment */ struct iwm_scan_umac_chan_param { uint8_t flags; uint8_t count; uint16_t reserved; } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ #define IWM_SCAN_LB_LMAC_IDX 0 #define IWM_SCAN_HB_LMAC_IDX 1 /** * struct iwm_scan_req_umac * @flags: &enum iwl_umac_scan_flags * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @general_flags: &enum iwl_umac_scan_general_flags * @scan_start_mac_id: report the scan start TSF time according to this mac TSF * @extended_dwell: dwell time for channels 1, 6 and 11 * @active_dwell: dwell time for active scan per LMAC * @passive_dwell: dwell time for passive scan per LMAC * @fragmented_dwell: dwell time for fragmented passive scan * @adwell_default_n_aps: for adaptive dwell the default number of APs * per channel * @adwell_default_n_aps_social: for adaptive dwell the default * number of APs per social (1,6,11) channel * @general_flags2: &enum iwl_umac_scan_general_flags2 * @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added * to total scan time * @max_out_time: max out of serving channel time, per LMAC - for CDB there * are 2 LMACs (high band and low band) * @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs * @scan_priority: scan internal prioritization &enum iwl_scan_priority * @num_of_fragments: Number of fragments needed for full coverage per band. * Relevant only for fragmented scan. * @channel: &struct iwm_scan_umac_chan_param * @reserved: for future use and alignment * @reserved3: for future use and alignment * @data: &struct iwm_scan_channel_cfg_umac and * &struct iwm_scan_req_umac_tail */ struct iwm_scan_req_umac { uint32_t flags; uint32_t uid; uint32_t ooc_priority; /* SCAN_GENERAL_PARAMS_API_S_VER_1 */ uint16_t general_flags; uint8_t reserved; uint8_t scan_start_mac_id; union { struct { uint8_t extended_dwell; uint8_t active_dwell; uint8_t passive_dwell; uint8_t fragmented_dwell; uint32_t max_out_time; uint32_t suspend_time; uint32_t scan_priority; struct iwm_scan_umac_chan_param channel; uint8_t data[]; } v1; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ struct { uint8_t extended_dwell; uint8_t active_dwell; uint8_t passive_dwell; uint8_t fragmented_dwell; uint32_t max_out_time[2]; uint32_t suspend_time[2]; uint32_t scan_priority; struct iwm_scan_umac_chan_param channel; uint8_t data[]; } v6; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_6 */ struct { uint8_t active_dwell; uint8_t passive_dwell; uint8_t fragmented_dwell; uint8_t adwell_default_n_aps; uint8_t adwell_default_n_aps_social; uint8_t reserved3; uint16_t adwell_max_budget; uint32_t max_out_time[2]; uint32_t suspend_time[2]; uint32_t scan_priority; struct iwm_scan_umac_chan_param channel; uint8_t data[]; } v7; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_7 */ struct { uint8_t active_dwell[2]; uint8_t reserved2; uint8_t adwell_default_n_aps; uint8_t adwell_default_n_aps_social; uint8_t general_flags2; uint16_t adwell_max_budget; uint32_t max_out_time[2]; uint32_t suspend_time[2]; uint32_t scan_priority; uint8_t passive_dwell[2]; uint8_t num_of_fragments[2]; struct iwm_scan_umac_chan_param channel; uint8_t data[]; } v8; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_8 */ struct { uint8_t active_dwell[2]; uint8_t adwell_default_hb_n_aps; uint8_t adwell_default_lb_n_aps; uint8_t adwell_default_n_aps_social; uint8_t general_flags2; uint16_t adwell_max_budget; uint32_t max_out_time[2]; uint32_t suspend_time[2]; uint32_t scan_priority; uint8_t passive_dwell[2]; uint8_t num_of_fragments[2]; struct iwm_scan_umac_chan_param channel; uint8_t data[]; } v9; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_9 */ }; } __packed; #define IWM_SCAN_REQ_UMAC_SIZE_V8 sizeof(struct iwm_scan_req_umac) #define IWM_SCAN_REQ_UMAC_SIZE_V7 48 #define IWM_SCAN_REQ_UMAC_SIZE_V6 44 #define IWM_SCAN_REQ_UMAC_SIZE_V1 36 /** * struct iwm_umac_scan_abort * @uid: scan id, &enum iwm_umac_scan_uid_offsets * @flags: reserved */ struct iwm_umac_scan_abort { uint32_t uid; uint32_t flags; } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ /** * struct iwm_umac_scan_complete * @uid: scan id, &enum iwm_umac_scan_uid_offsets * @last_schedule: last scheduling line * @last_iter: last scan iteration number * @scan status: &enum iwm_scan_offload_complete_status * @ebs_status: &enum iwm_scan_ebs_status * @time_from_last_iter: time elapsed from last iteration * @reserved: for future use */ struct iwm_umac_scan_complete { uint32_t uid; uint8_t last_schedule; uint8_t last_iter; uint8_t status; uint8_t ebs_status; uint32_t time_from_last_iter; uint32_t reserved; } __packed; /* SCAN_COMPLETE_NTF_UMAC_API_S_VER_1 */ #define IWM_SCAN_OFFLOAD_MATCHING_CHANNELS_LEN 5 /** * struct iwm_scan_offload_profile_match - match information * @bssid: matched bssid * @channel: channel where the match occurred * @energy: * @matching_feature: * @matching_channels: bitmap of channels that matched, referencing * the channels passed in tue scan offload request */ struct iwm_scan_offload_profile_match { uint8_t bssid[ETHER_ADDR_LEN]; uint16_t reserved; uint8_t channel; uint8_t energy; uint8_t matching_feature; uint8_t matching_channels[IWM_SCAN_OFFLOAD_MATCHING_CHANNELS_LEN]; } __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_1 */ /** * struct iwm_scan_offload_profiles_query - match results query response * @matched_profiles: bitmap of matched profiles, referencing the * matches passed in the scan offload request * @last_scan_age: age of the last offloaded scan * @n_scans_done: number of offloaded scans done * @gp2_d0u: GP2 when D0U occurred * @gp2_invoked: GP2 when scan offload was invoked * @resume_while_scanning: not used * @self_recovery: obsolete * @reserved: reserved * @matches: array of match information, one for each match */ struct iwm_scan_offload_profiles_query { uint32_t matched_profiles; uint32_t last_scan_age; uint32_t n_scans_done; uint32_t gp2_d0u; uint32_t gp2_invoked; uint8_t resume_while_scanning; uint8_t self_recovery; uint16_t reserved; struct iwm_scan_offload_profile_match matches[IWM_SCAN_MAX_PROFILES]; } __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */ /** * struct iwm_umac_scan_iter_complete_notif - notifies end of scanning iteration * @uid: scan id, &enum iwm_umac_scan_uid_offsets * @scanned_channels: number of channels scanned and number of valid elements in * results array * @status: one of SCAN_COMP_STATUS_* * @bt_status: BT on/off status * @last_channel: last channel that was scanned * @tsf_low: TSF timer (lower half) in usecs * @tsf_high: TSF timer (higher half) in usecs * @results: array of scan results, only "scanned_channels" of them are valid */ struct iwm_umac_scan_iter_complete_notif { uint32_t uid; uint8_t scanned_channels; uint8_t status; uint8_t bt_status; uint8_t last_channel; uint32_t tsf_low; uint32_t tsf_high; struct iwm_scan_results_notif results[]; } __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_1 */ #define IWM_GSCAN_START_CMD 0x0 #define IWM_GSCAN_STOP_CMD 0x1 #define IWM_GSCAN_SET_HOTLIST_CMD 0x2 #define IWM_GSCAN_RESET_HOTLIST_CMD 0x3 #define IWM_GSCAN_SET_SIGNIFICANT_CHANGE_CMD 0x4 #define IWM_GSCAN_RESET_SIGNIFICANT_CHANGE_CMD 0x5 #define IWM_GSCAN_SIGNIFICANT_CHANGE_EVENT 0xFD #define IWM_GSCAN_HOTLIST_CHANGE_EVENT 0xFE #define IWM_GSCAN_RESULTS_AVAILABLE_EVENT 0xFF /* STA API */ /** * flags for the ADD_STA host command * @IWM_STA_FLG_REDUCED_TX_PWR_CTRL: * @IWM_STA_FLG_REDUCED_TX_PWR_DATA: * @IWM_STA_FLG_DISABLE_TX: set if TX should be disabled * @IWM_STA_FLG_PS: set if STA is in Power Save * @IWM_STA_FLG_INVALID: set if STA is invalid * @IWM_STA_FLG_DLP_EN: Direct Link Protocol is enabled * @IWM_STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs * @IWM_STA_FLG_DRAIN_FLOW: drain flow * @IWM_STA_FLG_PAN: STA is for PAN interface * @IWM_STA_FLG_CLASS_AUTH: * @IWM_STA_FLG_CLASS_ASSOC: * @IWM_STA_FLG_CLASS_MIMO_PROT: * @IWM_STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU * @IWM_STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation * @IWM_STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is * initialised by driver and can be updated by fw upon reception of * action frames that can change the channel width. When cleared the fw * will send all the frames in 20MHz even when FAT channel is requested. * @IWM_STA_FLG_MIMO_EN_MSK: support for MIMO. This flag is initialised by the * driver and can be updated by fw upon reception of action frames. * @IWM_STA_FLG_MFP_EN: Management Frame Protection */ #define IWM_STA_FLG_REDUCED_TX_PWR_CTRL (1 << 3) #define IWM_STA_FLG_REDUCED_TX_PWR_DATA (1 << 6) #define IWM_STA_FLG_DISABLE_TX (1 << 4) #define IWM_STA_FLG_PS (1 << 8) #define IWM_STA_FLG_DRAIN_FLOW (1 << 12) #define IWM_STA_FLG_PAN (1 << 13) #define IWM_STA_FLG_CLASS_AUTH (1 << 14) #define IWM_STA_FLG_CLASS_ASSOC (1 << 15) #define IWM_STA_FLG_RTS_MIMO_PROT (1 << 17) #define IWM_STA_FLG_MAX_AGG_SIZE_SHIFT 19 #define IWM_STA_FLG_MAX_AGG_SIZE_8K (0 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_16K (1 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_32K (2 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_64K (3 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_128K (4 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_256K (5 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_512K (6 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_1024K (7 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_2M (8 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_4M (9 << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_MAX_AGG_SIZE_MSK (0xf << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWM_STA_FLG_AGG_MPDU_DENS_SHIFT 23 #define IWM_STA_FLG_AGG_MPDU_DENS_2US (4 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWM_STA_FLG_AGG_MPDU_DENS_4US (5 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWM_STA_FLG_AGG_MPDU_DENS_8US (6 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWM_STA_FLG_AGG_MPDU_DENS_16US (7 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWM_STA_FLG_AGG_MPDU_DENS_MSK (7 << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWM_STA_FLG_FAT_EN_20MHZ (0 << 26) #define IWM_STA_FLG_FAT_EN_40MHZ (1 << 26) #define IWM_STA_FLG_FAT_EN_80MHZ (2 << 26) #define IWM_STA_FLG_FAT_EN_160MHZ (3 << 26) #define IWM_STA_FLG_FAT_EN_MSK (3 << 26) #define IWM_STA_FLG_MIMO_EN_SISO (0 << 28) #define IWM_STA_FLG_MIMO_EN_MIMO2 (1 << 28) #define IWM_STA_FLG_MIMO_EN_MIMO3 (2 << 28) #define IWM_STA_FLG_MIMO_EN_MSK (3 << 28) /** * key flags for the ADD_STA host command * @IWM_STA_KEY_FLG_NO_ENC: no encryption * @IWM_STA_KEY_FLG_WEP: WEP encryption algorithm * @IWM_STA_KEY_FLG_CCM: CCMP encryption algorithm * @IWM_STA_KEY_FLG_TKIP: TKIP encryption algorithm * @IWM_STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support) * @IWM_STA_KEY_FLG_CMAC: CMAC encryption algorithm * @IWM_STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm * @IWM_STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value * @IWM_STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from * station info array (1 - n 1X mode) * @IWM_STA_KEY_FLG_KEYID_MSK: the index of the key * @IWM_STA_KEY_NOT_VALID: key is invalid * @IWM_STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key * @IWM_STA_KEY_MULTICAST: set for multicast key * @IWM_STA_KEY_MFP: key is used for Management Frame Protection */ #define IWM_STA_KEY_FLG_NO_ENC (0 << 0) #define IWM_STA_KEY_FLG_WEP (1 << 0) #define IWM_STA_KEY_FLG_CCM (2 << 0) #define IWM_STA_KEY_FLG_TKIP (3 << 0) #define IWM_STA_KEY_FLG_EXT (4 << 0) #define IWM_STA_KEY_FLG_CMAC (6 << 0) #define IWM_STA_KEY_FLG_ENC_UNKNOWN (7 << 0) #define IWM_STA_KEY_FLG_EN_MSK (7 << 0) #define IWM_STA_KEY_FLG_WEP_KEY_MAP (1 << 3) #define IWM_STA_KEY_FLG_KEYID_POS 8 #define IWM_STA_KEY_FLG_KEYID_MSK (3 << IWM_STA_KEY_FLG_KEYID_POS) #define IWM_STA_KEY_NOT_VALID (1 << 11) #define IWM_STA_KEY_FLG_WEP_13BYTES (1 << 12) #define IWM_STA_KEY_MULTICAST (1 << 14) #define IWM_STA_KEY_MFP (1 << 15) /** * indicate to the fw what flag are being changed * @IWM_STA_MODIFY_QUEUE_REMOVAL: this command removes a queue * @IWM_STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx * @IWM_STA_MODIFY_TX_RATE: unused * @IWM_STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid * @IWM_STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid * @IWM_STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count * @IWM_STA_MODIFY_PROT_TH: * @IWM_STA_MODIFY_QUEUES: modify the queues used by this station */ #define IWM_STA_MODIFY_QUEUE_REMOVAL (1 << 0) #define IWM_STA_MODIFY_TID_DISABLE_TX (1 << 1) #define IWM_STA_MODIFY_TX_RATE (1 << 2) #define IWM_STA_MODIFY_ADD_BA_TID (1 << 3) #define IWM_STA_MODIFY_REMOVE_BA_TID (1 << 4) #define IWM_STA_MODIFY_SLEEPING_STA_TX_COUNT (1 << 5) #define IWM_STA_MODIFY_PROT_TH (1 << 6) #define IWM_STA_MODIFY_QUEUES (1 << 7) #define IWM_STA_MODE_MODIFY 1 /** * type of sleep of the station * @IWM_STA_SLEEP_STATE_AWAKE: * @IWM_STA_SLEEP_STATE_PS_POLL: * @IWM_STA_SLEEP_STATE_UAPSD: * @IWM_STA_SLEEP_STATE_MOREDATA: set more-data bit on * (last) released frame */ #define IWM_STA_SLEEP_STATE_AWAKE 0 #define IWM_STA_SLEEP_STATE_PS_POLL (1 << 0) #define IWM_STA_SLEEP_STATE_UAPSD (1 << 1) #define IWM_STA_SLEEP_STATE_MOREDATA (1 << 2) /* STA ID and color bits definitions */ #define IWM_STA_ID_SEED (0x0f) #define IWM_STA_ID_POS (0) #define IWM_STA_ID_MSK (IWM_STA_ID_SEED << IWM_STA_ID_POS) #define IWM_STA_COLOR_SEED (0x7) #define IWM_STA_COLOR_POS (4) #define IWM_STA_COLOR_MSK (IWM_STA_COLOR_SEED << IWM_STA_COLOR_POS) #define IWM_STA_ID_N_COLOR_GET_COLOR(id_n_color) \ (((id_n_color) & IWM_STA_COLOR_MSK) >> IWM_STA_COLOR_POS) #define IWM_STA_ID_N_COLOR_GET_ID(id_n_color) \ (((id_n_color) & IWM_STA_ID_MSK) >> IWM_STA_ID_POS) #define IWM_STA_KEY_MAX_NUM (16) #define IWM_STA_KEY_IDX_INVALID (0xff) #define IWM_STA_KEY_MAX_DATA_KEY_NUM (4) #define IWM_MAX_GLOBAL_KEYS (4) #define IWM_STA_KEY_LEN_WEP40 (5) #define IWM_STA_KEY_LEN_WEP104 (13) /** * struct iwm_keyinfo - key information * @key_flags: type %iwm_sta_key_flag * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx * @key_offset: key offset in the fw's key table * @key: 16-byte unicast decryption key * @tx_secur_seq_cnt: initial RSC / PN needed for replay check * @hw_tkip_mic_rx_key: byte: MIC Rx Key - used for TKIP only * @hw_tkip_mic_tx_key: byte: MIC Tx Key - used for TKIP only */ struct iwm_keyinfo { uint16_t key_flags; uint8_t tkip_rx_tsc_byte2; uint8_t reserved1; uint16_t tkip_rx_ttak[5]; uint8_t key_offset; uint8_t reserved2; uint8_t key[16]; uint64_t tx_secur_seq_cnt; uint64_t hw_tkip_mic_rx_key; uint64_t hw_tkip_mic_tx_key; } __packed; #define IWM_ADD_STA_STATUS_MASK 0xFF #define IWM_ADD_STA_BAID_VALID_MASK 0x8000 #define IWM_ADD_STA_BAID_MASK 0x7F00 #define IWM_ADD_STA_BAID_SHIFT 8 /** * struct iwm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) * @add_modify: 1: modify existing, 0: add new station * @awake_acs: * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %IWM_STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to * @addr[ETHER_ADDR_LEN]: station's MAC address * @sta_id: index of station in uCode's station table * @modify_mask: IWM_STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. * @station_flags: look at %iwm_sta_flags * @station_flags_msk: what of %station_flags have changed * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) * Set %IWM_STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx) * Set %IWM_STA_MODIFY_REMOVE_BA_TID to use this field * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with * add_immediate_ba_tid. * @sleep_tx_count: number of packets to transmit to station even though it is * asleep. Used to synchronise PS-poll and u-APSD responses while ucode * keeps track of STA sleep state. * @sleep_state_flags: Look at %iwm_sta_sleep_flag. * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP * mac-addr. * @beamform_flags: beam forming controls * @tfd_queue_msk: tfd queues used by this station * * The device contains an internal table of per-station information, with info * on security keys, aggregation parameters, and Tx rates for initial Tx * attempt and any retries (set by IWM_REPLY_TX_LINK_QUALITY_CMD). * * ADD_STA sets up the table entry for one station, either creating a new * entry, or modifying a pre-existing one. */ struct iwm_add_sta_cmd_v7 { uint8_t add_modify; uint8_t awake_acs; uint16_t tid_disable_tx; uint32_t mac_id_n_color; uint8_t addr[ETHER_ADDR_LEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ uint16_t reserved2; uint8_t sta_id; uint8_t modify_mask; uint16_t reserved3; uint32_t station_flags; uint32_t station_flags_msk; uint8_t add_immediate_ba_tid; uint8_t remove_immediate_ba_tid; uint16_t add_immediate_ba_ssn; uint16_t sleep_tx_count; uint16_t sleep_state_flags; uint16_t assoc_id; uint16_t beamform_flags; uint32_t tfd_queue_msk; } __packed; /* ADD_STA_CMD_API_S_VER_7 */ /** * struct iwm_add_sta_cmd - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) * @add_modify: see &enum iwl_sta_mode * @awake_acs: ACs to transmit data on while station is sleeping (for U-APSD) * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to, * see &enum iwl_ctxt_id_and_color * @addr: station's MAC address * @reserved2: reserved * @sta_id: index of station in uCode's station table * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. * @reserved3: reserved * @station_flags: look at &enum iwl_sta_flags * @station_flags_msk: what of %station_flags have changed, * also &enum iwl_sta_flags * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx) * Set %STA_MODIFY_REMOVE_BA_TID to use this field * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with * add_immediate_ba_tid. * @sleep_tx_count: number of packets to transmit to station even though it is * asleep. Used to synchronise PS-poll and u-APSD responses while ucode * keeps track of STA sleep state. * @station_type: type of this station. See &enum iwl_sta_type. * @sleep_state_flags: Look at &enum iwl_sta_sleep_flag. * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP * mac-addr. * @beamform_flags: beam forming controls * @tfd_queue_msk: tfd queues used by this station. * Obselete for new TX API (9 and above). * @rx_ba_window: aggregation window size * @sp_length: the size of the SP in actual number of frames * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver * enabled ACs. * * The device contains an internal table of per-station information, with info * on security keys, aggregation parameters, and Tx rates for initial Tx * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD). * * ADD_STA sets up the table entry for one station, either creating a new * entry, or modifying a pre-existing one. */ struct iwm_add_sta_cmd { uint8_t add_modify; uint8_t awake_acs; uint16_t tid_disable_tx; uint32_t mac_id_n_color; uint8_t addr[ETHER_ADDR_LEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ uint16_t reserved2; uint8_t sta_id; uint8_t modify_mask; uint16_t reserved3; uint32_t station_flags; uint32_t station_flags_msk; uint8_t add_immediate_ba_tid; uint8_t remove_immediate_ba_tid; uint16_t add_immediate_ba_ssn; uint16_t sleep_tx_count; uint8_t sleep_state_flags; uint8_t station_type; uint16_t assoc_id; uint16_t beamform_flags; uint32_t tfd_queue_msk; uint16_t rx_ba_window; uint8_t sp_length; uint8_t uapsd_acs; } __packed; /* ADD_STA_CMD_API_S_VER_10 */ /** * FW station types * ( REPLY_ADD_STA = 0x18 ) * @IWM_STA_LINK: Link station - normal RX and TX traffic. * @IWM_STA_GENERAL_PURPOSE: General purpose. In AP mode used for beacons * and probe responses. * @IWM_STA_MULTICAST: multicast traffic, * @IWM_STA_TDLS_LINK: TDLS link station * @IWM_STA_AUX_ACTIVITY: auxilary station (scan, ROC and so on). */ #define IWM_STA_LINK 0 #define IWM_STA_GENERAL_PURPOSE 1 #define IWM_STA_MULTICAST 2 #define IWM_STA_TDLS_LINK 3 #define IWM_STA_AUX_ACTIVITY 4 /** * struct iwm_add_sta_key_common - add/modify sta key common part * ( REPLY_ADD_STA_KEY = 0x17 ) * @sta_id: index of station in uCode's station table * @key_offset: key offset in key storage * @key_flags: IWM_STA_KEY_FLG_* * @key: key material data * @rx_secur_seq_cnt: RX security sequence counter for the key */ struct iwm_add_sta_key_common { uint8_t sta_id; uint8_t key_offset; uint16_t key_flags; uint8_t key[32]; uint8_t rx_secur_seq_cnt[16]; } __packed; /** * struct iwm_add_sta_key_cmd_v1 - add/modify sta key * @common: see &struct iwm_add_sta_key_common * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection * @reserved: reserved * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx */ struct iwm_add_sta_key_cmd_v1 { struct iwm_add_sta_key_common common; uint8_t tkip_rx_tsc_byte2; uint8_t reserved; uint16_t tkip_rx_ttak[5]; } __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_1 */ /** * struct iwm_add_sta_key_cmd - add/modify sta key * @common: see &struct iwm_add_sta_key_common * @rx_mic_key: TKIP RX unicast or multicast key * @tx_mic_key: TKIP TX key * @transmit_seq_cnt: TSC, transmit packet number */ struct iwm_add_sta_key_cmd { struct iwm_add_sta_key_common common; uint64_t rx_mic_key; uint64_t tx_mic_key; uint64_t transmit_seq_cnt; } __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_2 */ /** * status in the response to ADD_STA command * @IWM_ADD_STA_SUCCESS: operation was executed successfully * @IWM_ADD_STA_STATIONS_OVERLOAD: no room left in the fw's station table * @IWM_ADD_STA_IMMEDIATE_BA_FAILURE: can't add Rx block ack session * @IWM_ADD_STA_MODIFY_NON_EXISTING_STA: driver requested to modify a station * that doesn't exist. */ #define IWM_ADD_STA_SUCCESS 0x1 #define IWM_ADD_STA_STATIONS_OVERLOAD 0x2 #define IWM_ADD_STA_IMMEDIATE_BA_FAILURE 0x4 #define IWM_ADD_STA_MODIFY_NON_EXISTING_STA 0x8 /** * struct iwm_rm_sta_cmd - Add / modify a station in the fw's station table * ( IWM_REMOVE_STA = 0x19 ) * @sta_id: the station id of the station to be removed */ struct iwm_rm_sta_cmd { uint8_t sta_id; uint8_t reserved[3]; } __packed; /* IWM_REMOVE_STA_CMD_API_S_VER_2 */ /** * struct iwm_mgmt_mcast_key_cmd * ( IWM_MGMT_MCAST_KEY = 0x1f ) * @ctrl_flags: %iwm_sta_key_flag * @IGTK: * @K1: IGTK master key * @K2: IGTK sub key * @sta_id: station ID that support IGTK * @key_id: * @receive_seq_cnt: initial RSC/PN needed for replay check */ struct iwm_mgmt_mcast_key_cmd { uint32_t ctrl_flags; uint8_t IGTK[16]; uint8_t K1[16]; uint8_t K2[16]; uint32_t key_id; uint32_t sta_id; uint64_t receive_seq_cnt; } __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */ struct iwm_wep_key { uint8_t key_index; uint8_t key_offset; uint16_t reserved1; uint8_t key_size; uint8_t reserved2[3]; uint8_t key[16]; } __packed; struct iwm_wep_key_cmd { uint32_t mac_id_n_color; uint8_t num_keys; uint8_t decryption_type; uint8_t flags; uint8_t reserved; struct iwm_wep_key wep_key[0]; } __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */ /* * BT coex */ #define IWM_BT_COEX_DISABLE 0x0 #define IWM_BT_COEX_NW 0x1 #define IWM_BT_COEX_BT 0x2 #define IWM_BT_COEX_WIFI 0x3 /* BT_COEX_MODES_E */ #define IWM_BT_COEX_MPLUT_ENABLED (1 << 0) #define IWM_BT_COEX_MPLUT_BOOST_ENABLED (1 << 1) #define IWM_BT_COEX_SYNC2SCO_ENABLED (1 << 2) #define IWM_BT_COEX_CORUN_ENABLED (1 << 3) #define IWM_BT_COEX_HIGH_BAND_RET (1 << 4) /* BT_COEX_MODULES_ENABLE_E_VER_1 */ /** * struct iwm_bt_coex_cmd - bt coex configuration command * @mode: enum %iwm_bt_coex_mode * @enabled_modules: enum %iwm_bt_coex_enabled_modules * * The structure is used for the BT_COEX command. */ struct iwm_bt_coex_cmd { uint32_t mode; uint32_t enabled_modules; } __packed; /* BT_COEX_CMD_API_S_VER_6 */ /* * Location Aware Regulatory (LAR) API - MCC updates */ /** * struct iwm_mcc_update_cmd_v1 - Request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the * MCC in the cmd response will be the relevant MCC in the NVM. * @mcc: given mobile country code * @source_id: the source from where we got the MCC, see iwm_mcc_source * @reserved: reserved for alignment */ struct iwm_mcc_update_cmd_v1 { uint16_t mcc; uint8_t source_id; uint8_t reserved; } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */ /** * struct iwm_mcc_update_cmd - Request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the * MCC in the cmd response will be the relevant MCC in the NVM. * @mcc: given mobile country code * @source_id: the source from where we got the MCC, see iwm_mcc_source * @reserved: reserved for alignment * @key: integrity key for MCC API OEM testing * @reserved2: reserved */ struct iwm_mcc_update_cmd { uint16_t mcc; uint8_t source_id; uint8_t reserved; uint32_t key; uint32_t reserved2[5]; } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */ /** * iwm_mcc_update_resp_v1 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. * @status: see &enum iwm_mcc_update_status * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC * @source_id: the MCC source, see iwm_mcc_source * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 * channels, depending on platform) * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ struct iwm_mcc_update_resp_v1 { uint32_t status; uint16_t mcc; uint8_t cap; uint8_t source_id; uint32_t n_channels; uint32_t channels[0]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */ /** * iwm_mcc_update_resp_v2 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. * @status: see &enum iwm_mcc_update_status * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC * @source_id: the MCC source, see iwm_mcc_source * @time: time elapsed from the MCC test start (in 30 seconds TU) * @reserved: reserved. * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 * channels, depending on platform) * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ struct iwm_mcc_update_resp_v2 { uint32_t status; uint16_t mcc; uint8_t cap; uint8_t source_id; uint16_t time; uint16_t reserved; uint32_t n_channels; uint32_t channels[0]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */ #define IWM_GEO_NO_INFO 0 #define IWM_GEO_WMM_ETSI_5GHZ_INFO (1 << 0) /** * iwm_mcc_update_resp_v3 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. * @status: see &enum iwm_mcc_update_status * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC * @source_id: the MCC source, see IWM_MCC_SOURCE_* * @time: time elapsed from the MCC test start (in 30 seconds TU) * @geo_info: geographic specific profile information * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 * channels, depending on platform) * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ struct iwm_mcc_update_resp_v3 { uint32_t status; uint16_t mcc; uint8_t cap; uint8_t source_id; uint16_t time; uint16_t geo_info; uint32_t n_channels; uint32_t channels[0]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ /** * struct iwm_mcc_chub_notif - chub notifies of mcc change * (MCC_CHUB_UPDATE_CMD = 0xc9) * The Chub (Communication Hub, CommsHUB) is a HW component that connects to * the cellular and connectivity cores that gets updates of the mcc, and * notifies the ucode directly of any mcc change. * The ucode requests the driver to request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the * MCC in the cmd response will be the relevant MCC in the NVM. * @mcc: given mobile country code * @source_id: identity of the change originator, see iwm_mcc_source * @reserved1: reserved for alignment */ struct iwm_mcc_chub_notif { uint16_t mcc; uint8_t source_id; uint8_t reserved1; } __packed; /* LAR_MCC_NOTIFY_S */ #define IWM_MCC_RESP_NEW_CHAN_PROFILE 0 #define IWM_MCC_RESP_SAME_CHAN_PROFILE 1 #define IWM_MCC_RESP_INVALID 2 #define IWM_MCC_RESP_NVM_DISABLED 3 #define IWM_MCC_RESP_ILLEGAL 4 #define IWM_MCC_RESP_LOW_PRIORITY 5 #define IWM_MCC_RESP_TEST_MODE_ACTIVE 6 #define IWM_MCC_RESP_TEST_MODE_NOT_ACTIVE 7 #define IWM_MCC_RESP_TEST_MODE_DENIAL_OF_SERVICE 8 #define IWM_MCC_SOURCE_OLD_FW 0 #define IWM_MCC_SOURCE_ME 1 #define IWM_MCC_SOURCE_BIOS 2 #define IWM_MCC_SOURCE_3G_LTE_HOST 3 #define IWM_MCC_SOURCE_3G_LTE_DEVICE 4 #define IWM_MCC_SOURCE_WIFI 5 #define IWM_MCC_SOURCE_RESERVED 6 #define IWM_MCC_SOURCE_DEFAULT 7 #define IWM_MCC_SOURCE_UNINITIALIZED 8 #define IWM_MCC_SOURCE_MCC_API 9 #define IWM_MCC_SOURCE_GET_CURRENT 0x10 #define IWM_MCC_SOURCE_GETTING_MCC_TEST_MODE 0x11 /* * Some cherry-picked definitions */ #define IWM_FRAME_LIMIT 64 /* * From Linux commit ab02165ccec4c78162501acedeef1a768acdb811: * As the firmware is slowly running out of command IDs and grouping of * commands is desirable anyway, the firmware is extending the command * header from 4 bytes to 8 bytes to introduce a group (in place of the * former flags field, since that's always 0 on commands and thus can * be easily used to distinguish between the two). * * These functions retrieve specific information from the id field in * the iwm_host_cmd struct which contains the command id, the group id, * and the version of the command. */ static inline uint8_t iwm_cmd_opcode(uint32_t cmdid) { return cmdid & 0xff; } static inline uint8_t iwm_cmd_groupid(uint32_t cmdid) { return ((cmdid & 0Xff00) >> 8); } static inline uint8_t iwm_cmd_version(uint32_t cmdid) { return ((cmdid & 0xff0000) >> 16); } static inline uint32_t iwm_cmd_id(uint8_t opcode, uint8_t groupid, uint8_t version) { return opcode + (groupid << 8) + (version << 16); } /* make uint16_t wide id out of uint8_t group and opcode */ #define IWM_WIDE_ID(grp, opcode) ((grp << 8) | opcode) struct iwm_cmd_header { uint8_t code; uint8_t flags; uint8_t idx; uint8_t qid; } __packed; struct iwm_cmd_header_wide { uint8_t opcode; uint8_t group_id; uint8_t idx; uint8_t qid; uint16_t length; uint8_t reserved; uint8_t version; } __packed; #define IWM_POWER_SCHEME_CAM 1 #define IWM_POWER_SCHEME_BPS 2 #define IWM_POWER_SCHEME_LP 3 #define IWM_DEF_CMD_PAYLOAD_SIZE 320 #define IWM_MAX_CMD_PAYLOAD_SIZE ((4096 - 4) - sizeof(struct iwm_cmd_header)) #define IWM_CMD_FAILED_MSK 0x40 /** * struct iwm_device_cmd * * For allocation of the command and tx queues, this establishes the overall * size of the largest command we send to uCode, except for commands that * aren't fully copied and use other TFD space. */ struct iwm_device_cmd { union { struct { struct iwm_cmd_header hdr; uint8_t data[IWM_DEF_CMD_PAYLOAD_SIZE]; }; struct { struct iwm_cmd_header_wide hdr_wide; uint8_t data_wide[IWM_DEF_CMD_PAYLOAD_SIZE - sizeof(struct iwm_cmd_header_wide) + sizeof(struct iwm_cmd_header)]; }; }; } __packed; struct iwm_rx_packet { /* * The first 4 bytes of the RX frame header contain both the RX frame * size and some flags. * Bit fields: * 31: flag flush RB request * 30: flag ignore TC (terminal counter) request * 29: flag fast IRQ request * 28-26: Reserved * 25: Offload enabled * 24: RPF enabled * 23: RSS enabled * 22: Checksum enabled * 21-16: RX queue * 15-14: Reserved * 13-00: RX frame size */ uint32_t len_n_flags; struct iwm_cmd_header hdr; uint8_t data[]; } __packed; #define IWM_FH_RSCSR_FRAME_SIZE_MSK 0x00003fff #define IWM_FH_RSCSR_FRAME_INVALID 0x55550000 #define IWM_FH_RSCSR_FRAME_ALIGN 0x40 #define IWM_FH_RSCSR_RPA_EN (1 << 25) #define IWM_FH_RSCSR_RADA_EN (1 << 26) #define IWM_FH_RSCSR_RXQ_POS 16 #define IWM_FH_RSCSR_RXQ_MASK 0x3F0000 static uint32_t iwm_rx_packet_len(const struct iwm_rx_packet *pkt) { return le32toh(pkt->len_n_flags) & IWM_FH_RSCSR_FRAME_SIZE_MSK; } static uint32_t iwm_rx_packet_payload_len(const struct iwm_rx_packet *pkt) { return iwm_rx_packet_len(pkt) - sizeof(pkt->hdr); } #define IWM_MIN_DBM -100 #define IWM_MAX_DBM -33 /* realistic guess */ #define IWM_READ(sc, reg) \ bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg)) #define IWM_WRITE(sc, reg, val) \ bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val)) #define IWM_WRITE_1(sc, reg, val) \ bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val)) #define IWM_SETBITS(sc, reg, mask) \ IWM_WRITE(sc, reg, IWM_READ(sc, reg) | (mask)) #define IWM_CLRBITS(sc, reg, mask) \ IWM_WRITE(sc, reg, IWM_READ(sc, reg) & ~(mask)) #define IWM_BARRIER_WRITE(sc) \ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ BUS_SPACE_BARRIER_WRITE) #define IWM_BARRIER_READ_WRITE(sc) \ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) ================================================ FILE: itlwm/hal_iwm/if_iwmvar.h ================================================ /* * 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. */ /* $OpenBSD: if_iwmvar.h,v 1.57 2020/10/11 07:05:28 mpi Exp $ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * * Driver version we are currently based off of is * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd) * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include "rs.h" struct iwm_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; uint64_t wr_tsft; uint8_t wr_flags; uint8_t wr_rate; uint16_t wr_chan_freq; uint16_t wr_chan_flags; int8_t wr_dbm_antsignal; int8_t wr_dbm_antnoise; } __packed; #define IWM_RX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_TSFT) | \ (1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL) | \ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)) struct iwm_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; uint8_t wt_flags; uint8_t wt_rate; uint16_t wt_chan_freq; uint16_t wt_chan_flags; } __packed; #define IWM_TX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL)) #define IWM_UCODE_SECT_MAX 16 #define IWM_FWDMASEGSZ (192*1024) #define IWM_FWDMASEGSZ_8000 (320*1024) /* sanity check value */ #define IWM_FWMAXSIZE (2*1024*1024) /* * fw_status is used to determine if we've already parsed the firmware file * * In addition to the following, status < 0 ==> -error */ #define IWM_FW_STATUS_NONE 0 #define IWM_FW_STATUS_INPROGRESS 1 #define IWM_FW_STATUS_DONE 2 enum iwm_ucode_type { IWM_UCODE_TYPE_REGULAR, IWM_UCODE_TYPE_INIT, IWM_UCODE_TYPE_WOW, IWM_UCODE_TYPE_REGULAR_USNIFFER, IWM_UCODE_TYPE_MAX }; struct iwm_fw_onesect { void *fws_data; uint32_t fws_len; uint32_t fws_devoff; }; struct iwm_fw_sects { struct iwm_fw_onesect fw_sect[IWM_UCODE_SECT_MAX]; size_t fw_totlen; int fw_count; uint32_t paging_mem_size; }; struct iwm_fw_info { void *fw_rawdata; size_t fw_rawsize; int fw_status; struct iwm_fw_sects fw_sects[IWM_UCODE_TYPE_MAX]; }; struct iwm_nvm_data { int n_hw_addrs; uint8_t hw_addr[ETHER_ADDR_LEN]; uint8_t calib_version; uint16_t calib_voltage; uint16_t raw_temperature; uint16_t kelvin_temperature; uint16_t kelvin_voltage; uint16_t xtal_calib[2]; int sku_cap_band_24GHz_enable; int sku_cap_band_52GHz_enable; int sku_cap_11n_enable; int sku_cap_11ac_enable; int sku_cap_amt_enable; int sku_cap_ipan_enable; int sku_cap_mimo_disable; uint8_t radio_cfg_type; uint8_t radio_cfg_step; uint8_t radio_cfg_dash; uint8_t radio_cfg_pnum; uint8_t valid_tx_ant, valid_rx_ant; bool vht160_supported; uint16_t nvm_version; uint8_t max_tx_pwr_half_dbm; int lar_enabled; }; /* max bufs per tfd the driver will use */ #define IWM_MAX_CMD_TBS_PER_TFD 2 struct iwm_host_cmd { const void *data[IWM_MAX_CMD_TBS_PER_TFD]; struct iwm_rx_packet *resp_pkt; size_t resp_pkt_len; unsigned long _rx_page_addr; uint32_t _rx_page_order; int handler_status; uint32_t flags; uint16_t len[IWM_MAX_CMD_TBS_PER_TFD]; uint8_t dataflags[IWM_MAX_CMD_TBS_PER_TFD]; uint32_t id; }; /* * DMA glue is from iwn */ struct iwm_dma_info { IOBufferMemoryDescriptor* buffer; bus_addr_t paddr; void *vaddr; size_t size; IODMACommand *cmd; }; /** * struct iwm_fw_paging * @fw_paging_block: dma memory info * @fw_paging_size: page size */ struct iwm_fw_paging { struct iwm_dma_info fw_paging_block; uint32_t fw_paging_size; }; #define IWM_TX_RING_COUNT 256 #define IWM_TX_RING_LOMARK 192 #define IWM_TX_RING_HIMARK 224 struct iwm_tx_data { bus_dmamap_t map; bus_addr_t cmd_paddr; bus_addr_t scratch_paddr; mbuf_t m; struct iwm_node *in; int txmcs; int txrate; int totlen; uint16_t fc; struct ieee80211_tx_info info; }; struct iwm_tx_ring { struct iwm_dma_info desc_dma; struct iwm_dma_info cmd_dma; struct iwm_tfd *desc; struct iwm_device_cmd *cmd; struct iwm_tx_data data[IWM_TX_RING_COUNT]; int qid; int queued; int cur; int read; int tail; }; #define IWM_RX_MQ_RING_COUNT 512 #define IWM_RX_RING_COUNT 256 /* Linux driver optionally uses 8k buffer */ #define IWM_RBUF_SIZE 4096 struct iwm_rx_data { mbuf_t m; bus_dmamap_t map; }; struct iwm_rx_ring { struct iwm_dma_info free_desc_dma; struct iwm_dma_info stat_dma; struct iwm_dma_info used_desc_dma; void *desc; struct iwm_rb_status *stat; struct iwm_rx_data data[IWM_RX_MQ_RING_COUNT]; int cur; }; #define IWM_FLAG_USE_ICT 0x01 /* using Interrupt Cause Table */ #define IWM_FLAG_RFKILL 0x02 /* radio kill switch is set */ #define IWM_FLAG_SCANNING 0x04 /* scan in progress */ #define IWM_FLAG_MAC_ACTIVE 0x08 /* MAC context added to firmware */ #define IWM_FLAG_BINDING_ACTIVE 0x10 /* MAC->PHY binding added to firmware */ #define IWM_FLAG_STA_ACTIVE 0x20 /* AP added to firmware station table */ #define IWM_FLAG_TE_ACTIVE 0x40 /* time event is scheduled */ #define IWM_FLAG_HW_ERR 0x80 /* hardware error occurred */ #define IWM_FLAG_SHUTDOWN 0x100 /* shutting down; new tasks forbidden */ #define IWM_FLAG_BGSCAN 0x200 /* background scan in progress */ struct iwm_ucode_status { uint32_t uc_error_event_table; uint32_t uc_umac_error_event_table; uint32_t uc_log_event_table; int uc_ok; int uc_intr; }; #define IWM_CMD_RESP_MAX PAGE_SIZE /* lower blocks contain EEPROM image and calibration data */ #define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_7000 16384 #define IWM_OTP_LOW_IMAGE_SIZE_FAMILY_8000 32768 #define IWM_TE_SESSION_PROTECTION_MAX_TIME_MS 1000 #define IWM_TE_SESSION_PROTECTION_MIN_TIME_MS 400 enum IWM_CMD_MODE { IWM_CMD_ASYNC = (1 << 0), IWM_CMD_WANT_RESP = (1 << 1), IWM_CMD_SEND_IN_RFKILL = (1 << 2), }; enum iwm_hcmd_dataflag { IWM_HCMD_DFL_NOCOPY = (1 << 0), IWM_HCMD_DFL_DUP = (1 << 1), }; #define IWM_NUM_PAPD_CH_GROUPS 9 #define IWM_NUM_TXP_CH_GROUPS 9 struct iwm_phy_db_entry { uint16_t size; uint8_t *data; }; struct iwm_phy_db { struct iwm_phy_db_entry cfg; struct iwm_phy_db_entry calib_nch; struct iwm_phy_db_entry calib_ch_group_papd[IWM_NUM_PAPD_CH_GROUPS]; struct iwm_phy_db_entry calib_ch_group_txp[IWM_NUM_TXP_CH_GROUPS]; }; struct iwm_phy_ctxt { uint16_t id; uint16_t color; uint32_t ref; struct ieee80211_channel *channel; }; struct iwm_bf_data { int bf_enabled; /* filtering */ int ba_enabled; /* abort */ int ave_beacon_signal; int last_cqm_event; }; /** * struct iwm_reorder_buffer - per ra/tid/queue reorder buffer * @head_sn: reorder window head sn * @num_stored: number of mpdus stored in the buffer * @buf_size: the reorder buffer size as set by the last addba request * @queue: queue of this reorder buffer * @last_amsdu: track last ASMDU SN for duplication detection * @last_sub_index: track ASMDU sub frame index for duplication detection * @reorder_timer: timer for frames are in the reorder buffer. For AMSDU * it is the time of last received sub-frame * @removed: prevent timer re-arming * @valid: reordering is valid for this queue * @consec_oldsn_drops: consecutive drops due to old SN * @consec_oldsn_ampdu_gp2: A-MPDU GP2 timestamp to track * when to apply old SN consecutive drop workaround * @consec_oldsn_prev_drop: track whether or not an MPDU * that was single/part of the previous A-MPDU was * dropped due to old SN */ struct iwm_reorder_buffer { uint16_t head_sn; uint16_t num_stored; uint16_t buf_size; uint16_t last_amsdu; uint8_t last_sub_index; CTimeout *reorder_timer; int removed; int valid; unsigned int consec_oldsn_drops; uint32_t consec_oldsn_ampdu_gp2; unsigned int consec_oldsn_prev_drop; #define IWM_AMPDU_CONSEC_DROPS_DELBA 20 }; /** * struct iwm_reorder_buf_entry - reorder buffer entry per frame sequence number * @frames: list of mbufs stored (A-MSDU subframes share a sequence number) * @reorder_time: time the packet was stored in the reorder buffer */ struct iwm_reorder_buf_entry { struct mbuf_list frames; struct timeval reorder_time; uint32_t rx_pkt_status; int chanidx; int is_shortpre; uint32_t rate_n_flags; uint32_t device_timestamp; struct ieee80211_rxinfo rxi; }; /** * struct iwm_rxba_data - BA session data * @sta_id: station id * @tid: tid of the session * @baid: baid of the session * @timeout: the timeout set in the addba request * @entries_per_queue: # of buffers per queue * @last_rx: last rx timestamp, updated only if timeout passed from last update * @session_timer: timer to check if BA session expired, runs at 2 * timeout * @sc: softc pointer, needed for timer context * @reorder_buf: reorder buffer * @reorder_buf_data: buffered frames, one entry per sequence number */ struct iwm_rxba_data { uint8_t sta_id; uint8_t tid; uint8_t baid; uint16_t timeout; uint16_t entries_per_queue; struct timeval last_rx; CTimeout *session_timer; struct iwm_softc *sc; struct iwm_reorder_buffer reorder_buf; struct iwm_reorder_buf_entry entries[IEEE80211_BA_MAX_WINSZ]; }; static inline struct iwm_rxba_data * iwm_rxba_data_from_reorder_buf(struct iwm_reorder_buffer *buf) { return (struct iwm_rxba_data *)((uint8_t *)buf - offsetof(struct iwm_rxba_data, reorder_buf)); } /** * struct iwm_rxq_dup_data - per station per rx queue data * @last_seq: last sequence per tid for duplicate packet detection * @last_sub_frame: last subframe packet */ struct iwm_rxq_dup_data { uint16_t last_seq[IWM_MAX_TID_COUNT + 1]; uint8_t last_sub_frame[IWM_MAX_TID_COUNT + 1]; }; struct iwm_tx_ba { struct iwm_node * wn; uint32_t rate_n_flags; uint8_t lq_color; uint16_t tx_time; uint32_t tx_count_last; uint32_t tx_count; unsigned long tpt_meas_start; }; struct iwm_ba_task_data { uint32_t start_tidmask; uint32_t stop_tidmask; }; struct iwm_softc { struct device sc_dev; struct ieee80211com sc_ic; int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int); int sc_newstate_pending; struct ieee80211_amrr sc_amrr; CTimeout *sc_calib_to; CTimeout *sc_led_blink_to; pci_intr_handle_t ih; struct task init_task; /* NB: not reference-counted */ // struct refcnt task_refs; struct task newstate_task; enum ieee80211_state ns_nstate; int ns_arg; /* Task for firmware BlockAck setup/teardown and its arguments. */ struct task ba_task; struct iwm_ba_task_data ba_rx; struct iwm_ba_task_data ba_tx; /* Task for ERP/HT prot/slot-time/EDCA updates. */ struct task mac_ctxt_task; struct task chan_ctxt_task; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; bus_size_t sc_sz; bus_dma_tag_t sc_dmat; pci_chipset_tag_t sc_pct; pcitag_t sc_pcitag; IOInterruptEventSource *sc_ih; int sc_msix; /* TX scheduler rings. */ struct iwm_dma_info sched_dma; uint32_t sched_base; /* TX/RX rings. */ struct iwm_tx_ring txq[IWM_MAX_QUEUES]; struct iwm_rx_ring rxq; int qfullmsk; int cmdqid; uint8_t sc_mgmt_last_antenna_idx; uint8_t sc_tx_ant; int sc_sf_state; /* ICT table. */ struct iwm_dma_info ict_dma; int ict_cur; int sc_hw_rev; #define IWM_SILICON_A_STEP 0 #define IWM_SILICON_B_STEP 1 #define IWM_SILICON_C_STEP 2 #define IWM_SILICON_D_STEP 3 int sc_hw_id; int sc_device_family; #define IWM_DEVICE_FAMILY_7000 1 #define IWM_DEVICE_FAMILY_8000 2 #define IWM_DEVICE_FAMILY_9000 3 struct iwm_dma_info kw_dma; struct iwm_dma_info fw_dma; int sc_fw_chunk_done; int sc_init_complete; #define IWM_INIT_COMPLETE 0x01 #define IWM_CALIB_COMPLETE 0x02 struct iwm_ucode_status sc_uc; enum iwm_ucode_type sc_uc_current; char sc_fwver[32]; int sc_capaflags; int sc_capa_max_probe_len; int sc_capa_n_scan_channels; uint8_t sc_ucode_api[howmany(IWM_NUM_UCODE_TLV_API, NBBY)]; uint8_t sc_enabled_capa[howmany(IWM_NUM_UCODE_TLV_CAPA, NBBY)]; #define IWM_MAX_FW_CMD_VERSIONS 64 struct iwm_fw_cmd_version cmd_versions[IWM_MAX_FW_CMD_VERSIONS]; int n_cmd_versions; char sc_fw_mcc[3]; uint16_t sc_fw_mcc_int; int sc_intmask; int sc_flags; uint32_t sc_fh_init_mask; uint32_t sc_hw_init_mask; uint32_t sc_fh_mask; uint32_t sc_hw_mask; /* * So why do we need a separate stopped flag and a generation? * the former protects the device from issueing commands when it's * stopped (duh). The latter protects against race from a very * fast stop/unstop cycle where threads waiting for responses do * not have a chance to run in between. Notably: we want to stop * the device from interrupt context when it craps out, so we * don't have the luxury of waiting for quiescense. */ int sc_generation; // struct rwlock ioctl_rwl; int sc_cap_off; /* PCIe caps */ const char *sc_fwname; bus_size_t sc_fwdmasegsz; size_t sc_nvm_max_section_size; struct iwm_fw_info sc_fw; int sc_fw_phy_config; struct iwm_tlv_calib_ctrl sc_default_calib[IWM_UCODE_TYPE_MAX]; struct iwm_nvm_data sc_nvm; struct iwm_phy_db sc_phy_db; struct iwm_bf_data sc_bf; int sc_tx_timer[IWM_MAX_QUEUES]; int sc_rx_ba_sessions; int sc_scan_last_antenna; int sc_fixed_ridx; int sc_staid; int sc_nodecolor; uint8_t *sc_cmd_resp_pkt[IWM_TX_RING_COUNT]; size_t sc_cmd_resp_len[IWM_TX_RING_COUNT]; int sc_nic_locks; struct taskq *sc_nswq; struct iwm_rx_phy_info sc_last_phy_info; int sc_ampdu_ref; #define IWM_MAX_BAID 32 struct iwm_rxba_data sc_rxba_data[IWM_MAX_BAID]; int agg_queue_mask; int agg_tid_disable; struct iwm_tx_ba sc_tx_ba[IEEE80211_NUM_TID]; uint32_t sc_time_event_uid; /* phy contexts. we only use the first one */ struct iwm_phy_ctxt sc_phyctxt[IWM_NUM_PHY_CTX]; struct iwm_notif_statistics sc_stats; int sc_noise; int host_interrupt_operation_mode; int sc_ltr_enabled; enum iwm_nvm_type nvm_type; int support_ldpc; uint8_t non_shared_ant; int sc_mqrx_supported; int sc_integrated; int sc_ltr_delay; int sc_xtal_latency; int sc_low_latency_xtal; /* * Paging parameters - All of the parameters should be set by the * opmode when paging is enabled */ struct iwm_fw_paging fw_paging_db[IWM_NUM_OF_FW_PAGING_BLOCKS]; uint16_t num_of_paging_blk; uint16_t num_of_pages_in_last_blk; #if NBPFILTER > 0 caddr_t sc_drvbpf; union { struct iwm_rx_radiotap_header th; uint8_t pad[IEEE80211_RADIOTAP_HDRLEN]; } sc_rxtapu; #define sc_rxtap sc_rxtapu.th int sc_rxtap_len; union { struct iwm_tx_radiotap_header th; uint8_t pad[IEEE80211_RADIOTAP_HDRLEN]; } sc_txtapu; #define sc_txtap sc_txtapu.th int sc_txtap_len; #endif union { struct iwl_lq_sta_rs_fw rs_fw; struct iwl_lq_sta rs_drv; } lq_sta; int tx_protection; }; struct iwm_node { struct ieee80211_node in_ni; struct iwm_phy_ctxt *in_phyctxt; uint8_t in_macaddr[ETHER_ADDR_LEN]; uint16_t in_id; uint16_t in_color; struct ieee80211_amrr_node in_amn; int lq_rate_mismatch; uint32_t next_ampdu_id; struct iwm_rxq_dup_data dup_data; }; #define IWM_STATION_ID 0 #define IWM_AUX_STA_ID 1 #define IWM_MONITOR_STA_ID 2 #define IWM_ICT_SIZE 4096 #define IWM_ICT_COUNT (IWM_ICT_SIZE / sizeof (uint32_t)) #define IWM_ICT_PADDR_SHIFT 12 ================================================ FILE: itlwm/hal_iwm/io.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" #include uint32_t ItlIwm:: iwm_read_prph_unlocked(struct iwm_softc *sc, uint32_t addr) { IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_RADDR, ((addr & 0x000fffff) | (3 << 24))); IWM_BARRIER_READ_WRITE(sc); return IWM_READ(sc, IWM_HBUS_TARG_PRPH_RDAT); } uint32_t ItlIwm:: iwm_read_prph(struct iwm_softc *sc, uint32_t addr) { iwm_nic_assert_locked(sc); return iwm_read_prph_unlocked(sc, addr); } void ItlIwm:: iwm_write_prph_unlocked(struct iwm_softc *sc, uint32_t addr, uint32_t val) { IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_WADDR, ((addr & 0x000fffff) | (3 << 24))); IWM_BARRIER_WRITE(sc); IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_WDAT, val); } void ItlIwm:: iwm_write_prph(struct iwm_softc *sc, uint32_t addr, uint32_t val) { iwm_nic_assert_locked(sc); iwm_write_prph_unlocked(sc, addr, val); } void ItlIwm:: iwm_write_prph64(struct iwm_softc *sc, uint64_t addr, uint64_t val) { iwm_write_prph(sc, (uint32_t)addr, val & 0xffffffff); iwm_write_prph(sc, (uint32_t)addr + 4, val >> 32); } int ItlIwm:: iwm_read_mem(struct iwm_softc *sc, uint32_t addr, void *buf, int dwords) { int offs, err = 0; uint32_t *vals = (uint32_t*)buf; if (iwm_nic_lock(sc)) { IWM_WRITE(sc, IWM_HBUS_TARG_MEM_RADDR, addr); for (offs = 0; offs < dwords; offs++) vals[offs] = IWM_READ(sc, IWM_HBUS_TARG_MEM_RDAT); iwm_nic_unlock(sc); } else { err = EBUSY; } return err; } int ItlIwm:: iwm_write_mem(struct iwm_softc *sc, uint32_t addr, const void *buf, int dwords) { int offs; const uint32_t *vals = (const uint32_t*)buf; if (iwm_nic_lock(sc)) { IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WADDR, addr); /* WADDR auto-increments */ for (offs = 0; offs < dwords; offs++) { uint32_t val = vals ? vals[offs] : 0; IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WDAT, val); } iwm_nic_unlock(sc); } else { return EBUSY; } return 0; } int ItlIwm:: iwm_write_mem32(struct iwm_softc *sc, uint32_t addr, uint32_t val) { return iwm_write_mem(sc, addr, &val, 1); } int ItlIwm:: iwm_poll_bit(struct iwm_softc *sc, int reg, uint32_t bits, uint32_t mask, int timo) { for (;;) { if ((IWM_READ(sc, reg) & mask) == (bits & mask)) { return 1; } if (timo < 10) { return 0; } timo -= 10; DELAY(10); } } int ItlIwm:: iwm_nic_lock(struct iwm_softc *sc) { if (sc->sc_nic_locks > 0) { sc->sc_nic_locks++; return 1; /* already locked */ } IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); if (sc->sc_device_family >= IWM_DEVICE_FAMILY_8000) DELAY(2); if (iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP, 150000)) { sc->sc_nic_locks++; return 1; } XYLog("%s: acquiring device failed\n", DEVNAME(sc)); return 0; } void ItlIwm:: iwm_nic_assert_locked(struct iwm_softc *sc) { if (sc->sc_nic_locks <= 0) panic("%s: nic locks counter %d", DEVNAME(sc), sc->sc_nic_locks); } void ItlIwm:: iwm_nic_unlock(struct iwm_softc *sc) { if (sc->sc_nic_locks > 0) { if (--sc->sc_nic_locks == 0) IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } else XYLog("%s: NIC already unlocked\n", DEVNAME(sc)); } void ItlIwm:: iwm_set_bits_mask_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits, uint32_t mask) { uint32_t val; /* XXX: no error path? */ if (iwm_nic_lock(sc)) { val = iwm_read_prph(sc, reg) & mask; val |= bits; iwm_write_prph(sc, reg, val); iwm_nic_unlock(sc); } } void ItlIwm:: iwm_set_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits) { iwm_set_bits_mask_prph(sc, reg, bits, ~0); } void ItlIwm:: iwm_clear_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits) { iwm_set_bits_mask_prph(sc, reg, 0, ~bits); } bool allocDmaMemory2(struct iwm_dma_info *dma, size_t size, int alignment) { IOBufferMemoryDescriptor *bmd; IODMACommand::Segment64 seg; UInt64 ofs = 0; UInt32 numSegs = 1; bmd = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, kIODirectionInOut | kIOMemoryPhysicallyContiguous | kIOMapInhibitCache, size, DMA_BIT_MASK(36)); if (bmd == NULL) { XYLog("%s alloc DMA memory failed.\n", __FUNCTION__); return false; } bmd->prepare(); IODMACommand *cmd = IODMACommand::withSpecification(kIODMACommandOutputHost64, 64, 0, IODMACommand::kMapped, 0, alignment); if (cmd == NULL) { XYLog("%s alloc IODMACommand memory failed.\n", __FUNCTION__); bmd->complete(); bmd->release(); return false; } cmd->setMemoryDescriptor(bmd); if (cmd->gen64IOVMSegments(&ofs, &seg, &numSegs) != kIOReturnSuccess) { cmd->release(); cmd = NULL; bmd->complete(); bmd->release(); bmd = NULL; return false; } dma->paddr = seg.fIOVMAddr; dma->vaddr = bmd->getBytesNoCopy(); dma->size = size; dma->buffer = bmd; dma->cmd = cmd; memset(dma->vaddr, 0, dma->size); return true; } void ItlIwm:: iwm_dma_contig_free(struct iwm_dma_info *dma) { if (dma == NULL || dma->cmd == NULL) return; if (dma->vaddr == NULL) return; dma->cmd->clearMemoryDescriptor(); dma->cmd->release(); dma->cmd = NULL; dma->buffer->complete(); dma->buffer->release(); dma->buffer = NULL; dma->vaddr = NULL; } int ItlIwm:: iwm_dma_contig_alloc(bus_dma_tag_t tag, struct iwm_dma_info *dma, bus_size_t size, bus_size_t alignment) { if (!allocDmaMemory2(dma, size, alignment)) { return 1; } return 0; } ================================================ FILE: itlwm/hal_iwm/itlhdr.h ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef itlhdr_h #define itlhdr_h #include #include #include #include #include #include #include #include #include #include #include #include "if_iwmreg.h" #include "if_iwmvar.h" #include #define DEVNAME(_s) ("itlwm") #define IWM_DEBUG #ifdef IWM_DEBUG #define DPRINTF(x) do { if (iwm_debug > 0) XYLog x; } while (0) #define DPRINTFN(n, x) do { if (iwm_debug >= (n)) XYLog x; } while (0) extern int iwm_debug; #else #define DPRINTF(x) do { ; } while (0) #define DPRINTFN(n, x) do { ; } while (0) #endif #define M_DEVBUF 2 #define M_WAIT 3 #define DELAY IODelay #define INFSLP UINT64_MAX #define IC2IFP(_ic_) (&(_ic_)->ic_if) #define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen)) const uint8_t iwm_nvm_channels[] = { /* 2.4 GHz */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 5 GHz */ 36, 40, 44 , 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165 }; const uint8_t iwm_nvm_channels_8000[] = { /* 2.4 GHz */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 5 GHz */ 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, 177, 181 }; #define IWM_NUM_2GHZ_CHANNELS 14 #define IWM_FIRST_2GHZ_HT_MINUS 5 #define IWM_LAST_2GHZ_HT_PLUS 9 struct iwm_nvm_section { uint16_t length; uint8_t *data; }; /* Map ieee80211_edca_ac categories to firmware Tx FIFO. */ const uint8_t iwm_ac_to_tx_fifo[] = { IWM_TX_FIFO_BE, IWM_TX_FIFO_BK, IWM_TX_FIFO_VI, IWM_TX_FIFO_VO, }; #endif /* itlhdr_h */ ================================================ FILE: itlwm/hal_iwm/led.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" void ItlIwm:: iwm_led_enable(struct iwm_softc *sc) { IWM_WRITE(sc, IWM_CSR_LED_REG, IWM_CSR_LED_REG_TURN_ON); } void ItlIwm:: iwm_led_disable(struct iwm_softc *sc) { IWM_WRITE(sc, IWM_CSR_LED_REG, IWM_CSR_LED_REG_TURN_OFF); } int ItlIwm:: iwm_led_is_enabled(struct iwm_softc *sc) { return (IWM_READ(sc, IWM_CSR_LED_REG) == IWM_CSR_LED_REG_TURN_ON); } #define IWM_LED_BLINK_TIMEOUT_MSEC 200 void ItlIwm:: iwm_led_blink_timeout(void *arg) { struct iwm_softc *sc = (struct iwm_softc *)arg; ItlIwm *that = container_of(sc, ItlIwm, com); if (that->iwm_led_is_enabled(sc)) that->iwm_led_disable(sc); else that->iwm_led_enable(sc); timeout_add_msec(&sc->sc_led_blink_to, IWM_LED_BLINK_TIMEOUT_MSEC); } void ItlIwm:: iwm_led_blink_start(struct iwm_softc *sc) { timeout_add_msec(&sc->sc_led_blink_to, IWM_LED_BLINK_TIMEOUT_MSEC); iwm_led_enable(sc); } void ItlIwm:: iwm_led_blink_stop(struct iwm_softc *sc) { timeout_del(&sc->sc_led_blink_to); iwm_led_disable(sc); } ================================================ FILE: itlwm/hal_iwm/mac80211.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" #include #include #include #include "rs.h" #ifdef IWM_DEBUG int iwm_debug = 1; #endif int ItlIwm:: iwm_is_valid_channel(uint16_t ch_id) { if (ch_id <= 14 || (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) return 1; return 0; } uint8_t ItlIwm:: iwm_ch_id_to_ch_index(uint16_t ch_id) { if (!iwm_is_valid_channel(ch_id)) return 0xff; if (ch_id <= 14) return ch_id - 1; if (ch_id <= 64) return (ch_id + 20) / 4; if (ch_id <= 140) return (ch_id - 12) / 4; return (ch_id - 13) / 4; } uint16_t ItlIwm:: iwm_channel_id_to_papd(uint16_t ch_id) { if (!iwm_is_valid_channel(ch_id)) return 0xff; if (1 <= ch_id && ch_id <= 14) return 0; if (36 <= ch_id && ch_id <= 64) return 1; if (100 <= ch_id && ch_id <= 140) return 2; return 3; } uint16_t ItlIwm:: iwm_channel_id_to_txp(struct iwm_softc *sc, uint16_t ch_id) { struct iwm_phy_db *phy_db = &sc->sc_phy_db; struct iwm_phy_db_chg_txp *txp_chg; int i; uint8_t ch_index = iwm_ch_id_to_ch_index(ch_id); if (ch_index == 0xff) return 0xff; for (i = 0; i < IWM_NUM_TXP_CH_GROUPS; i++) { txp_chg = (struct iwm_phy_db_chg_txp *)phy_db->calib_ch_group_txp[i].data; if (!txp_chg) return 0xff; /* * Looking for the first channel group the max channel * of which is higher than the requested channel. */ if (le16toh(txp_chg->max_channel_idx) >= ch_index) return i; } return 0xff; } int ItlIwm:: iwm_mimo_enabled(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; return !sc->sc_nvm.sku_cap_mimo_disable && (ic->ic_userflags & IEEE80211_F_NOMIMO) == 0; } void ItlIwm:: iwm_init_channel_map(struct iwm_softc *sc, const uint16_t * const nvm_ch_flags, const uint8_t *nvm_channels, size_t nchan) { struct ieee80211com *ic = &sc->sc_ic; struct iwm_nvm_data *data = &sc->sc_nvm; int ch_idx; struct ieee80211_channel *channel; uint16_t ch_flags; int is_5ghz; int flags, hw_value; for (ch_idx = 0; ch_idx < nchan; ch_idx++) { ch_flags = le16_to_cpup(nvm_ch_flags + ch_idx); if (ch_idx >= IWM_NUM_2GHZ_CHANNELS && !data->sku_cap_band_52GHz_enable) ch_flags &= ~IWM_NVM_CHANNEL_VALID; if (!(ch_flags & IWM_NVM_CHANNEL_VALID)) continue; if (ch_flags & IWM_NVM_CHANNEL_160MHZ) data->vht160_supported = true; hw_value = nvm_channels[ch_idx]; channel = &ic->ic_channels[hw_value]; is_5ghz = ch_idx >= IWM_NUM_2GHZ_CHANNELS; if (!is_5ghz) { flags = IEEE80211_CHAN_2GHZ; channel->ic_flags = IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; } else { flags = IEEE80211_CHAN_5GHZ; channel->ic_flags = IEEE80211_CHAN_A; } if (!(ch_flags & IWM_NVM_CHANNEL_ACTIVE)) channel->ic_flags |= IEEE80211_CHAN_PASSIVE; if (data->sku_cap_11n_enable) channel->ic_flags |= IEEE80211_CHAN_HT20; if (!is_5ghz && (ch_flags & IWM_NVM_CHANNEL_40MHZ)) { if (hw_value <= IWM_LAST_2GHZ_HT_PLUS) { channel->ic_flags |= IEEE80211_CHAN_HT40U; } if (hw_value >= IWM_FIRST_2GHZ_HT_MINUS) { channel->ic_flags |= IEEE80211_CHAN_HT40D; } } else if (ch_flags & IWM_NVM_CHANNEL_40MHZ) { if ((ch_idx - IWM_NUM_2GHZ_CHANNELS) % 2 == 0) { channel->ic_flags |= IEEE80211_CHAN_HT40U; } else { channel->ic_flags |= IEEE80211_CHAN_HT40D; } } if (data->sku_cap_11ac_enable) { if (ch_flags & IWM_NVM_CHANNEL_80MHZ) { channel->ic_flags |= IEEE80211_CHAN_VHT80; } if (ch_flags & IWM_NVM_CHANNEL_160MHZ) { channel->ic_flags |= IEEE80211_CHAN_VHT160; } } if (ch_flags & IWM_NVM_CHANNEL_DFS) { channel->ic_flags |= IEEE80211_CHAN_DFS; } channel->ic_freq = ieee80211_ieee2mhz(hw_value, flags); } } void ItlIwm:: iwm_setup_ht_rates(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; uint8_t rx_ant; /* TX is supported with the same MCS as RX. */ ic->ic_tx_mcs_set = IEEE80211_TX_MCS_SET_DEFINED; memset(ic->ic_sup_mcs, 0, sizeof(ic->ic_sup_mcs)); ic->ic_sup_mcs[0] = 0xff; /* MCS 0-7 */ if (sc->support_ldpc) ic->ic_htcaps |= IEEE80211_HTCAP_LDPC; if (!iwm_mimo_enabled(sc)) return; rx_ant = iwm_fw_valid_rx_ant(sc); if ((rx_ant & IWM_ANT_AB) == IWM_ANT_AB || (rx_ant & IWM_ANT_BC) == IWM_ANT_BC) ic->ic_sup_mcs[1] = 0xff; /* MCS 8-15 */ } void ItlIwm:: iwm_init_reorder_buffer(struct iwm_reorder_buffer *reorder_buf, uint16_t ssn, uint16_t buf_size) { reorder_buf->head_sn = ssn; reorder_buf->num_stored = 0; reorder_buf->buf_size = buf_size; reorder_buf->last_amsdu = 0; reorder_buf->last_sub_index = 0; reorder_buf->removed = 0; reorder_buf->valid = 0; reorder_buf->consec_oldsn_drops = 0; reorder_buf->consec_oldsn_ampdu_gp2 = 0; reorder_buf->consec_oldsn_prev_drop = 0; } void ItlIwm:: iwm_clear_reorder_buffer(struct iwm_softc *sc, struct iwm_rxba_data *rxba) { int i; struct iwm_reorder_buffer *reorder_buf = &rxba->reorder_buf; struct iwm_reorder_buf_entry *entry; for (i = 0; i < reorder_buf->buf_size; i++) { entry = &rxba->entries[i]; ml_purge(&entry->frames); timerclear(&entry->reorder_time); } reorder_buf->removed = 1; timeout_del(&reorder_buf->reorder_timer); timeout_free(&reorder_buf->reorder_timer); timerclear(&rxba->last_rx); timeout_del(&rxba->session_timer); timeout_free(&rxba->session_timer); rxba->baid = IWM_RX_REORDER_DATA_INVALID_BAID; } void ItlIwm:: iwm_rx_ba_session_expired(void *arg) { struct iwm_rxba_data *rxba = (struct iwm_rxba_data *)arg; struct iwm_softc *sc = rxba->sc; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; struct timeval now, timeout, expiry; int s; s = splnet(); if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) == 0 && ic->ic_state == IEEE80211_S_RUN && rxba->baid != IWM_RX_REORDER_DATA_INVALID_BAID) { getmicrouptime(&now); USEC_TO_TIMEVAL(RX_REORDER_BUF_TIMEOUT_MQ_USEC, &timeout); timeradd(&rxba->last_rx, &timeout, &expiry); if (timercmp(&now, &expiry, <)) { timeout_add_usec(&rxba->session_timer, rxba->timeout); } else { ic->ic_stats.is_ht_rx_ba_timeout++; ieee80211_delba_request(ic, ni, IEEE80211_REASON_TIMEOUT, 0, rxba->tid); } } splx(s); } void ItlIwm:: iwm_reorder_timer_expired(void *arg) { struct mbuf_list ml = MBUF_LIST_INITIALIZER(); struct iwm_reorder_buffer *buf = (struct iwm_reorder_buffer *)arg; struct iwm_rxba_data *rxba = iwm_rxba_data_from_reorder_buf(buf); struct iwm_reorder_buf_entry *entries = &rxba->entries[0]; struct iwm_softc *sc = rxba->sc; ItlIwm *that = container_of(sc, ItlIwm, com); struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; int i, s; uint16_t sn = 0, index = 0; int expired = 0; int cont = 0; struct timeval now, timeout, expiry; if (!buf->num_stored || buf->removed) return; s = splnet(); getmicrouptime(&now); USEC_TO_TIMEVAL(RX_REORDER_BUF_TIMEOUT_MQ_USEC, &timeout); for (i = 0; i < buf->buf_size ; i++) { index = (buf->head_sn + i) % buf->buf_size; if (ml_empty(&entries[index].frames)) { /* * If there is a hole and the next frame didn't expire * we want to break and not advance SN. */ cont = 0; continue; } timeradd(&entries[index].reorder_time, &timeout, &expiry); if (!cont && timercmp(&now, &expiry, <)) break; expired = 1; /* continue until next hole after this expired frame */ cont = 1; sn = (buf->head_sn + (i + 1)) & 0xfff; } if (expired) { /* SN is set to the last expired frame + 1 */ that->iwm_release_frames(sc, ni, rxba, buf, sn, &ml); if_input(&sc->sc_ic.ic_if, &ml); ic->ic_stats.is_ht_rx_ba_window_gap_timeout++; } else { /* * If no frame expired and there are stored frames, index is now * pointing to the first unexpired frame - modify reorder timeout * accordingly. */ timeout_add_usec(&buf->reorder_timer, RX_REORDER_BUF_TIMEOUT_MQ_USEC); } splx(s); } uint8_t ItlIwm:: iwm_num_of_ant(uint8_t mask) { return !!((mask) & IWM_ANT_A) + !!((mask) & IWM_ANT_B) + !!((mask) & IWM_ANT_C); } void ItlIwm:: iwm_setup_vht_rates(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; uint8_t rx_ant, tx_ant; unsigned int max_ampdu_exponent = IEEE80211_VHTCAP_MAX_AMPDU_1024K; if (ic->ic_userflags & IEEE80211_F_NOVHT) return; /* enable 11ac support */ ic->ic_flags |= IEEE80211_F_VHTON; rx_ant = iwm_num_of_ant(iwm_fw_valid_rx_ant(sc)); tx_ant = iwm_num_of_ant(iwm_fw_valid_tx_ant(sc)); ic->ic_vhtcaps = IEEE80211_VHTCAP_SHORT_GI_80 | IEEE80211_VHTCAP_RXSTBC_1 | IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE | 3 << IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT | max_ampdu_exponent << IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT | IEEE80211_VHTCAP_MU_BEAMFORMEE_CAPABLE; if (sc->sc_nvm.vht160_supported) ic->ic_vhtcaps |= IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ | IEEE80211_VHTCAP_SHORT_GI_160; if (sc->support_ldpc) ic->ic_vhtcaps |= IEEE80211_VHTCAP_RXLDPC; if (!iwm_mimo_enabled(sc)) { rx_ant = 1; tx_ant = 1; } if (tx_ant > 1) ic->ic_vhtcaps |= IEEE80211_VHTCAP_TXSTBC; else ic->ic_vhtcaps |= IEEE80211_VHTCAP_TX_ANTENNA_PATTERN; ic->ic_vht_rx_mcs_map = htole16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); if (rx_ant == 1) { ic->ic_vhtcaps |= IEEE80211_VHTCAP_RX_ANTENNA_PATTERN; /* this works because NOT_SUPPORTED == 3 */ ic->ic_vht_rx_mcs_map |= htole16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2); } ic->ic_vht_tx_mcs_map = ic->ic_vht_rx_mcs_map; ic->ic_vht_tx_highest = ic->ic_vht_rx_highest = 0; memset(ic->ic_vht_sup_mcs, 0, sizeof(ic->ic_vht_sup_mcs)); ic->ic_vht_sup_mcs[0] = 0x03FF; /* MCS 0-9 */ if (!iwm_mimo_enabled(sc)) return; ic->ic_vht_sup_mcs[1] = 0x03FF; /* MCS 0-9 */ } #define IWM_MAX_RX_BA_SESSIONS 16 int ItlIwm:: iwm_sta_rx_agg(struct iwm_softc *sc, struct ieee80211_node *ni, uint8_t tid, uint16_t ssn, uint16_t winsize, int timeout_val, int start) { struct ieee80211com *ic = &sc->sc_ic; struct iwm_add_sta_cmd cmd; struct iwm_node *in = (struct iwm_node *)ni; int err, s; uint32_t status; size_t cmdsize; struct iwm_rxba_data *rxba = NULL; uint8_t baid = 0; s = splnet(); if (start && sc->sc_rx_ba_sessions >= IWM_MAX_RX_BA_SESSIONS) { ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return 0; } memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = IWM_STATION_ID; cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); cmd.add_modify = IWM_STA_MODE_MODIFY; if (start) { cmd.add_immediate_ba_tid = (uint8_t)tid; cmd.add_immediate_ba_ssn = ssn; cmd.rx_ba_window = winsize; } else { cmd.remove_immediate_ba_tid = (uint8_t)tid; } cmd.modify_mask = start ? IWM_STA_MODIFY_ADD_BA_TID : IWM_STA_MODIFY_REMOVE_BA_TID; status = IWM_ADD_STA_SUCCESS; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_STA_TYPE)) cmdsize = sizeof(cmd); else cmdsize = sizeof(struct iwm_add_sta_cmd_v7); err = iwm_send_cmd_pdu_status(sc, IWM_ADD_STA, cmdsize, &cmd, &status); if (!err && (status & IWM_ADD_STA_STATUS_MASK) != IWM_ADD_STA_SUCCESS) err = EIO; if (err) { if (start) ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return err; } if (sc->sc_mqrx_supported) { /* Deaggregation is done in hardware. */ if (start) { if (!(status & IWM_ADD_STA_BAID_VALID_MASK)) { ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return EIO; } baid = (status & IWM_ADD_STA_BAID_MASK) >> IWM_ADD_STA_BAID_SHIFT; if (baid == IWM_RX_REORDER_DATA_INVALID_BAID || baid >= nitems(sc->sc_rxba_data)) { ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return EIO; } rxba = &sc->sc_rxba_data[baid]; if (rxba->baid != IWM_RX_REORDER_DATA_INVALID_BAID) { ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return 0; } rxba->sta_id = IWM_STATION_ID; rxba->tid = tid; rxba->baid = baid; rxba->timeout = timeout_val; getmicrouptime(&rxba->last_rx); iwm_init_reorder_buffer(&rxba->reorder_buf, ssn, winsize); if (timeout_val != 0) { struct ieee80211_rx_ba *ba; timeout_add_usec(&rxba->session_timer, timeout_val); /* XXX disable net80211's BA timeout handler */ ba = &ni->ni_rx_ba[tid]; ba->ba_timeout_val = 0; } } else { int i; for (i = 0; i < nitems(sc->sc_rxba_data); i++) { rxba = &sc->sc_rxba_data[i]; if (rxba->baid == IWM_RX_REORDER_DATA_INVALID_BAID) continue; if (rxba->tid != tid) continue; iwm_clear_reorder_buffer(sc, rxba); break; } } } if (start) { sc->sc_rx_ba_sessions++; ieee80211_addba_req_accept(ic, ni, tid); } else if (sc->sc_rx_ba_sessions > 0) sc->sc_rx_ba_sessions--; splx(s); return 0; } int ItlIwm:: iwm_sta_tx_agg(struct iwm_softc *sc, struct ieee80211_node *ni, uint8_t tid, uint8_t qid, uint16_t ssn, int start) { struct iwm_add_sta_cmd cmd; struct iwm_node *in = (struct iwm_node *)ni; int err = 0; uint32_t status; size_t cmdsize; memset(&cmd, 0, sizeof(cmd)); cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); cmd.sta_id = IWM_STATION_ID; cmd.add_modify = IWM_STA_MODE_MODIFY; cmd.modify_mask = (IWM_STA_MODIFY_QUEUES | IWM_STA_MODIFY_TID_DISABLE_TX); cmd.tfd_queue_msk = htole32(sc->agg_queue_mask); cmd.tid_disable_tx = htole16(sc->agg_tid_disable); if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_STA_TYPE)) cmdsize = sizeof(cmd); else cmdsize = sizeof(struct iwm_add_sta_cmd_v7); status = IWM_ADD_STA_SUCCESS; err = iwm_send_cmd_pdu_status(sc, IWM_ADD_STA, cmdsize, &cmd, &status); XYLog("%s tx agg %s. err=%d status=%d, mask_status=%d\n", __FUNCTION__, err ? "failed" : "done", err, status, (status & IWM_ADD_STA_STATUS_MASK)); return err || ((status & IWM_ADD_STA_STATUS_MASK) != IWM_ADD_STA_SUCCESS); } void ItlIwm:: iwm_set_hw_address_8000(struct iwm_softc *sc, struct iwm_nvm_data *data, const uint16_t *mac_override, const uint16_t *nvm_hw) { const uint8_t *hw_addr; if (mac_override) { static const uint8_t reserved_mac[] = { 0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00 }; hw_addr = (const uint8_t *)(mac_override + IWM_MAC_ADDRESS_OVERRIDE_8000); /* * Store the MAC address from MAO section. * No byte swapping is required in MAO section */ memcpy(data->hw_addr, hw_addr, ETHER_ADDR_LEN); /* * Force the use of the OTP MAC address in case of reserved MAC * address in the NVM, or if address is given but invalid. */ if (memcmp(reserved_mac, hw_addr, ETHER_ADDR_LEN) != 0 && (memcmp(etherbroadcastaddr, data->hw_addr, sizeof(etherbroadcastaddr)) != 0) && (memcmp(etheranyaddr, data->hw_addr, sizeof(etheranyaddr)) != 0) && !ETHER_IS_MULTICAST(data->hw_addr)) return; } if (nvm_hw) { /* Read the mac address from WFMP registers. */ uint32_t mac_addr0, mac_addr1; if (!iwm_nic_lock(sc)) goto out; mac_addr0 = htole32(iwm_read_prph(sc, IWM_WFMP_MAC_ADDR_0)); mac_addr1 = htole32(iwm_read_prph(sc, IWM_WFMP_MAC_ADDR_1)); iwm_nic_unlock(sc); hw_addr = (const uint8_t *)&mac_addr0; data->hw_addr[0] = hw_addr[3]; data->hw_addr[1] = hw_addr[2]; data->hw_addr[2] = hw_addr[1]; data->hw_addr[3] = hw_addr[0]; hw_addr = (const uint8_t *)&mac_addr1; data->hw_addr[4] = hw_addr[1]; data->hw_addr[5] = hw_addr[0]; return; } out: XYLog("%s: mac address not found\n", DEVNAME(sc)); memset(data->hw_addr, 0, sizeof(data->hw_addr)); } /* * RSSI values are reported by the FW as positive values - need to negate * to obtain their dBM. Account for missing antennas by replacing 0 * values by -256dBm: practically 0 power and a non-feasible 8 bit value. */ int ItlIwm:: iwm_get_signal_strength(struct iwm_softc *sc, struct ieee80211_rx_status *rx_status, struct iwm_rx_phy_info *phy_info) { int energy_a, energy_b, energy_c, max_energy; uint32_t val; val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_ENERGY_ANT_ABC_IDX]); energy_a = (val & IWM_RX_INFO_ENERGY_ANT_A_MSK) >> IWM_RX_INFO_ENERGY_ANT_A_POS; energy_a = energy_a ? -energy_a : -256; energy_b = (val & IWM_RX_INFO_ENERGY_ANT_B_MSK) >> IWM_RX_INFO_ENERGY_ANT_B_POS; energy_b = energy_b ? -energy_b : -256; energy_c = (val & IWM_RX_INFO_ENERGY_ANT_C_MSK) >> IWM_RX_INFO_ENERGY_ANT_C_POS; energy_c = energy_c ? -energy_c : -256; max_energy = MAX(energy_a, energy_b); max_energy = MAX(max_energy, energy_c); rx_status->signal = max_energy; rx_status->chains = (le16toh(phy_info->phy_flags) & IWM_RX_RES_PHY_FLAGS_ANTENNA) >> IWM_RX_RES_PHY_FLAGS_ANTENNA_POS; rx_status->chain_signal[0] = energy_a; rx_status->chain_signal[1] = energy_b; rx_status->chain_signal[2] = energy_c; return max_energy; } int ItlIwm:: iwm_rxmq_get_signal_strength(struct iwm_softc *sc, struct ieee80211_rx_status *rx_status, uint32_t rate_n_flags, struct iwm_rx_mpdu_desc *desc) { int energy_a, energy_b; energy_a = desc->v1.energy_a; energy_b = desc->v1.energy_b; energy_a = energy_a ? -energy_a : -256; energy_b = energy_b ? -energy_b : -256; rx_status->signal = MAX(energy_a, energy_b); rx_status->chains = (rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS; rx_status->chain_signal[0] = energy_a; rx_status->chain_signal[1] = energy_b; rx_status->chain_signal[2] = S8_MIN; return rx_status->signal; } /* * Retrieve the average noise (in dBm) among receivers. */ int ItlIwm:: iwm_get_noise(const struct iwm_statistics_rx_non_phy *stats) { int i, total, nbant, noise; total = nbant = noise = 0; for (i = 0; i < 3; i++) { noise = letoh32(stats->beacon_silence_rssi[i]) & 0xff; if (noise) { total += noise; nbant++; } } /* There should be at least one antenna but check anyway. */ return (nbant == 0) ? -127 : (total / nbant) - 107; } int ItlIwm:: iwm_ccmp_decap(struct iwm_softc *sc, mbuf_t m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_key *k = &ni->ni_pairwise_key; struct ieee80211_frame *wh; uint64_t pn, *prsc; uint8_t *ivp; uint8_t tid; int hdrlen, hasqos; wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); ivp = (uint8_t *)wh + hdrlen; /* Check that ExtIV bit is set. */ if (!(ivp[3] & IEEE80211_WEP_EXTIV)) return 1; hasqos = ieee80211_has_qos(wh); tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; prsc = &k->k_rsc[tid]; /* Extract the 48-bit PN from the CCMP header. */ pn = (uint64_t)ivp[0] | (uint64_t)ivp[1] << 8 | (uint64_t)ivp[4] << 16 | (uint64_t)ivp[5] << 24 | (uint64_t)ivp[6] << 32 | (uint64_t)ivp[7] << 40; if (rxi->rxi_flags & IEEE80211_RXI_HWDEC_SAME_PN) { if (pn < *prsc) { ic->ic_stats.is_ccmp_replays++; return 1; } } else if (pn <= *prsc) { ic->ic_stats.is_ccmp_replays++; return 1; } /* Last seen packet number is updated in ieee80211_inputm(). */ /* * Some firmware versions strip the MIC, and some don't. It is not * clear which of the capability flags could tell us what to expect. * For now, keep things simple and just leave the MIC in place if * it is present. * * The IV will be stripped by ieee80211_inputm(). */ return 0; } int ItlIwm:: iwm_rx_hwdecrypt(struct iwm_softc *sc, mbuf_t m, uint32_t rx_pkt_status, struct ieee80211_rxinfo *rxi) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); struct ieee80211_frame *wh; struct ieee80211_node *ni; int ret = 0; uint8_t type, subtype; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; if (type == IEEE80211_FC0_TYPE_CTL) return 0; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (ieee80211_has_qos(wh) && (subtype & IEEE80211_FC0_SUBTYPE_NODATA)) return 0; if (IEEE80211_IS_MULTICAST(wh->i_addr1) || !(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) return 0; ni = ieee80211_find_rxnode(ic, wh); /* Handle hardware decryption. */ if ((ni->ni_flags & IEEE80211_NODE_RXPROT) && ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) { if ((rx_pkt_status & IWM_RX_MPDU_RES_STATUS_SEC_ENC_MSK) != IWM_RX_MPDU_RES_STATUS_SEC_CCM_ENC) { ic->ic_stats.is_ccmp_dec_errs++; ret = 1; goto out; } /* Check whether decryption was successful or not. */ if ((rx_pkt_status & (IWM_RX_MPDU_RES_STATUS_DEC_DONE | IWM_RX_MPDU_RES_STATUS_MIC_OK)) != (IWM_RX_MPDU_RES_STATUS_DEC_DONE | IWM_RX_MPDU_RES_STATUS_MIC_OK)) { ic->ic_stats.is_ccmp_dec_errs++; ret = 1; goto out; } rxi->rxi_flags |= IEEE80211_RXI_HWDEC; } out: if (ret) ifp->netStat->inputErrors++; ieee80211_release_node(ic, ni); return ret; } void ItlIwm:: iwm_rx_frame(struct iwm_softc *sc, mbuf_t m, int chanidx, uint32_t rx_pkt_status, int is_shortpre, int rate_n_flags, uint32_t device_timestamp, struct ieee80211_rxinfo *rxi, struct mbuf_list *ml) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_frame *wh; struct ieee80211_node *ni; struct _ifnet *ifp = IC2IFP(ic); if (chanidx < 0 || chanidx >= nitems(ic->ic_channels)) chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan); wh = mtod(m, struct ieee80211_frame *); ni = ieee80211_find_rxnode(ic, wh); if ((rxi->rxi_flags & IEEE80211_RXI_HWDEC) && iwm_ccmp_decap(sc, m, ni, rxi) != 0) { if (ifp->netStat) ifp->netStat->inputErrors++; mbuf_freem(m); ieee80211_release_node(ic, ni); return; } #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { struct iwm_rx_radiotap_header *tap = &sc->sc_rxtap; uint16_t chan_flags; tap->wr_flags = 0; if (is_shortpre) tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; tap->wr_chan_freq = htole16(ic->ic_channels[chanidx].ic_freq); chan_flags = ic->ic_channels[chanidx].ic_flags; if (ic->ic_curmode != IEEE80211_MODE_11N) chan_flags &= ~IEEE80211_CHAN_HT; tap->wr_chan_flags = htole16(chan_flags); tap->wr_dbm_antsignal = (int8_t)rxi->rxi_rssi; tap->wr_dbm_antnoise = (int8_t)sc->sc_noise; tap->wr_tsft = device_timestamp; if (rate_n_flags & IWM_RATE_MCS_HT_MSK) { uint8_t mcs = (rate_n_flags & (IWM_RATE_HT_MCS_RATE_CODE_MSK | IWM_RATE_HT_MCS_NSS_MSK)); tap->wr_rate = (0x80 | mcs); } else { uint8_t rate = (rate_n_flags & IWM_RATE_LEGACY_RATE_MSK); switch (rate) { /* CCK rates. */ case 10: tap->wr_rate = 2; break; case 20: tap->wr_rate = 4; break; case 55: tap->wr_rate = 11; break; case 110: tap->wr_rate = 22; break; /* OFDM rates. */ case 0xd: tap->wr_rate = 12; break; case 0xf: tap->wr_rate = 18; break; case 0x5: tap->wr_rate = 24; break; case 0x7: tap->wr_rate = 36; break; case 0x9: tap->wr_rate = 48; break; case 0xb: tap->wr_rate = 72; break; case 0x1: tap->wr_rate = 96; break; case 0x3: tap->wr_rate = 108; break; /* Unknown rate: should not happen. */ default: tap->wr_rate = 0; } } bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m, BPF_DIRECTION_IN); } #endif ieee80211_inputm(IC2IFP(ic), m, ni, rxi, ml); ieee80211_release_node(ic, ni); } #define IWM_AGG_TX_STATE_(x) case IWM_AGG_TX_STATE_ ## x: return #x static const char *iwm_get_agg_tx_status(u16 status) { switch (status & IWM_AGG_TX_STATE_STATUS_MSK) { IWM_AGG_TX_STATE_(TRANSMITTED); IWM_AGG_TX_STATE_(UNDERRUN); IWM_AGG_TX_STATE_(BT_PRIO); IWM_AGG_TX_STATE_(FEW_BYTES); IWM_AGG_TX_STATE_(ABORT); IWM_AGG_TX_STATE_(TX_ON_AIR_DROP); IWM_AGG_TX_STATE_(LAST_SENT_TRY_CNT); IWM_AGG_TX_STATE_(LAST_SENT_BT_KILL); IWM_AGG_TX_STATE_(SCD_QUERY); IWM_AGG_TX_STATE_(TEST_BAD_CRC32); IWM_AGG_TX_STATE_(RESPONSE); IWM_AGG_TX_STATE_(DUMP_TX); IWM_AGG_TX_STATE_(DELAY_TX); } return "UNKNOWN"; } #define IEEE80211_TX_MAX_RATES 4 static int ieee80211_tx_get_rates(struct iwm_softc *sc, struct ieee80211_tx_info *info, int *retry_count) { int count = -1; int i; int max_report_rates = 1; for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { if ((info->flags & IEEE80211_TX_CTL_AMPDU) && !(info->flags & IEEE80211_TX_STAT_AMPDU)) { /* just the first aggr frame carry status info */ info->status.rates[i].idx = -1; info->status.rates[i].count = 0; break; } else if (info->status.rates[i].idx < 0) { break; } else if (i >= max_report_rates) { /* the HW cannot have attempted that rate */ info->status.rates[i].idx = -1; info->status.rates[i].count = 0; break; } count += info->status.rates[i].count; } if (count < 0) count = 0; *retry_count = count; return i - 1; } void ieee80211_tx_status(struct iwm_softc *sc, struct ieee80211_tx_info *info, int tid, uint16_t fc, int ssn) { struct _ifnet *ifp = &sc->sc_ic.ic_ac.ac_if; int rates_idx, retry_count; if (!info) return; rates_idx = ieee80211_tx_get_rates(sc, info, &retry_count); rs_drv_mac80211_tx_status(sc, sc->sc_ic.ic_bss, info, tid, fc, ssn); if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && (info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && (ieee80211_is_data_qos(fc))) ifp->netStat->outputErrors++; } void ItlIwm:: iwm_ampdu_txq_advance(struct iwm_softc *sc, struct iwm_tx_ring *ring, int idx) { struct iwm_tx_data *txd; while (ring->tail != idx) { txd = &ring->data[ring->tail]; if (txd->m != NULL) { if (ring->qid < IWM_FIRST_AGG_TX_QUEUE) DPRINTF(("%s: missed Tx completion: tail=%d " "idx=%d\n", __func__, ring->tail, idx)); iwm_reset_sched(sc, ring->qid, ring->tail, IWM_STATION_ID); iwm_txd_done(sc, txd); ring->queued--; } ring->tail = (ring->tail + 1) % IWM_TX_RING_COUNT; } } void ItlIwm:: iwm_ampdu_rate_control(struct iwm_softc *sc, struct ieee80211_node *ni, struct iwm_tx_ring *ring, uint16_t seq, uint16_t ssn, struct ieee80211_tx_info *tx_info, int tid, uint32_t rate_n_flags) { int idx, end_idx; struct iwm_tx_ba *tid_data = &sc->sc_tx_ba[tid]; int freed = 0; bool rs_update = false; /* pack lq color from tid_data along the reduced txp */ tx_info->status.status_driver_data[0] = RS_DRV_DATA_PACK(tid_data->lq_color, tx_info->status.status_driver_data[0]); tx_info->status.status_driver_data[1] = (void *)(uintptr_t)rate_n_flags; /* * Update Tx rate statistics for A-MPDUs before firmware's BA window. */ idx = IWM_AGG_SSN_TO_TXQ_IDX(seq); end_idx = IWM_AGG_SSN_TO_TXQ_IDX(ssn); while (idx != end_idx) { struct iwm_tx_data *txdata = &ring->data[idx]; struct ieee80211_tx_info *info = &txdata->info; if (txdata->m != NULL) { rs_update = true; memset(&info->status, 0, sizeof(info->status)); /* Packet was transmitted successfully, failures come as single * frames because before failing a frame the firmware transmits * it without aggregation at least once. */ info->flags |= IEEE80211_TX_STAT_ACK; if (ieee80211_is_data_qos(txdata->fc)) freed++; else WARN_ON_ONCE(tid != IWL_MAX_TID_COUNT); /* this is the first skb we deliver in this batch */ /* put the rate scaling data there */ if (freed == 1) { info->flags |= IEEE80211_TX_STAT_AMPDU; memcpy(&info->status, &tx_info->status, sizeof(tx_info->status)); iwl_mvm_hwrate_to_tx_status(rate_n_flags, info); } ieee80211_tx_status(sc, info, tid, txdata->fc, ssn); } idx = (idx + 1) % IWM_TX_RING_COUNT; } /* We got a BA notif with 0 acked or scd_ssn didn't progress which is * possible (i.e. first MPDU in the aggregation wasn't acked) * Still it's important to update RS about sent vs. acked. */ if (!rs_update) { tx_info->band = IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; iwl_mvm_hwrate_to_tx_status(rate_n_flags, tx_info); DPRINTFN(3, ("No reclaim. Update rs directly\n")); iwl_mvm_rs_tx_status(sc, sc->sc_ic.ic_bss, tid, tx_info, false); } } void ItlIwm:: iwm_rx_tx_ba_notif(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_rx_data *data) { struct ieee80211_tx_ba *ba; struct ieee80211com *ic = &sc->sc_ic; struct iwm_ba_notif *ba_notif = (struct iwm_ba_notif *)pkt->data; struct iwm_tx_ring *ring; uint16_t ssn; int qid; struct ieee80211_node *ni = ic->ic_bss; struct iwm_node *in = (struct iwm_node *)ni; struct iwm_tx_ba *tid_data; struct ieee80211_tx_info ba_info = {}; DPRINTFN(3, ("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n", ba_notif->tid, le16_to_cpu(ba_notif->seq_ctl), le64_to_cpu(ba_notif->bitmap), le16_to_cpu(ba_notif->scd_flow), le16_to_cpu(ba_notif->scd_ssn), ba_notif->txed, ba_notif->txed_2_done)); if (ic->ic_state != IEEE80211_S_RUN) return; if (iwm_rx_packet_payload_len(pkt) < sizeof(*ba_notif)) return; if (ba_notif->sta_id != IWM_STATION_ID || !IEEE80211_ADDR_EQ(in->in_macaddr, ba_notif->sta_addr)) return; qid = le16toh(ba_notif->scd_flow); if (qid < IWM_FIRST_AGG_TX_QUEUE || qid > IWM_LAST_AGG_TX_QUEUE) return; /* Protect against a firmware bug where the queue/TID are off. */ if (qid != IWM_FIRST_AGG_TX_QUEUE + ba_notif->tid) return; sc->sc_tx_timer[qid] = 0; ba = &ni->ni_tx_ba[ba_notif->tid]; if (ba->ba_state != IEEE80211_BA_AGREED) return; ring = &sc->txq[qid]; /* * The firmware's new BA window starting sequence number * corresponds to the first hole in ban->scd_ssn, implying * that all frames between 'seq' and 'ssn' (non-inclusive) * have been acked. */ ssn = le16toh(ba_notif->scd_ssn); /* pack lq color from tid_data along the reduced txp */ tid_data = &sc->sc_tx_ba[ba_notif->tid]; ba_info.flags = IEEE80211_TX_STAT_AMPDU; ba_info.status.ampdu_ack_len = ba_notif->txed_2_done; ba_info.status.ampdu_len = ba_notif->txed; ba_info.status.tx_time = tid_data->tx_time; ba_info.status.status_driver_data[0] = (void *)(uintptr_t)ba_notif->reduced_txp; if (SEQ_LT(ssn, ba->ba_winstart)) return; /* Skip rate control if our Tx rate is fixed. */ if (ic->ic_fixed_mcs == -1) iwm_ampdu_rate_control(sc, ni, ring, ba->ba_winstart, ssn, &ba_info, ba_notif->tid, tid_data->rate_n_flags); /* * SSN corresponds to the first (perhaps not yet transmitted) frame * in firmware's BA window. Firmware is not going to retransmit any * frames before its BA window so mark them all as done. */ ieee80211_output_ba_move_window(ic, ni, ba_notif->tid, ssn); iwm_ampdu_txq_advance(sc, ring, IWM_AGG_SSN_TO_TXQ_IDX(ssn)); iwm_clear_oactive(sc, ring); } void ItlIwm:: iwm_ampdu_tx_done(struct iwm_softc *sc, struct iwm_cmd_header *cmd_hdr, struct iwm_node *in, struct iwm_tx_ring *txq, uint32_t initial_rate, uint8_t nframes, uint8_t failure_frame, uint16_t ssn, int status, struct iwm_agg_tx_status *agg_status) { struct ieee80211com *ic = &sc->sc_ic; int tid = cmd_hdr->qid - IWM_FIRST_AGG_TX_QUEUE; struct iwm_tx_data *txdata = &txq->data[cmd_hdr->idx]; struct ieee80211_node *ni = &in->in_ni; int txfail = (status != IWM_TX_STATUS_SUCCESS && status != IWM_TX_STATUS_DIRECT_DONE); struct ieee80211_tx_ba *ba; if (ic->ic_state != IEEE80211_S_RUN) return; if (nframes > 1) { return; } if (ni == NULL) return; ba = &ni->ni_tx_ba[tid]; if (ba->ba_state != IEEE80211_BA_AGREED) return; if (SEQ_LT(ssn, ba->ba_winstart)) return; /* This is a final single-frame Tx attempt. */ DPRINTFN(3, ("%s: final tx status=0x%x qid=%d queued=%d idx=%d ssn=%u " "bitmap=0x%llx\n", __func__, status, cmd_hdr->qid, txq->queued, cmd_hdr->idx, ssn, ba->ba_bitmap)); if (txfail) { ieee80211_tx_compressed_bar(ic, ni, tid, ssn); XYLog("%s sending bar ssn=%d tid=%d\n", __FUNCTION__, ssn, tid); } /* * SSN corresponds to the first (perhaps not yet transmitted) frame * in firmware's BA window. Firmware is not going to retransmit any * frames before its BA window so mark them all as done. */ ieee80211_output_ba_move_window(ic, ni, tid, ssn); } #define IWL_MVM_TX_RES_GET_TID(_ra_tid) ((_ra_tid) & 0x0f) #define TX_RES_INIT_RATE_INDEX_MSK 0x0f #define TX_RES_RATE_TABLE_COLOR_POS 4 #define TX_RES_RATE_TABLE_COLOR_MSK 0x70 #define TX_RES_INV_RATE_INDEX_MSK 0x80 #define TX_RES_RATE_TABLE_COL_GET(_f) (((_f) & TX_RES_RATE_TABLE_COLOR_MSK) >>\ TX_RES_RATE_TABLE_COLOR_POS) static inline struct iwm_agg_tx_status * iwl_mvm_get_agg_status(struct iwm_softc *sc, void *tx_resp) { return (struct iwm_agg_tx_status *)(((struct iwm_tx_resp *)tx_resp)->status); } static inline u32 iwl_mvm_get_scd_ssn(struct iwm_softc *sc, struct iwm_tx_resp *tx_resp) { return le32_to_cpup((__le32 *)iwl_mvm_get_agg_status(sc, tx_resp) + tx_resp->frame_count) & 0xfff; } void ItlIwm:: iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_tx_resp *tx_resp, int qid, int idx) { u32 status = le16toh(iwl_mvm_get_agg_status(sc, tx_resp)->status); u16 ssn = iwl_mvm_get_scd_ssn(sc, tx_resp); int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid); struct iwm_tx_data *txd; struct iwm_tx_ring *ring = &sc->txq[qid]; u8 skb_freed = 0; u8 lq_color; while (ring->tail != idx) { txd = &ring->data[ring->tail]; struct ieee80211_tx_info *info = &txd->info; bool flushed = false; if (txd->m != NULL) { skb_freed++; memset(&info->status, 0, sizeof(info->status)); info->flags &= ~(IEEE80211_TX_STAT_ACK | IEEE80211_TX_STAT_TX_FILTERED); /* inform mac80211 about what happened with the frame */ switch (status & IWM_TX_STATUS_MSK) { case IWM_TX_STATUS_SUCCESS: case IWM_TX_STATUS_DIRECT_DONE: info->flags |= IEEE80211_TX_STAT_ACK; break; case IWM_TX_STATUS_FAIL_FIFO_FLUSHED: case IWM_TX_STATUS_FAIL_DRAIN_FLOW: flushed = true; break; case IWM_TX_STATUS_FAIL_DEST_PS: /* the FW should have stopped the queue and not * return this status */ WARN_ON(1); info->flags |= IEEE80211_TX_STAT_TX_FILTERED; break; default: break; } if ((status & IWM_TX_STATUS_MSK) != IWM_TX_STATUS_SUCCESS && ieee80211_is_mgmt(txd->fc)) iwm_toggle_tx_ant(sc, &sc->sc_mgmt_last_antenna_idx); if ((status & IWM_TX_STATUS_MSK) != IWM_TX_STATUS_SUCCESS && sc->sc_ic.ic_state <= IEEE80211_S_RUN) iwm_toggle_tx_ant(sc, &sc->sc_tx_ant); /* * If we are freeing multiple frames, mark all the frames * but the first one as acked, since they were acknowledged * before * */ if (skb_freed > 1) info->flags |= IEEE80211_TX_STAT_ACK; info->status.rates[0].count = tx_resp->failure_frame + 1; iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate), info); info->status.status_driver_data[1] = (void *)(uintptr_t)le32_to_cpu(tx_resp->initial_rate); /* Single frame failure in an AMPDU queue => send BAR */ if (info->flags & IEEE80211_TX_CTL_AMPDU && !(info->flags & IEEE80211_TX_STAT_ACK) && !(info->flags & IEEE80211_TX_STAT_TX_FILTERED) && !flushed) info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; info->flags &= ~IEEE80211_TX_CTL_AMPDU; /* * TODO: this is not accurate if we are freeing more than one * packet. */ info->status.tx_time = le16_to_cpu(tx_resp->wireless_media_time); BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); lq_color = TX_RES_RATE_TABLE_COL_GET(tx_resp->tlc_info); info->status.status_driver_data[0] = RS_DRV_DATA_PACK(lq_color, tx_resp->reduced_tpc); ieee80211_tx_status(sc, info, tid, txd->fc, ssn); iwm_reset_sched(sc, ring->qid, ring->tail, IWM_STATION_ID); iwm_txd_done(sc, txd); ring->queued--; } ring->tail = (ring->tail + 1) % IWM_TX_RING_COUNT; } } void ItlIwm:: iwm_txd_done(struct iwm_softc *sc, struct iwm_tx_data *txd) { struct ieee80211com *ic = &sc->sc_ic; // bus_dmamap_sync(sc->sc_dmat, txd->map, 0, txd->map->dm_mapsize, // BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, txd->map); if (txd->m) { mbuf_freem(txd->m); txd->m = NULL; } KASSERT(txd->in, "txd->in"); ieee80211_release_node(ic, &txd->in->in_ni); txd->in = NULL; txd->totlen = 0; txd->txmcs = 0; txd->txrate = 0; txd->fc = 0; memset(&txd->info, 0, sizeof(struct ieee80211_tx_info)); } void ItlIwm:: iwm_clear_oactive(struct iwm_softc *sc, struct iwm_tx_ring *ring) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; if (ring->queued < IWM_TX_RING_LOMARK) { sc->qfullmsk &= ~(1 << ring->qid); if (sc->qfullmsk == 0 && ifq_is_oactive(&ifp->if_snd)) { ifq_clr_oactive(&ifp->if_snd); (*ifp->if_start)(ifp); } #ifdef __PRIVATE_SPI__ ifp->iface->signalOutputThread(); #endif } } #define TX_RES_INIT_RATE_INDEX_MSK 0x0f #define TX_RES_RATE_TABLE_COLOR_POS 4 #define TX_RES_RATE_TABLE_COLOR_MSK 0x70 #define TX_RES_INV_RATE_INDEX_MSK 0x80 #define TX_RES_RATE_TABLE_COL_GET(_f) (((_f) & TX_RES_RATE_TABLE_COLOR_MSK) >>\ TX_RES_RATE_TABLE_COLOR_POS) void ItlIwm:: iwm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_rx_data *data) { struct iwm_cmd_header *cmd_hdr = &pkt->hdr; int idx = cmd_hdr->idx; int qid = cmd_hdr->qid; struct iwm_tx_ring *ring; struct iwm_tx_data *txd; struct iwm_tx_resp *tx_resp = (struct iwm_tx_resp *)pkt->data; uint32_t ssn; uint32_t len = iwm_rx_packet_len(pkt); struct iwm_tx_ba *tid_data; bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE, BUS_DMASYNC_POSTREAD); /* Sanity checks. */ if (sizeof(*tx_resp) > len) return; if (qid < IWM_FIRST_AGG_TX_QUEUE && tx_resp->frame_count > 1) return; if (qid > IWM_LAST_AGG_TX_QUEUE) return; if (sizeof(*tx_resp) + sizeof(ssn) + tx_resp->frame_count * sizeof(struct iwm_agg_tx_status) > len) return; sc->sc_tx_timer[qid] = 0; ring = &sc->txq[qid]; txd = &ring->data[idx]; if (tx_resp->frame_count > 1) { for (int i = 0; i < tx_resp->frame_count; i++) { struct iwm_agg_tx_status *frame_status = iwl_mvm_get_agg_status(sc, tx_resp); u16 fstatus = le16_to_cpu(frame_status[i].status); DPRINTFN(3, ("status %s (0x%04x), try-count (%d) qid (%d) seq (0x%x)\n", iwm_get_agg_tx_status(fstatus), fstatus & IWM_AGG_TX_STATE_STATUS_MSK, (fstatus & IWM_AGG_TX_STATE_TRY_CNT_MSK) >> IWM_AGG_TX_STATE_TRY_CNT_POS, qid, le16_to_cpu(frame_status[i].idx))); } int tid = cmd_hdr->qid - IWM_FIRST_AGG_TX_QUEUE; if (tid < 0) return; tid_data = &sc->sc_tx_ba[tid]; tid_data->lq_color = TX_RES_RATE_TABLE_COL_GET(tx_resp->tlc_info); tid_data->tx_time = le16toh(tx_resp->wireless_media_time); tid_data->rate_n_flags = le32toh(tx_resp->initial_rate); return; } DPRINTFN(2, ("%s idx=%d qid=%d txd->txmcs=%d txd->txrate=%d, frame_count=%d len=%d\n", __FUNCTION__, idx, qid, txd->txmcs, txd->txrate, ((struct iwm_tx_resp *)pkt->data)->frame_count, ((struct iwm_tx_resp *)pkt->data)->byte_cnt)); ssn = iwm_get_scd_ssn(tx_resp); iwm_rx_tx_cmd_single(sc, tx_resp, qid, IWM_AGG_SSN_TO_TXQ_IDX(ssn)); if (qid >= IWM_FIRST_AGG_TX_QUEUE) { int status; status = le16toh(iwl_mvm_get_agg_status(sc, tx_resp)->status) & IWM_TX_STATUS_MSK; iwm_ampdu_tx_done(sc, cmd_hdr, txd->in, ring, le32toh(tx_resp->initial_rate), tx_resp->frame_count, tx_resp->failure_frame, ssn, status, iwl_mvm_get_agg_status(sc, tx_resp)); } iwm_clear_oactive(sc, ring); } void ItlIwm:: iwm_rx_bmiss(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_rx_data *data) { struct ieee80211com *ic = &sc->sc_ic; struct iwm_missed_beacons_notif *mbn = (struct iwm_missed_beacons_notif *)pkt->data; uint32_t missed; if ((ic->ic_opmode != IEEE80211_M_STA) || (ic->ic_state != IEEE80211_S_RUN)) return; // bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*pkt), // sizeof(*mbn), BUS_DMASYNC_POSTREAD); missed = le32toh(mbn->consec_missed_beacons_since_last_rx); if (missed > ic->ic_bmissthres && ic->ic_mgt_timer == 0) { if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: receiving no beacons from %s; checking if " "this AP is still responding to probe requests\n", DEVNAME(sc), ether_sprintf(ic->ic_bss->ni_macaddr)); /* * Rather than go directly to scan state, try to send a * directed probe request first. If that fails then the * state machine will drop us into scanning after timing * out waiting for a probe response. */ IEEE80211_SEND_MGMT(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); } } static int iwm_rate2ridx(struct iwm_softc *sc, int rate) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; int ridx = -1, i; int min_ridx = (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) ? IWL_FIRST_OFDM_RATE : IWL_FIRST_CCK_RATE; for (i = 0; i < ieee80211_std_rateset_11g.rs_nrates; i++) { if (ieee80211_std_rateset_11g.rs_rates[i] == rate) { ridx = i; break; } } return ridx == -1 ? min_ridx : ridx; } /* * Fill in various bit for management frames, and leave them * unfilled for data frames (firmware takes care of that). * Return the selected TX rate. */ const struct iwl_rs_rate_info *ItlIwm:: iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in, struct ieee80211_frame *wh, struct iwm_tx_cmd *tx) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = &in->in_ni; int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; int subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; int ridx = -1, rate_flags; int min_ridx = iwm_rate2ridx(sc, ieee80211_min_basic_rate(ic)); tx->rts_retry_limit = IWM_RTS_DFAULT_RETRY_LIMIT; if (type == IEEE80211_FC0_TYPE_CTL && subtype == IEEE80211_FC0_SUBTYPE_BAR) tx->data_retry_limit = IWM_BAR_DFAULT_RETRY_LIMIT; else tx->data_retry_limit = IWM_DEFAULT_TX_RETRY; if (IEEE80211_IS_MULTICAST(wh->i_addr1) || type != IEEE80211_FC0_TYPE_DATA) { /* for non-data, use the lowest supported rate */ ridx = min_ridx; tx->data_retry_limit = IWM_MGMT_DFAULT_RETRY_LIMIT; } else if (ic->ic_fixed_mcs != -1) { if (ni->ni_flags & IEEE80211_NODE_VHT) ridx = IWL_FIRST_OFDM_RATE; else ridx = sc->sc_fixed_ridx; } else if (ic->ic_fixed_rate != -1) { ridx = sc->sc_fixed_ridx; } else { /* Use firmware rateset retry table. */ tx->initial_rate_index = 0; tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE); if (ni->ni_flags & IEEE80211_NODE_HT) /* VHT implies HT */ return 0; return &iwl_rates[iwm_rate2ridx(sc, ni->ni_txrate)]; } if (ridx == -1 || ridx >= IWL_RATE_COUNT_LEGACY) ridx = min_ridx; rate_flags = iwm_get_tx_ant(sc, ni, type, wh); XYLog("%s ridx=%d ant=%d\n", __FUNCTION__, ridx, (rate_flags >> RATE_MCS_ANT_POS)); /* Set CCK flag as needed */ if ((ridx >= IWL_FIRST_CCK_RATE) && (ridx <= IWL_LAST_CCK_RATE)) rate_flags |= RATE_MCS_CCK_MSK; tx->rate_n_flags = htole32(rate_flags | iwl_mvm_mac80211_idx_to_hwrate(ridx)); return &iwl_rates[ridx]; } #define TB0_SIZE 20 int ItlIwm:: iwm_tx(struct iwm_softc *sc, mbuf_t m, struct ieee80211_node *ni, int ac) { struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ni; struct iwm_tx_ring *ring; struct iwm_tx_data *data; struct iwm_tfd *desc; struct iwm_device_cmd *cmd; struct iwm_tx_cmd *tx; struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; const struct iwl_rs_rate_info *rinfo; uint8_t *ivp; uint32_t flags; u_int hdrlen; IOPhysicalSegment *seg; IOPhysicalSegment segs[IWM_NUM_OF_TBS - 2]; int nsegs = 0; uint8_t tid, type, subtype; int i, totlen, hasqos; int rtsthres = ic->ic_rtsthreshold; int qid; uint16_t len, tb1_len; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (type == IEEE80211_FC0_TYPE_CTL) hdrlen = sizeof(struct ieee80211_frame_min); else hdrlen = ieee80211_get_hdrlen(wh); hasqos = ieee80211_has_qos(wh); if (type == IEEE80211_FC0_TYPE_DATA) tid = IWM_TID_NON_QOS; else tid = IWM_MAX_TID_COUNT; /* * Map EDCA categories to Tx data queues. * * We use static data queue assignments even in DQA mode. We do not * need to share Tx queues between stations because we only implement * client mode; the firmware's station table contains only one entry * which represents our access point. */ if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) qid = IWM_DQA_MIN_MGMT_QUEUE + ac; else qid = ac; if (hasqos) { struct ieee80211_tx_ba *ba; uint16_t qos = ieee80211_get_qos(wh); int qostid = qos & IEEE80211_QOS_TID; int agg_qid = IWM_FIRST_AGG_TX_QUEUE + qostid; ba = &ni->ni_tx_ba[qostid]; if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && type == IEEE80211_FC0_TYPE_DATA && subtype != IEEE80211_FC0_SUBTYPE_NODATA && sc->sc_tx_ba[tid].wn == in && ba->ba_state == IEEE80211_BA_AGREED) { qid = agg_qid; tid = qostid; ac = ieee80211_up_to_ac(ic, qostid); } } ring = &sc->txq[qid]; desc = &ring->desc[ring->cur]; memset(desc, 0, sizeof(*desc)); data = &ring->data[ring->cur]; cmd = &ring->cmd[ring->cur]; cmd->hdr.code = IWM_TX_CMD; cmd->hdr.flags = 0; cmd->hdr.qid = ring->qid; cmd->hdr.idx = ring->cur; tx = (struct iwm_tx_cmd *)cmd->data; memset(tx, 0, sizeof(*tx)); rinfo = iwm_tx_fill_cmd(sc, in, wh, tx); #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { struct iwm_tx_radiotap_header *tap = &sc->sc_txtap; uint16_t chan_flags; tap->wt_flags = 0; tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); chan_flags = ni->ni_chan->ic_flags; if (ic->ic_curmode != IEEE80211_MODE_11N) chan_flags &= ~IEEE80211_CHAN_HT; tap->wt_chan_flags = htole16(chan_flags); if ((ni->ni_flags & IEEE80211_NODE_HT) && !IEEE80211_IS_MULTICAST(wh->i_addr1) && type == IEEE80211_FC0_TYPE_DATA && rinfo->ht_plcp != IWM_RATE_HT_SISO_MCS_INV_PLCP) { tap->wt_rate = (0x80 | rinfo->ht_plcp); } else tap->wt_rate = rinfo->rate; if ((ic->ic_flags & IEEE80211_F_WEPON) && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_txtap_len, m, BPF_DIRECTION_OUT); } #endif totlen = mbuf_pkthdr_len(m); if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_get_txkey(ic, wh, ni); if ((k->k_flags & IEEE80211_KEY_GROUP) || (k->k_cipher != IEEE80211_CIPHER_CCMP)) { if ((m = ieee80211_encrypt(ic, m, k)) == NULL) return ENOBUFS; /* 802.11 header may have moved. */ wh = mtod(m, struct ieee80211_frame *); totlen = mbuf_pkthdr_len(m); k = NULL; /* skip hardware crypto below */ } else { /* HW appends CCMP MIC */ totlen += IEEE80211_CCMP_HDRLEN; } } flags = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) flags |= IWM_TX_CMD_FLG_ACK; if (type == IEEE80211_FC0_TYPE_DATA && !IEEE80211_IS_MULTICAST(wh->i_addr1) && (totlen + IEEE80211_CRC_LEN > rtsthres || (ic->ic_flags & IEEE80211_F_USEPROT))) flags |= IWM_TX_CMD_FLG_PROT_REQUIRE; if (type == IEEE80211_FC0_TYPE_CTL && subtype == IEEE80211_FC0_SUBTYPE_BAR) { struct ieee80211_frame_min *mwh; uint8_t *barfrm; uint16_t ctl; mwh = mtod(m, struct ieee80211_frame_min *); barfrm = (uint8_t *)&mwh[1]; ctl = LE_READ_2(barfrm); tid = (ctl & IEEE80211_BA_TID_INFO_MASK) >> IEEE80211_BA_TID_INFO_SHIFT; flags |= (IWM_TX_CMD_FLG_ACK | IWM_TX_CMD_FLG_BAR); } tx->sta_id = IWM_STATION_ID; if (type == IEEE80211_FC0_TYPE_MGT) { if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) tx->pm_frame_timeout = htole16(3); else if (subtype == IEEE80211_FC0_SUBTYPE_ACTION) tx->pm_frame_timeout = htole16(0); else tx->pm_frame_timeout = htole16(2); } else { tx->pm_frame_timeout = htole16(0); } len = sizeof(struct iwm_tx_cmd) + sizeof(struct iwm_cmd_header) + hdrlen - TB0_SIZE; tb1_len = _ALIGN(len, 4); /* Tell NIC about any 2-byte padding after MAC header */ if (tb1_len != len) { flags |= IWM_TX_CMD_FLG_MH_PAD; tx->offload_assist |= htole16(IWM_TX_CMD_OFFLD_PAD); } tx->driver_txop = 0; tx->len = htole16(totlen); tx->tid_tspec = tid; tx->life_time = htole32(IWM_TX_CMD_LIFE_TIME_INFINITE); /* Set physical address of "scratch area". */ tx->dram_lsb_ptr = htole32(data->scratch_paddr); tx->dram_msb_ptr = iwm_get_dma_hi_addr(data->scratch_paddr); /* Copy 802.11 header in TX command. */ memcpy(((uint8_t *)tx) + sizeof(*tx), wh, hdrlen); if (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP) { /* Trim 802.11 header and prepend CCMP IV. */ mbuf_adj(m, hdrlen - IEEE80211_CCMP_HDRLEN); ivp = mtod(m, u_int8_t *); k->k_tsc++; /* increment the 48-bit PN */ ivp[0] = k->k_tsc; /* PN0 */ ivp[1] = k->k_tsc >> 8; /* PN1 */ ivp[2] = 0; /* Rsvd */ ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; ivp[4] = k->k_tsc >> 16; /* PN2 */ ivp[5] = k->k_tsc >> 24; /* PN3 */ ivp[6] = k->k_tsc >> 32; /* PN4 */ ivp[7] = k->k_tsc >> 40; /* PN5 */ tx->sec_ctl = IWM_TX_CMD_SEC_CCM; memcpy(tx->key, k->k_key, MIN(sizeof(tx->key), k->k_len)); } else { /* Trim 802.11 header. */ mbuf_adj(m, hdrlen); tx->sec_ctl = 0; } flags |= (iwm_coex_tx_prio(sc, wh, ac) << IWM_TX_CMD_FLG_BT_PRIO_POS); if (!hasqos) flags |= IWM_TX_CMD_FLG_SEQ_CTL; tx->tx_flags |= htole32(flags); nsegs = data->map->cursor->getPhysicalSegmentsWithCoalesce(m, &segs[0], IWM_NUM_OF_TBS - 2); // XYLog("map frame dm_nsegs=%d\n", data->map->dm_nsegs); if (nsegs == 0) { XYLog("%s: can't map mbuf (error %d)\n", DEVNAME(sc), data->map->dm_nsegs); mbuf_freem(m); return ENOMEM; } data->m = m; data->in = in; data->txmcs = ni->ni_txmcs; data->txrate = ni->ni_txrate; data->totlen = totlen; memcpy(&data->fc, &wh->i_fc[0], sizeof(uint16_t)); data->info.band = IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; DPRINTFN(3, ("sending data: 嘤嘤嘤 qid=%d idx=%d len=%d nsegs=%d txflags=0x%08x rate_n_flags=0x%08x rateidx=%u txmcs=%d ni_txrate=%d\n", ring->qid, ring->cur, totlen, nsegs, le32toh(tx->tx_flags), le32toh(tx->rate_n_flags), tx->initial_rate_index, data->txmcs, data->txrate)); /* Fill TX descriptor. */ desc->num_tbs = 2 + nsegs; desc->tbs[0].lo = htole32(data->cmd_paddr); desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr) | (TB0_SIZE << 4)); desc->tbs[1].lo = htole32(data->cmd_paddr + TB0_SIZE); desc->tbs[1].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr) | (tb1_len << 4)); /* Other DMA segments are for data payload. */ for (i = 0; i < nsegs; i++) { seg = &segs[i]; desc->tbs[i+2].lo = htole32(seg->location); desc->tbs[i+2].hi_n_len = htole16(iwm_get_dma_hi_addr(seg->location) | ((seg->length) << 4)); // XYLog("DMA segments index=%d location=0x%llx length=%llu", i, seg->location, seg->length); } // XYLog("----------end sending data------\n"); // bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, // BUS_DMASYNC_PREWRITE); // bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map, // (char *)(void *)cmd - (char *)(void *)ring->cmd_dma.vaddr, // sizeof (*cmd), BUS_DMASYNC_PREWRITE); // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, // (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr, // sizeof (*desc), BUS_DMASYNC_PREWRITE); iwm_update_sched(sc, ring->qid, ring->cur, tx->sta_id, le16toh(tx->len)); /* Kick TX ring. */ ring->cur = (ring->cur + 1) % IWM_TX_RING_COUNT; IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); /* Mark TX ring as full if we reach a certain threshold. */ if (++ring->queued > IWM_TX_RING_HIMARK) { // XYLog("%s qid=%d sc->qfullmsk is FULL ring->cur=%d ring->queued=%d\n", __FUNCTION__, ring->qid, ring->cur, ring->queued); sc->qfullmsk |= 1 << ring->qid; } if (ic->ic_if.if_flags & IFF_UP) sc->sc_tx_timer[ring->qid] = 15; return 0; } #define IWM_TX_CRC_SIZE 4 #define IWM_TX_DELIMITER_SIZE 4 void ItlIwm:: iwm_update_sched(struct iwm_softc *sc, int qid, int cur, uint8_t sta_id, uint16_t len) { DPRINTFN(3, ("%s qid=%d cur=%d sta=%d len=%d\n", __FUNCTION__, qid, cur, sta_id, len)); struct iwm_agn_scd_bc_tbl *scd_bc_tbl; uint8_t sec_ctl = 0; uint16_t bc_ent; struct iwm_tx_ring *txq = &sc->txq[qid]; iwm_tx_cmd *tx = (struct iwm_tx_cmd *)txq->cmd; sec_ctl = tx->sec_ctl; scd_bc_tbl = (struct iwm_agn_scd_bc_tbl *)sc->sched_dma.vaddr; len += (IWM_TX_CRC_SIZE + IWM_TX_DELIMITER_SIZE); switch (sec_ctl & IWM_TX_CMD_SEC_MSK) { case IWM_TX_CMD_SEC_CCM: len += IEEE80211_CCMP_MICLEN; break; case IWM_TX_CMD_SEC_TKIP: len += IEEE80211_TKIP_ICVLEN; break; case IWM_TX_CMD_SEC_WEP: len += IEEE80211_WEP_IVLEN + IEEE80211_WEP_ICVLEN; break; } len = howmany(len, 4); bc_ent = htole16(len | (IWM_STATION_ID << 12)); scd_bc_tbl[qid].tfd_offset[cur] = bc_ent; if (cur < IWM_TFD_QUEUE_SIZE_BC_DUP) { scd_bc_tbl[qid].tfd_offset[IWM_TFD_QUEUE_SIZE_MAX + cur] = bc_ent; } } void ItlIwm:: iwm_reset_sched(struct iwm_softc *sc, int qid, int idx, uint8_t sta_id) { DPRINTFN(3, ("%s qid=%d idx=%d\n", __FUNCTION__, qid, idx)); struct iwm_agn_scd_bc_tbl *scd_bc_tbl; uint16_t val; scd_bc_tbl = (struct iwm_agn_scd_bc_tbl *)sc->sched_dma.vaddr; val = htole16(1 | (sta_id << 12)); /* Update TX scheduler. */ scd_bc_tbl[qid].tfd_offset[idx] = val; if (idx < IWM_TFD_QUEUE_SIZE_BC_DUP) scd_bc_tbl[qid].tfd_offset[IWM_TFD_QUEUE_SIZE_MAX + idx] = val; } int ItlIwm:: iwm_flush_tx_path(struct iwm_softc *sc, int tfd_queue_msk) { struct iwm_tx_path_flush_cmd_v1 flush_cmd = { .queues_ctl = htole32(tfd_queue_msk), .flush_ctl = htole16(IWM_DUMP_TX_FIFO_FLUSH), }; int err; err = iwm_send_cmd_pdu(sc, IWM_TXPATH_FLUSH, 0, sizeof(flush_cmd), &flush_cmd); if (err) XYLog("%s: Flushing tx queue failed: %d\n", DEVNAME(sc), err); return err; } static uint8_t iwm_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_edca_ac ac) { static const uint8_t mac80211_ac_to_ucode_ac[] = { IWM_AC_BE, IWM_AC_BK, IWM_AC_VI, IWM_AC_VO, }; return mac80211_ac_to_ucode_ac[ac]; } void ItlIwm:: iwm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in, struct iwm_mac_ctx_cmd *cmd, uint32_t action) { #define IWM_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; int cck_ack_rates, ofdm_ack_rates; int i; cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); cmd->action = htole32(action); if (ic->ic_opmode == IEEE80211_M_MONITOR) cmd->mac_type = htole32(IWM_FW_MAC_TYPE_LISTENER); else if (ic->ic_opmode == IEEE80211_M_STA) cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA); else panic("unsupported operating mode %d\n", ic->ic_opmode); cmd->tsf_id = htole32(IWM_TSF_ID_A); IEEE80211_ADDR_COPY(cmd->node_addr, ic->ic_myaddr); if (ic->ic_opmode == IEEE80211_M_MONITOR) { IEEE80211_ADDR_COPY(cmd->bssid_addr, etherbroadcastaddr); return; } IEEE80211_ADDR_COPY(cmd->bssid_addr, in->in_macaddr); iwm_ack_rates(sc, in, &cck_ack_rates, &ofdm_ack_rates); cmd->cck_rates = htole32(cck_ack_rates); cmd->ofdm_rates = htole32(ofdm_ack_rates); cmd->cck_short_preamble = htole32((ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? IWM_MAC_FLG_SHORT_PREAMBLE : 0); cmd->short_slot = htole32((ic->ic_flags & IEEE80211_F_SHSLOT) ? IWM_MAC_FLG_SHORT_SLOT : 0); for (i = 0; i < EDCA_NUM_AC; i++) { struct ieee80211_edca_ac_params *ac = &ic->ic_edca_ac[i]; int txf = iwm_ac_to_tx_fifo[i]; uint8_t ucode_ac = iwm_mvm_mac80211_ac_to_ucode_ac((enum ieee80211_edca_ac)i); cmd->ac[ucode_ac].cw_min = htole16(IWM_EXP2(ac->ac_ecwmin)); cmd->ac[ucode_ac].cw_max = htole16(IWM_EXP2(ac->ac_ecwmax)); cmd->ac[ucode_ac].aifsn = ac->ac_aifsn; cmd->ac[ucode_ac].fifos_mask = (1 << txf); cmd->ac[ucode_ac].edca_txop = htole16(ac->ac_txoplimit * 32); } if (ni->ni_flags & IEEE80211_NODE_QOS) cmd->qos_flags |= htole32(IWM_MAC_QOS_FLG_UPDATE_EDCA); if (ni->ni_flags & IEEE80211_NODE_HT) { enum ieee80211_htprot htprot = (enum ieee80211_htprot)(ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK); /* The fw does not distinguish between ht and fat */ uint32_t ht_flag = IWM_MAC_PROT_FLG_HT_PROT | IWM_MAC_PROT_FLG_FAT_PROT; /* * See section 9.23.3.1 of IEEE 80211-2012. * Nongreenfield HT STAs Present is not supported. */ switch (htprot) { case IEEE80211_HTPROT_NONE: break; case IEEE80211_HTPROT_NONMEMBER: case IEEE80211_HTPROT_NONHT_MIXED: cmd->protection_flags = htole32(ht_flag); break; case IEEE80211_HTPROT_20MHZ: /* Protect when channel wider than 20MHz */ if (ni->ni_chw > IEEE80211_CHAN_WIDTH_20) cmd->protection_flags = htole32(ht_flag); break; default: XYLog("Illegal protection mode %d\n", htprot); break; } cmd->qos_flags |= htole32(IWM_MAC_QOS_FLG_TGN); } if (ic->ic_flags & IEEE80211_F_USEPROT) cmd->protection_flags |= htole32(IWM_MAC_PROT_FLG_TGG_PROTECT); cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP); #undef IWM_EXP2 } void ItlIwm:: iwm_mac_ctxt_cmd_fill_sta(struct iwm_softc *sc, struct iwm_node *in, struct iwm_mac_data_sta *sta, int assoc) { struct ieee80211_node *ni = &in->in_ni; uint32_t dtim_off; uint64_t tsf; dtim_off = ni->ni_dtimcount * ni->ni_intval * IEEE80211_DUR_TU; memcpy(&tsf, ni->ni_tstamp, sizeof(tsf)); tsf = letoh64(tsf); sta->is_assoc = htole32(assoc); sta->dtim_time = htole32(ni->ni_rstamp + dtim_off); sta->dtim_tsf = htole64(tsf + dtim_off); sta->bi = htole32(ni->ni_intval); sta->bi_reciprocal = htole32(iwm_reciprocal(ni->ni_intval)); sta->dtim_interval = htole32(ni->ni_intval * ni->ni_dtimperiod); sta->dtim_reciprocal = htole32(iwm_reciprocal(sta->dtim_interval)); sta->listen_interval = htole32(10); sta->assoc_id = htole32(ni->ni_associd); sta->assoc_beacon_arrive_time = htole32(ni->ni_rstamp); } int ItlIwm:: iwm_mac_ctxt_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action, int assoc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = &in->in_ni; struct iwm_mac_ctx_cmd cmd; int active = (sc->sc_flags & IWM_FLAG_MAC_ACTIVE); if (action == IWM_FW_CTXT_ACTION_ADD && active) { XYLog("MAC already added"); return 0; } if (action == IWM_FW_CTXT_ACTION_REMOVE && !active) { XYLog("MAC already removed"); return 0; } memset(&cmd, 0, sizeof(cmd)); iwm_mac_ctxt_cmd_common(sc, in, &cmd, action); if (ic->ic_opmode == IEEE80211_M_MONITOR) { cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_PROMISC | IWM_MAC_FILTER_IN_CONTROL_AND_MGMT | IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON | IWM_MAC_FILTER_IN_PROBE_REQUEST | IWM_MAC_FILTER_IN_CRC32); } else if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod) /* * Allow beacons to pass through as long as we are not * associated or we do not have dtim period information. */ cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_BEACON); else iwm_mac_ctxt_cmd_fill_sta(sc, in, &cmd.sta, assoc); return iwm_send_cmd_pdu(sc, IWM_MAC_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } int ItlIwm:: iwm_update_quotas(struct iwm_softc *sc, struct iwm_node *in, int running) { struct iwm_time_quota_cmd_v1 cmd; int i, idx, num_active_macs, quota, quota_rem; int colors[IWM_MAX_BINDINGS] = { -1, -1, -1, -1, }; int n_ifs[IWM_MAX_BINDINGS] = {0, }; uint16_t id; memset(&cmd, 0, sizeof(cmd)); /* currently, PHY ID == binding ID */ if (in && in->in_phyctxt) { id = in->in_phyctxt->id; KASSERT(id < IWM_MAX_BINDINGS, "id < IWM_MAX_BINDINGS"); colors[id] = in->in_phyctxt->color; if (running) n_ifs[id] = 1; } /* * The FW's scheduling session consists of * IWM_MAX_QUOTA fragments. Divide these fragments * equally between all the bindings that require quota */ num_active_macs = 0; for (i = 0; i < IWM_MAX_BINDINGS; i++) { cmd.quotas[i].id_and_color = htole32(IWM_FW_CTXT_INVALID); num_active_macs += n_ifs[i]; } quota = 0; quota_rem = 0; if (num_active_macs) { quota = IWM_MAX_QUOTA / num_active_macs; quota_rem = IWM_MAX_QUOTA % num_active_macs; } for (idx = 0, i = 0; i < IWM_MAX_BINDINGS; i++) { if (colors[i] < 0) continue; cmd.quotas[idx].id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(i, colors[i])); if (n_ifs[i] <= 0) { cmd.quotas[idx].quota = htole32(0); cmd.quotas[idx].max_duration = htole32(0); } else { cmd.quotas[idx].quota = htole32(quota * n_ifs[i]); cmd.quotas[idx].max_duration = htole32(0); } idx++; } /* Give the remainder of the session to the first binding */ cmd.quotas[0].quota = htole32(le32toh(cmd.quotas[0].quota) + quota_rem); if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_QUOTA_LOW_LATENCY)) { struct iwm_time_quota_cmd cmd_v2; memset(&cmd_v2, 0, sizeof(cmd_v2)); for (i = 0; i < IWM_MAX_BINDINGS; i++) { cmd_v2.quotas[i].id_and_color = cmd.quotas[i].id_and_color; cmd_v2.quotas[i].quota = cmd.quotas[i].quota; cmd_v2.quotas[i].max_duration = cmd.quotas[i].max_duration; } return iwm_send_cmd_pdu(sc, IWM_TIME_QUOTA_CMD, 0, sizeof(cmd_v2), &cmd_v2); } return iwm_send_cmd_pdu(sc, IWM_TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd); } int ItlIwm:: iwm_auth(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; uint32_t duration; int generation = sc->sc_generation, err; splassert(IPL_NET); in->in_ni.ni_chw = IEEE80211_CHAN_WIDTH_20_NOHT; in->in_ni.ni_flags &= ~(IEEE80211_NODE_HT | IEEE80211_NODE_QOS | IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40 | IEEE80211_NODE_VHT | IEEE80211_NODE_VHT_SGI80 | IEEE80211_NODE_VHT_SGI160); if (ic->ic_opmode == IEEE80211_M_MONITOR) { err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0], ic->ic_ibss_chan, 1, 1, 0); if (err) return err; } else { err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0], in->in_ni.ni_chan, 1, 1, 0); if (err) return err; } in->in_phyctxt = &sc->sc_phyctxt[0]; IEEE80211_ADDR_COPY(in->in_macaddr, in->in_ni.ni_macaddr); err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD, 0); if (err) { XYLog("%s: could not add MAC context (error %d)\n", DEVNAME(sc), err); return err; } sc->sc_flags |= IWM_FLAG_MAC_ACTIVE; err = iwm_binding_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD); if (err) { XYLog("%s: could not add binding (error %d)\n", DEVNAME(sc), err); goto rm_mac_ctxt; } sc->sc_flags |= IWM_FLAG_BINDING_ACTIVE; err = iwm_add_sta_cmd(sc, in, 0, 0); if (err) { XYLog("%s: could not add sta (error %d)\n", DEVNAME(sc), err); goto rm_binding; } iwm_toggle_tx_ant(sc, &sc->sc_tx_ant); if (ic->ic_opmode == IEEE80211_M_MONITOR) return 0; /* * Prevent the FW from wandering off channel during association * by "protecting" the session with a time event. */ if (in->in_ni.ni_intval) duration = in->in_ni.ni_intval * 2; else duration = IEEE80211_DUR_TU; iwm_protect_session(sc, in, duration, in->in_ni.ni_intval / 2); rs_drv_alloc_sta(sc, &in->in_ni); iwl_mvm_rs_rate_init(sc, ic->ic_bss, IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ, false); return 0; rm_binding: if (generation == sc->sc_generation) { iwm_binding_cmd(sc, in, IWM_FW_CTXT_ACTION_REMOVE); sc->sc_flags &= ~IWM_FLAG_BINDING_ACTIVE; } rm_mac_ctxt: if (generation == sc->sc_generation) { iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_REMOVE, 0); sc->sc_flags &= ~IWM_FLAG_MAC_ACTIVE; } return err; } int ItlIwm:: iwm_deauth(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; int ac, tfd_queue_msk, err, i; splassert(IPL_NET); iwm_unprotect_session(sc, in); if (sc->sc_flags & IWM_FLAG_STA_ACTIVE) { err = iwm_rm_sta_cmd(sc, in); if (err) { XYLog("%s: could not remove STA (error %d)\n", DEVNAME(sc), err); return err; } sc->sc_rx_ba_sessions = 0; for (i = 0; i < nitems(sc->sc_tx_ba); i++) sc->sc_tx_ba[i].wn = NULL; sc->ba_rx.start_tidmask = 0; sc->ba_rx.stop_tidmask = 0; sc->ba_tx.start_tidmask = 0; sc->ba_tx.stop_tidmask = 0; } tfd_queue_msk = 0; for (ac = 0; ac < EDCA_NUM_AC; ac++) { int qid = ac; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) qid += IWM_DQA_MIN_MGMT_QUEUE; tfd_queue_msk |= htole32(1 << qid); } err = iwm_flush_tx_path(sc, tfd_queue_msk); if (err) { XYLog("%s: could not flush Tx path (error %d)\n", DEVNAME(sc), err); return err; } if (sc->sc_flags & IWM_FLAG_BINDING_ACTIVE) { err = iwm_binding_cmd(sc, in, IWM_FW_CTXT_ACTION_REMOVE); if (err) { XYLog("%s: could not remove binding (error %d)\n", DEVNAME(sc), err); return err; } sc->sc_flags &= ~IWM_FLAG_BINDING_ACTIVE; } if (sc->sc_flags & IWM_FLAG_MAC_ACTIVE) { err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_REMOVE, 0); if (err) { XYLog("%s: could not remove MAC context (error %d)\n", DEVNAME(sc), err); return err; } sc->sc_flags &= ~IWM_FLAG_MAC_ACTIVE; } in->in_ni.ni_chw = IEEE80211_CHAN_WIDTH_20_NOHT; in->in_ni.ni_flags &= ~(IEEE80211_NODE_HT | IEEE80211_NODE_QOS | IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40 | IEEE80211_NODE_VHT | IEEE80211_NODE_VHT_SGI80 | IEEE80211_NODE_VHT_SGI160); /* Move unused PHY context to a default channel. */ err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0], &ic->ic_channels[1], 1, 1, 0); if (err) return err; rs_drv_free_sta(sc, &in->in_ni); return 0; } int ItlIwm:: iwm_run(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; int err; int chains = iwm_mimo_enabled(sc) ? 2 : 1; splassert(IPL_NET); if (ic->ic_opmode == IEEE80211_M_MONITOR) { /* Add a MAC context and a sniffing STA. */ err = iwm_auth(sc); if (err) return err; } if (in->in_ni.ni_chw == IEEE80211_CHAN_WIDTH_80P80) { /* Fallback to 20mhz VHT */ in->in_ni.ni_chw = IEEE80211_CHAN_WIDTH_20; } if (in->in_ni.ni_flags & IEEE80211_NODE_VHT) { if (in->in_ni.ni_chw == IEEE80211_CHAN_WIDTH_20) { ic->ic_vht_sup_mcs[0] = 0x01FF; /* MCS 0-8 */ if (iwm_mimo_enabled(sc)) ic->ic_vht_sup_mcs[1] = 0x01FF; /* MCS 0-8 */ } else { ic->ic_vht_sup_mcs[0] = 0x03FF; /* MCS 0-9 */ if (iwm_mimo_enabled(sc)) ic->ic_vht_sup_mcs[1] = 0x03FF; /* MCS 0-9 */ } } /* Configure Rx chains for MIMO. */ if ((ic->ic_opmode == IEEE80211_M_MONITOR || (in->in_ni.ni_flags & IEEE80211_NODE_HT) || (in->in_ni.ni_flags & IEEE80211_NODE_VHT))) { err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0], in->in_ni.ni_chan, chains, chains, 0); if (err) { XYLog("%s: failed to update PHY\n", DEVNAME(sc)); return err; } } /* Update STA again, for HT-related settings such as MIMO. */ err = iwm_add_sta_cmd(sc, in, 1, 0); if (err) { XYLog("%s: could not update STA (error %d)\n", DEVNAME(sc), err); return err; } /* We have now been assigned an associd by the AP. */ err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 1); if (err) { XYLog("%s: failed to update MAC\n", DEVNAME(sc)); return err; } err = iwm_sf_config(sc, IWM_SF_FULL_ON); if (err) { XYLog("%s: could not set sf full on (error %d)\n", DEVNAME(sc), err); return err; } err = iwm_allow_mcast(sc); if (err) { XYLog("%s: could not allow mcast (error %d)\n", DEVNAME(sc), err); return err; } err = iwm_power_update_device(sc); if (err) { XYLog("%s: could not send power command (error %d)\n", DEVNAME(sc), err); return err; } #ifdef notyet /* * Disabled for now. Default beacon filter settings * prevent net80211 from getting ERP and HT protection * updates from beacons. */ err = iwm_enable_beacon_filter(sc, in); if (err) { XYLog("%s: could not enable beacon filter\n", DEVNAME(sc)); return err; } #endif err = iwm_power_mac_update_mode(sc, in); if (err) { XYLog("%s: could not update MAC power (error %d)\n", DEVNAME(sc), err); return err; } if (!isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) { err = iwm_update_quotas(sc, in, 1); if (err) { XYLog("%s: could not update quotas (error %d)\n", DEVNAME(sc), err); return err; } } ieee80211_amrr_node_init(&sc->sc_amrr, &in->in_amn); if (ic->ic_opmode == IEEE80211_M_MONITOR) { iwm_led_blink_start(sc); return 0; } /* Start at lowest available bit-rate, AMRR will raise. */ in->in_ni.ni_txrate = 0; in->in_ni.ni_txmcs = 0; iwl_mvm_rs_rate_init(sc, ic->ic_bss, IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ, true); timeout_add_msec(&sc->sc_calib_to, 500); iwm_led_enable(sc); iwm_toggle_tx_ant(sc, &sc->sc_mgmt_last_antenna_idx); return 0; } int ItlIwm:: iwm_run_stop(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; int err, i, tid; splassert(IPL_NET); /* * Stop Tx/Rx BA sessions now. We cannot rely on the BA task * for this when moving out of RUN state since it runs in a * separate thread. * Note that in->in_ni (struct ieee80211_node) already represents * our new access point in case we are roaming between APs. * This means we cannot rely on struct ieee802111_node to tell * us which BA sessions exist. */ for (i = 0; i < nitems(sc->sc_rxba_data); i++) { struct iwm_rxba_data *rxba = &sc->sc_rxba_data[i]; if (rxba->baid == IWM_RX_REORDER_DATA_INVALID_BAID) continue; iwm_sta_rx_agg(sc, &in->in_ni, rxba->tid, 0, 0, 0, 0); iwm_clear_reorder_buffer(sc, rxba); if (sc->sc_rx_ba_sessions > 0) sc->sc_rx_ba_sessions--; } for (tid = 0; tid < IWM_MAX_TID_COUNT; tid++) { int qid = IWM_FIRST_AGG_TX_QUEUE + tid; struct iwm_tx_ring *ring = &sc->txq[qid]; if ((sc->agg_queue_mask & (1 << qid)) == 0) continue; err = iwm_sta_tx_agg(sc, &in->in_ni, tid, 0, 0, 0); if (err) return err; iwm_ampdu_txq_advance(sc, ring, ring->cur); iwm_clear_oactive(sc, ring); } ieee80211_ba_del(&in->in_ni); sc->ba_tx.start_tidmask = 0; sc->ba_tx.stop_tidmask = 0; if (ic->ic_opmode == IEEE80211_M_MONITOR) iwm_led_blink_stop(sc); err = iwm_sf_config(sc, IWM_SF_INIT_OFF); if (err) return err; iwm_disable_beacon_filter(sc); if (!isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) { err = iwm_update_quotas(sc, in, 0); if (err) { XYLog("%s: could not update quotas (error %d)\n", DEVNAME(sc), err); return err; } } /* Mark station as disassociated. */ err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 0); if (err) { XYLog("%s: failed to update MAC\n", DEVNAME(sc)); return err; } /* Reset Tx chains in case MIMO was enabled. */ if ((in->in_ni.ni_flags & IEEE80211_NODE_HT) && iwm_mimo_enabled(sc)) { err = iwm_phy_ctxt_update(sc, &sc->sc_phyctxt[0], in->in_ni.ni_chan, 1, 1, 0); if (err) { XYLog("%s: failed to update PHY\n", DEVNAME(sc)); return err; } } return 0; } struct ieee80211_node *ItlIwm:: iwm_node_alloc(struct ieee80211com *ic) { return (struct ieee80211_node *)malloc(sizeof (struct iwm_node), M_DEVBUF, M_NOWAIT | M_ZERO); } int ItlIwm:: iwm_set_key_v1(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; struct iwm_add_sta_key_cmd_v1 cmd; memset(&cmd, 0, sizeof(cmd)); cmd.common.key_flags = htole16(IWM_STA_KEY_FLG_CCM | IWM_STA_KEY_FLG_WEP_KEY_MAP | ((k->k_id << IWM_STA_KEY_FLG_KEYID_POS) & IWM_STA_KEY_FLG_KEYID_MSK)); if (k->k_flags & IEEE80211_KEY_GROUP) cmd.common.key_flags |= htole16(IWM_STA_KEY_MULTICAST); memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len)); cmd.common.key_offset = 0; cmd.common.sta_id = IWM_STATION_ID; return iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC, sizeof(cmd), &cmd); } int ItlIwm:: iwm_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; struct iwm_add_sta_key_cmd cmd; ItlIwm *that = container_of(sc, ItlIwm, com); if ((k->k_flags & IEEE80211_KEY_GROUP) || k->k_cipher != IEEE80211_CIPHER_CCMP) { /* Fallback to software crypto for other ciphers. */ return (ieee80211_set_key(ic, ni, k)); } if (!isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_TKIP_MIC_KEYS)) return that->iwm_set_key_v1(ic, ni, k); memset(&cmd, 0, sizeof(cmd)); cmd.common.key_flags = htole16(IWM_STA_KEY_FLG_CCM | IWM_STA_KEY_FLG_WEP_KEY_MAP | ((k->k_id << IWM_STA_KEY_FLG_KEYID_POS) & IWM_STA_KEY_FLG_KEYID_MSK)); if (k->k_flags & IEEE80211_KEY_GROUP) cmd.common.key_flags |= htole16(IWM_STA_KEY_MULTICAST); memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len)); cmd.common.key_offset = 0; cmd.common.sta_id = IWM_STATION_ID; cmd.transmit_seq_cnt = htole64(k->k_tsc); return that->iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC, sizeof(cmd), &cmd); } void ItlIwm:: iwm_delete_key_v1(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; struct iwm_add_sta_key_cmd_v1 cmd; memset(&cmd, 0, sizeof(cmd)); cmd.common.key_flags = htole16(IWM_STA_KEY_NOT_VALID | IWM_STA_KEY_FLG_NO_ENC | IWM_STA_KEY_FLG_WEP_KEY_MAP | ((k->k_id << IWM_STA_KEY_FLG_KEYID_POS) & IWM_STA_KEY_FLG_KEYID_MSK)); memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len)); cmd.common.key_offset = 0; cmd.common.sta_id = IWM_STATION_ID; iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC, sizeof(cmd), &cmd); } void ItlIwm:: iwm_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; struct iwm_add_sta_key_cmd cmd; ItlIwm *that = container_of(sc, ItlIwm, com); if ((k->k_flags & IEEE80211_KEY_GROUP) || (k->k_cipher != IEEE80211_CIPHER_CCMP)) { /* Fallback to software crypto for other ciphers. */ ieee80211_delete_key(ic, ni, k); return; } if ((sc->sc_flags & IWM_FLAG_STA_ACTIVE) == 0) return; if (!isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_TKIP_MIC_KEYS)) return that->iwm_delete_key_v1(ic, ni, k); memset(&cmd, 0, sizeof(cmd)); cmd.common.key_flags = htole16(IWM_STA_KEY_NOT_VALID | IWM_STA_KEY_FLG_NO_ENC | IWM_STA_KEY_FLG_WEP_KEY_MAP | ((k->k_id << IWM_STA_KEY_FLG_KEYID_POS) & IWM_STA_KEY_FLG_KEYID_MSK)); memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len)); cmd.common.key_offset = 0; cmd.common.sta_id = IWM_STATION_ID; that->iwm_send_cmd_pdu(sc, IWM_ADD_STA_KEY, IWM_CMD_ASYNC, sizeof(cmd), &cmd); } void ItlIwm:: iwm_calib_timeout(void *arg) { struct iwm_softc *sc = (struct iwm_softc *)arg; ItlIwm *that = container_of(sc, ItlIwm, com); struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; struct ieee80211_node *ni = &in->in_ni; int s; s = splnet(); if ((ic->ic_fixed_rate == -1 || ic->ic_fixed_mcs == -1) && (ni->ni_flags & IEEE80211_NODE_HT) == 0 && ic->ic_opmode == IEEE80211_M_STA && ic->ic_bss) { int old_txrate = ni->ni_txrate; ieee80211_amrr_choose(&sc->sc_amrr, &in->in_ni, &in->in_amn); /* * If AMRR has chosen a new TX rate we must update * the firwmare's LQ rate table. * ni_txrate may change again before the task runs so * cache the chosen rate in the iwm_node structure. */ if (ni->ni_txrate != old_txrate) { XYLog("iwm_calib_timeout in->ni_txrate=%d\n", in->in_ni.ni_txrate); iwl_mvm_send_lq_cmd(sc, &sc->lq_sta.rs_drv.lq); } } splx(s); timeout_add_msec(&sc->sc_calib_to, 500); } /* Allow multicast from our BSSID. */ int ItlIwm:: iwm_allow_mcast(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; struct iwm_mcast_filter_cmd *cmd; size_t size; int err; size = roundup(sizeof(*cmd), 4); cmd = (struct iwm_mcast_filter_cmd*)malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); if (cmd == NULL) return ENOMEM; cmd->filter_own = 1; cmd->port_id = 0; cmd->count = 0; cmd->pass_all = 1; IEEE80211_ADDR_COPY(cmd->bssid, in->in_macaddr); err = iwm_send_cmd_pdu(sc, IWM_MCAST_FILTER_CMD, 0, size, cmd); ::free(cmd); return err; } /* * This function is called by upper layer when an ADDBA request is received * from another STA and before the ADDBA response is sent. */ int ItlIwm:: iwm_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct iwm_softc *sc = (struct iwm_softc *)IC2IFP(ic)->if_softc; ItlIwm *that = container_of(sc, ItlIwm, com); if (sc->sc_rx_ba_sessions >= IWM_MAX_RX_BA_SESSIONS || tid > IWM_MAX_TID_COUNT) return ENOSPC; if (ic->ic_state != IEEE80211_S_RUN) return ENOSPC; if (sc->ba_rx.start_tidmask & (1 << tid)) return EBUSY; sc->ba_rx.start_tidmask |= (1 << tid); that->iwm_add_task(sc, systq, &sc->ba_task); return EBUSY; } /* * This function is called by upper layer on teardown of an HT-immediate * Block Ack agreement (eg. upon receipt of a DELBA frame). */ void ItlIwm:: iwm_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct iwm_softc *sc = (struct iwm_softc *)IC2IFP(ic)->if_softc; ItlIwm *that = container_of(sc, ItlIwm, com); if (tid > IWM_MAX_TID_COUNT || sc->ba_rx.stop_tidmask & (1 << tid)) return; if (ic->ic_state != IEEE80211_S_RUN) return; sc->ba_rx.stop_tidmask |= (1 << tid); that->iwm_add_task(sc, systq, &sc->ba_task); } int ItlIwm:: iwm_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; ItlIwm *that = container_of(sc, ItlIwm, com); /* We only implement Tx aggregation with DQA-capable firmware. */ if (!isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) return ENOTSUP; /* Ensure we can map this TID to an aggregation queue. */ if (tid >= IWM_MAX_TID_COUNT) return EINVAL; /* We only support a fixed Tx aggregation window size, for now. */ if (ba->ba_winsize != IWM_FRAME_LIMIT) return ENOTSUP; /* Is firmware already using Tx aggregation on this queue? */ if (sc->sc_tx_ba[tid].wn != NULL) return ENOSPC; /* Are we already processing an ADDBA request? */ if (sc->ba_tx.start_tidmask & (1 << tid)) return EBUSY; sc->ba_tx.start_tidmask |= (1 << tid); that->iwm_add_task(sc, systq, &sc->ba_task); return EBUSY; } void ItlIwm:: iwm_ampdu_tx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; ItlIwm *that = container_of(sc, ItlIwm, com); XYLog("%s\n", __FUNCTION__); if (tid > IWM_MAX_TID_COUNT || sc->ba_tx.stop_tidmask & (1 << tid)) return; /* Is firmware currently using Tx aggregation on this queue? */ if (sc->sc_tx_ba[tid].wn == NULL) return; sc->ba_tx.stop_tidmask |= (1 << tid); that->iwm_add_task(sc, systq, &sc->ba_task); } void ItlIwm:: iwm_update_chw(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; ItlIwm *that = container_of(sc, ItlIwm, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWM_FLAG_STA_ACTIVE)) that->iwm_add_task(sc, systq, &sc->chan_ctxt_task); } /* * This function is called by upper layer when HT protection settings in * beacons have changed. */ void ItlIwm:: iwm_updateprot(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; ItlIwm *that = container_of(sc, ItlIwm, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWM_FLAG_STA_ACTIVE)) that->iwm_add_task(sc, systq, &sc->mac_ctxt_task); } void ItlIwm:: iwm_updateslot(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; ItlIwm *that = container_of(sc, ItlIwm, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWM_FLAG_STA_ACTIVE)) that->iwm_add_task(sc, systq, &sc->mac_ctxt_task); } void ItlIwm:: iwm_updateedca(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; ItlIwm *that = container_of(sc, ItlIwm, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWM_FLAG_STA_ACTIVE)) that->iwm_add_task(sc, systq, &sc->mac_ctxt_task); } void ItlIwm:: iwm_updatedtim(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc *)ic->ic_softc; ItlIwm *that = container_of(sc, ItlIwm, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWM_FLAG_STA_ACTIVE)) that->iwm_add_task(sc, systq, &sc->mac_ctxt_task); } int ItlIwm::iwm_media_change(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc*)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; uint8_t rate, ridx; int err; err = ieee80211_media_change(ifp); if (err != ENETRESET) return err; if (ic->ic_fixed_mcs != -1) { if (ni->ni_flags & IEEE80211_NODE_VHT) sc->sc_fixed_ridx = iwm_mcs2ridx[ic->ic_fixed_mcs]; else if (ni->ni_flags & IEEE80211_NODE_HT) sc->sc_fixed_ridx = iwm_mcs2ridx[ic->ic_fixed_mcs % 8]; } else if (ic->ic_fixed_rate != -1) { rate = ic->ic_sup_rates[ic->ic_curmode]. rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; /* Map 802.11 rate to HW rate index. */ for (ridx = 0; ridx <= ieee80211_std_rateset_11g.rs_nrates; ridx++) if (ieee80211_std_rateset_11g.rs_rates[ridx] == rate) break; sc->sc_fixed_ridx = ridx; } if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) { iwm_stop(ifp); err = iwm_init(ifp); } return err; } void ItlIwm:: iwm_newstate_task(void *psc) { struct iwm_softc *sc = (struct iwm_softc *)psc; ItlIwm *that = container_of(sc, ItlIwm, com); struct ieee80211com *ic = &sc->sc_ic; enum ieee80211_state nstate = sc->ns_nstate; enum ieee80211_state ostate = ic->ic_state; int arg = sc->ns_arg; int err = 0, s = splnet(); if (sc->sc_flags & IWM_FLAG_SHUTDOWN) { /* iwm_stop() is waiting for us. */ // refcnt_rele_wake(&sc->task_refs); splx(s); return; } if (ostate == IEEE80211_S_SCAN) { if (nstate == ostate) { if (sc->sc_flags & IWM_FLAG_SCANNING) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } /* Firmware is no longer scanning. Do another scan. */ goto next_scan; } else that->iwm_led_blink_stop(sc); } if (nstate <= ostate) { switch (ostate) { case IEEE80211_S_RUN: err = that->iwm_run_stop(sc); if (err) goto out; /* FALLTHROUGH */ case IEEE80211_S_ASSOC: case IEEE80211_S_AUTH: if (nstate <= IEEE80211_S_AUTH) { err = that->iwm_deauth(sc); if (err) goto out; } /* FALLTHROUGH */ case IEEE80211_S_SCAN: case IEEE80211_S_INIT: break; } /* Die now if iwm_stop() was called while we were sleeping. */ if (sc->sc_flags & IWM_FLAG_SHUTDOWN) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } } switch (nstate) { case IEEE80211_S_INIT: break; case IEEE80211_S_SCAN: next_scan: err = that->iwm_scan(sc); if (err) break; // refcnt_rele_wake(&sc->task_refs); splx(s); return; case IEEE80211_S_AUTH: err = that->iwm_auth(sc); break; case IEEE80211_S_ASSOC: break; case IEEE80211_S_RUN: err = that->iwm_run(sc); break; } out: if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) == 0) { if (err) task_add(systq, &sc->init_task); else sc->sc_newstate(ic, nstate, arg); } // refcnt_rele_wake(&sc->task_refs); splx(s); } int ItlIwm:: iwm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { XYLog("%s\n", __FUNCTION__); struct _ifnet *ifp = IC2IFP(ic); struct iwm_softc *sc = (struct iwm_softc*)ifp->if_softc; ItlIwm *that = container_of(sc, ItlIwm, com); struct ieee80211_node *ni = ic->ic_bss; /* * Prevent attemps to transition towards the same state, unless * we are scanning in which case a SCAN -> SCAN transition * triggers another scan iteration. And AUTH -> AUTH is needed * to support band-steering. */ if (sc->ns_nstate == nstate && nstate != IEEE80211_S_SCAN && nstate != IEEE80211_S_AUTH) if (ic->ic_state == IEEE80211_S_RUN) { if (nstate == IEEE80211_S_SCAN) { /* * During RUN->SCAN we don't call sc_newstate() so * we must stop A-MPDU Tx ourselves in this case. */ ieee80211_stop_ampdu_tx(ic, ni, -1); ieee80211_ba_del(ni); } timeout_del(&sc->sc_calib_to); that->iwm_del_task(sc, systq, &sc->ba_task); that->iwm_del_task(sc, systq, &sc->mac_ctxt_task); that->iwm_del_task(sc, systq, &sc->chan_ctxt_task); } sc->ns_nstate = nstate; sc->ns_arg = arg; that->iwm_add_task(sc, sc->sc_nswq, &sc->newstate_task); return 0; } void ItlIwm:: iwm_endscan(struct iwm_softc *sc) { struct ieee80211_node *ni, *nextbs; struct ieee80211com *ic = &sc->sc_ic; // ni = RB_MIN(ieee80211_tree, &ic->ic_tree); // for (; ni != NULL; ni = nextbs) { // nextbs = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); // XYLog("%s scan_result ssid=%s, bssid=%s, ni_rsnciphers=%d, ni_rsncipher=%d, ni_rsngroupmgmtcipher=%d, ni_rsngroupcipher=%d, ni_rssi=%d, ni_capinfo=%d, ni_intval=%d, ni_rsnakms=%d, ni_supported_rsnakms=%d, ni_rsnprotos=%d, ni_supported_rsnprotos=%d, ni_rstamp=%d\n", __FUNCTION__, ni->ni_essid, ether_sprintf(ni->ni_bssid), ni->ni_rsnciphers, ni->ni_rsncipher, ni->ni_rsngroupmgmtcipher, ni->ni_rsngroupcipher, ni->ni_rssi, ni->ni_capinfo, ni->ni_intval, ni->ni_rsnakms, ni->ni_supported_rsnakms, ni->ni_rsnprotos, ni->ni_supported_rsnprotos, ni->ni_rstamp); // } if ((sc->sc_flags & (IWM_FLAG_SCANNING | IWM_FLAG_BGSCAN)) == 0) return; sc->sc_flags &= ~(IWM_FLAG_SCANNING | IWM_FLAG_BGSCAN); ieee80211_end_scan(&ic->ic_if); } /* * Aging and idle timeouts for the different possible scenarios * in default configuration */ static const uint32_t iwm_sf_full_timeout_def[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = { { htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER_DEF), htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER_DEF) }, { htole32(IWM_SF_AGG_UNICAST_AGING_TIMER_DEF), htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER_DEF) }, { htole32(IWM_SF_MCAST_AGING_TIMER_DEF), htole32(IWM_SF_MCAST_IDLE_TIMER_DEF) }, { htole32(IWM_SF_BA_AGING_TIMER_DEF), htole32(IWM_SF_BA_IDLE_TIMER_DEF) }, { htole32(IWM_SF_TX_RE_AGING_TIMER_DEF), htole32(IWM_SF_TX_RE_IDLE_TIMER_DEF) }, }; /* * Aging and idle timeouts for the different possible scenarios * in single BSS MAC configuration. */ static const uint32_t iwm_sf_full_timeout[IWM_SF_NUM_SCENARIO][IWM_SF_NUM_TIMEOUT_TYPES] = { { htole32(IWM_SF_SINGLE_UNICAST_AGING_TIMER), htole32(IWM_SF_SINGLE_UNICAST_IDLE_TIMER) }, { htole32(IWM_SF_AGG_UNICAST_AGING_TIMER), htole32(IWM_SF_AGG_UNICAST_IDLE_TIMER) }, { htole32(IWM_SF_MCAST_AGING_TIMER), htole32(IWM_SF_MCAST_IDLE_TIMER) }, { htole32(IWM_SF_BA_AGING_TIMER), htole32(IWM_SF_BA_IDLE_TIMER) }, { htole32(IWM_SF_TX_RE_AGING_TIMER), htole32(IWM_SF_TX_RE_IDLE_TIMER) }, }; void ItlIwm:: iwm_fill_sf_command(struct iwm_softc *sc, struct iwm_sf_cfg_cmd *sf_cmd, struct ieee80211_node *ni) { int i, j, watermark; sf_cmd->watermark[IWM_SF_LONG_DELAY_ON] = htole32(IWM_SF_W_MARK_SCAN); /* * If we are in association flow - check antenna configuration * capabilities of the AP station, and choose the watermark accordingly. */ if (ni) { if (ni->ni_flags & IEEE80211_NODE_HT) { if (ni->ni_rxmcs[1] != 0) watermark = IWM_SF_W_MARK_MIMO2; else watermark = IWM_SF_W_MARK_SISO; } else { watermark = IWM_SF_W_MARK_LEGACY; } /* default watermark value for unassociated mode. */ } else { watermark = IWM_SF_W_MARK_MIMO2; } sf_cmd->watermark[IWM_SF_FULL_ON] = htole32(watermark); for (i = 0; i < IWM_SF_NUM_SCENARIO; i++) { for (j = 0; j < IWM_SF_NUM_TIMEOUT_TYPES; j++) { sf_cmd->long_delay_timeouts[i][j] = htole32(IWM_SF_LONG_DELAY_AGING_TIMER); } } if (ni) { memcpy(sf_cmd->full_on_timeouts, iwm_sf_full_timeout, sizeof(iwm_sf_full_timeout)); } else { memcpy(sf_cmd->full_on_timeouts, iwm_sf_full_timeout_def, sizeof(iwm_sf_full_timeout_def)); } } int ItlIwm:: iwm_sf_config(struct iwm_softc *sc, int new_state) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwm_sf_cfg_cmd sf_cmd = { .state = htole32(new_state), }; int err = 0; #if 0 /* only used for models with sdio interface, in iwlwifi */ if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000) sf_cmd.state |= htole32(IWM_SF_CFG_DUMMY_NOTIF_OFF); #endif switch (new_state) { case IWM_SF_UNINIT: case IWM_SF_INIT_OFF: iwm_fill_sf_command(sc, &sf_cmd, NULL); break; case IWM_SF_FULL_ON: iwm_fill_sf_command(sc, &sf_cmd, ic->ic_bss); break; default: return EINVAL; } err = iwm_send_cmd_pdu(sc, IWM_REPLY_SF_CFG_CMD, IWM_CMD_ASYNC, sizeof(sf_cmd), &sf_cmd); return err; } int ItlIwm:: iwm_init_hw(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; int err, i, ac, qid; err = iwm_preinit(sc); if (err) return err; err = iwm_start_hw(sc); if (err) { XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); return err; } err = iwm_run_init_mvm_ucode(sc, 0); if (err) return err; /* Should stop and start HW since INIT image just loaded. */ iwm_stop_device(sc); err = iwm_start_hw(sc); if (err) { XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); return err; } /* Restart, this time with the regular firmware */ err = iwm_load_ucode_wait_alive(sc, IWM_UCODE_TYPE_REGULAR); if (err) { XYLog("%s: could not load firmware\n", DEVNAME(sc)); goto err; } if (!iwm_nic_lock(sc)) return EBUSY; err = iwm_send_tx_ant_cfg(sc, iwm_fw_valid_tx_ant(sc)); if (err) { XYLog("%s: could not init tx ant config (error %d)\n", DEVNAME(sc), err); goto err; } err = iwm_send_phy_db_data(sc); if (err) { XYLog("%s: could not init phy db (error %d)\n", DEVNAME(sc), err); goto err; } err = iwm_send_phy_cfg_cmd(sc); if (err) { XYLog("%s: could not send phy config (error %d)\n", DEVNAME(sc), err); goto err; } err = iwm_send_bt_init_conf(sc); if (err) { XYLog("%s: could not init bt coex (error %d)\n", DEVNAME(sc), err); return err; } if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT)) { err = iwm_send_soc_conf(sc); if (err) return err; } if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) { err = iwm_send_dqa_cmd(sc); if (err) return err; } /* Add auxiliary station for scanning */ err = iwm_add_aux_sta(sc); if (err) { XYLog("%s: could not add aux station (error %d)\n", DEVNAME(sc), err); goto err; } for (i = 0; i < IWM_NUM_PHY_CTX; i++) { /* * The channel used here isn't relevant as it's * going to be overwritten in the other flows. * For now use the first channel we have. */ sc->sc_phyctxt[i].id = i; sc->sc_phyctxt[i].channel = &ic->ic_channels[1]; err = iwm_phy_ctxt_cmd(sc, &sc->sc_phyctxt[i], 1, 1, IWM_FW_CTXT_ACTION_ADD, 0); if (err) { XYLog("%s: could not add phy context %d (error %d)\n", DEVNAME(sc), i, err); goto err; } } /* Initialize tx backoffs to the minimum. */ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) iwm_tt_tx_backoff(sc, 0); err = iwm_config_ltr(sc); if (err) { XYLog("%s: PCIe LTR configuration failed (error %d)\n", DEVNAME(sc), err); } if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_CT_KILL_BY_FW)) { err = iwm_send_temp_report_ths_cmd(sc); if (err) goto err; } err = iwm_power_update_device(sc); if (err) { XYLog("%s: could not send power command (error %d)\n", DEVNAME(sc), err); goto err; } if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_SUPPORT)) { err = iwm_send_update_mcc_cmd(sc, "ZZ"); if (err) { XYLog("%s: could not init LAR (error %d)\n", DEVNAME(sc), err); goto err; } } if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) { err = iwm_config_umac_scan(sc); if (err) { XYLog("%s: could not configure scan (error %d)\n", DEVNAME(sc), err); goto err; } } if (ic->ic_opmode == IEEE80211_M_MONITOR) { if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) qid = IWM_DQA_INJECT_MONITOR_QUEUE; else qid = IWM_AUX_QUEUE; err = iwm_enable_txq(sc, IWM_MONITOR_STA_ID, qid, iwm_ac_to_tx_fifo[EDCA_AC_BE], 0, IWM_MAX_TID_COUNT, 0); if (err) { XYLog("%s: could not enable monitor inject Tx queue " "(error %d)\n", DEVNAME(sc), err); goto err; } } else { for (ac = 0; ac < EDCA_NUM_AC; ac++) { if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) qid = ac + IWM_DQA_MIN_MGMT_QUEUE; else qid = ac; err = iwm_enable_txq(sc, IWM_STATION_ID, qid, iwm_ac_to_tx_fifo[ac], 0, IWM_TID_NON_QOS, 0); if (err) { XYLog("%s: could not enable Tx queue %d " "(error %d)\n", DEVNAME(sc), ac, err); goto err; } } } err = iwm_disable_beacon_filter(sc); if (err) { XYLog("%s: could not disable beacon filter (error %d)\n", DEVNAME(sc), err); goto err; } err: iwm_nic_unlock(sc); return err; } int ItlIwm:: iwm_init(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc*)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; ItlIwm *that = container_of(sc, ItlIwm, com); int err, generation; // rw_assert_wrlock(&sc->ioctl_rwl); sc->agg_tid_disable = 0xffff; sc->agg_queue_mask = 0; memset(sc->sc_tx_ba, 0, sizeof(sc->sc_tx_ba)); generation = ++sc->sc_generation; KASSERT(sc->task_refs.refs == 0, "sc->task_refs.refs == 0"); // refcnt_init(&sc->task_refs); err = iwm_init_hw(sc); if (err) { if (generation == sc->sc_generation) iwm_stop_device(sc); return err; } if (sc->sc_nvm.sku_cap_11n_enable) iwm_setup_ht_rates(sc); if (sc->sc_nvm.sku_cap_11ac_enable) iwm_setup_vht_rates(sc); ifq_clr_oactive(&ifp->if_snd); ifq_flush(&ifp->if_snd); ifp->if_flags |= IFF_RUNNING; if (ic->ic_opmode == IEEE80211_M_MONITOR) { ic->ic_bss->ni_chan = ic->ic_ibss_chan; ieee80211_new_state(ic, IEEE80211_S_RUN, -1); return 0; } ieee80211_begin_scan(ifp); /* * ieee80211_begin_scan() ends up scheduling iwm_newstate_task(). * Wait until the transition to SCAN state has completed. */ do { err = tsleep_nsec(&ic->ic_state, PCATCH, "iwminit", SEC_TO_NSEC(1)); if (generation != sc->sc_generation) return ENXIO; if (err) { iwm_stop(ifp); return err; } } while (ic->ic_state != IEEE80211_S_SCAN); return 0; } IOReturn ItlIwm:: _iwm_start_task(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) { struct _ifnet *ifp = (struct _ifnet *)arg0; struct iwm_softc *sc = (struct iwm_softc*)ifp->if_softc; ItlIwm *that = container_of(sc, ItlIwm, com); struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; struct ether_header *eh; mbuf_t m; int ac = EDCA_AC_BE; /* XXX */ if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) { return kIOReturnOutputDropped; } for (;;) { /* why isn't this done per-queue? */ if (sc->qfullmsk != 0) { ifq_set_oactive(&ifp->if_snd); break; } /* need to send management frames even if we're not RUNning */ m = mq_dequeue(&ic->ic_mgtq); if (m) { ni = (struct ieee80211_node *)mbuf_pkthdr_rcvif(m); goto sendit; } if ( #ifndef AIRPORT ic->ic_state != IEEE80211_S_RUN || #endif (ic->ic_xflags & IEEE80211_F_TX_MGMT_ONLY)) break; m = ifq_dequeue(&ifp->if_snd); if (!m) { break; } if (mbuf_len(m) < sizeof (*eh) && mbuf_pullup(&m, sizeof (*eh)) != 0) { XYLog("%s %d OUTPUT_ERROR\n", __FUNCTION__, __LINE__); ifp->netStat->outputErrors++; continue; } #if NBPFILTER > 0 if (ifp->if_bpf != NULL) bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) { XYLog("%s %d ieee80211_encap OUTPUT_ERROR\n", __FUNCTION__, __LINE__); ifp->netStat->outputErrors++; continue; } // XYLog("%s if_snd->send\n", __FUNCTION__); sendit: #if NBPFILTER > 0 if (ic->ic_rawbpf != NULL) bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT); #endif if (that->iwm_tx(sc, m, ni, ac) != 0) { XYLog("%s %d iwm_tx OUTPUT_ERROR\n", __FUNCTION__, __LINE__); ieee80211_release_node(ic, ni); ifp->netStat->outputErrors++; continue; } ifp->netStat->outputPackets++; if (ifp->if_flags & IFF_UP) ifp->if_timer = 1; } return kIOReturnSuccess; } void ItlIwm:: iwm_start(struct _ifnet *ifp) { struct iwm_softc *sc = (struct iwm_softc*)ifp->if_softc; ItlIwm *that = container_of(sc, ItlIwm, com); // if (that->outputThreadSignal) { // semaphore_signal(that->outputThreadSignal); // } that->getMainCommandGate()->attemptAction(_iwm_start_task, &that->com.sc_ic.ic_ac.ac_if); // _iwm_start_task(that, &that->com.sc_ic.ic_ac.ac_if, NULL, NULL, NULL); } void ItlIwm:: iwm_stop(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc*)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; int i, s = splnet(); // rw_assert_wrlock(&sc->ioctl_rwl); sc->sc_flags |= IWM_FLAG_SHUTDOWN; /* Disallow new tasks. */ /* Cancel scheduled tasks and let any stale tasks finish up. */ task_del(systq, &sc->init_task); iwm_del_task(sc, sc->sc_nswq, &sc->newstate_task); iwm_del_task(sc, systq, &sc->ba_task); iwm_del_task(sc, systq, &sc->mac_ctxt_task); iwm_del_task(sc, systq, &sc->chan_ctxt_task); // KASSERT(sc->task_refs.refs >= 1, "sc->task_refs.refs >= 1"); // refcnt_finalize(&sc->task_refs, "iwmstop"); iwm_stop_device(sc); /* Reset soft state. */ sc->sc_generation++; for (i = 0; i < nitems(sc->sc_cmd_resp_pkt); i++) { ::free(sc->sc_cmd_resp_pkt[i]); sc->sc_cmd_resp_pkt[i] = NULL; sc->sc_cmd_resp_len[i] = 0; } ifp->if_flags &= ~IFF_RUNNING; ifq_flush(&ifp->if_snd); ifq_clr_oactive(&ifp->if_snd); in->in_phyctxt = NULL; in->in_ni.ni_chw = IEEE80211_CHAN_WIDTH_20_NOHT; IEEE80211_ADDR_COPY(in->in_macaddr, etheranyaddr); sc->sc_flags &= ~(IWM_FLAG_SCANNING | IWM_FLAG_BGSCAN); sc->sc_flags &= ~IWM_FLAG_MAC_ACTIVE; sc->sc_flags &= ~IWM_FLAG_BINDING_ACTIVE; sc->sc_flags &= ~IWM_FLAG_STA_ACTIVE; sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE; sc->sc_flags &= ~IWM_FLAG_HW_ERR; sc->sc_flags &= ~IWM_FLAG_SHUTDOWN; sc->sc_rx_ba_sessions = 0; sc->ba_rx.start_tidmask = 0; sc->ba_rx.stop_tidmask = 0; for (i = 0; i < nitems(sc->sc_tx_ba); i++) sc->sc_tx_ba[i].wn = NULL; sc->ba_tx.start_tidmask = 0; sc->ba_tx.stop_tidmask = 0; sc->sc_newstate(ic, IEEE80211_S_INIT, -1); sc->ns_nstate = IEEE80211_S_INIT; timeout_del(&sc->sc_calib_to); /* XXX refcount? */ for (i = 0; i < nitems(sc->sc_rxba_data); i++) { struct iwm_rxba_data *rxba = &sc->sc_rxba_data[i]; iwm_clear_reorder_buffer(sc, rxba); } iwm_led_blink_stop(sc); memset(sc->sc_tx_timer, 0, sizeof(sc->sc_tx_timer)); ifp->if_timer = 0; splx(s); } void ItlIwm:: iwm_watchdog(struct _ifnet *ifp) { struct iwm_softc *sc = (struct iwm_softc *)ifp->if_softc; ItlIwm *that = container_of(sc, ItlIwm, com); int i; ifp->if_timer = 0; /* * We maintain a separate timer for each Tx queue because * Tx aggregation queues can get "stuck" while other queues * keep working. The Linux driver uses a similar workaround. */ for (i = 0; i < nitems(sc->sc_tx_timer); i++) { if (sc->sc_tx_timer[i] > 0) { if (--sc->sc_tx_timer[i] == 0) { XYLog("%s: device timeout\n", DEVNAME(sc)); #ifdef IWM_DEBUG that->iwm_nic_error(sc); #endif if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) == 0) { task_add(systq, &sc->init_task); } XYLog("%s %d OUTPUT_ERROR\n", __FUNCTION__, __LINE__); ifp->netStat->outputErrors++; return; } ifp->if_timer = 1; } } ieee80211_watchdog(ifp); } int ItlIwm:: iwm_ioctl(struct _ifnet *ifp, u_long cmd, caddr_t data) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc *)ifp->if_softc; ItlIwm *that = container_of(sc, ItlIwm, com); int s, err = 0, generation = sc->sc_generation; /* * Prevent processes from entering this function while another * process is tsleep'ing in it. */ // err = rw_enter(&sc->ioctl_rwl, RW_WRITE | RW_INTR); if (err == 0 && generation != sc->sc_generation) { // rw_exit(&sc->ioctl_rwl); return ENXIO; } if (err) return err; s = splnet(); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; /* FALLTHROUGH */ case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (!(ifp->if_flags & IFF_RUNNING)) { err = that->iwm_init(ifp); } } else { if (ifp->if_flags & IFF_RUNNING) that->iwm_stop(ifp); } break; default: err = ieee80211_ioctl(ifp, cmd, data); } if (err == ENETRESET) { err = 0; if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) { that->iwm_stop(ifp); err = that->iwm_init(ifp); } } splx(s); // rw_exit(&sc->ioctl_rwl); return err; } #ifdef IWM_DEBUG /* * Note: This structure is read from the device with IO accesses, * and the reading already does the endian conversion. As it is * read with uint32_t-sized accesses, any members with a different size * need to be ordered correctly though! */ struct iwm_error_event_table { uint32_t valid; /* (nonzero) valid, (0) log is empty */ uint32_t error_id; /* type of error */ uint32_t trm_hw_status0; /* TRM HW status */ uint32_t trm_hw_status1; /* TRM HW status */ uint32_t blink2; /* branch link */ uint32_t ilink1; /* interrupt link */ uint32_t ilink2; /* interrupt link */ uint32_t data1; /* error-specific data */ uint32_t data2; /* error-specific data */ uint32_t data3; /* error-specific data */ uint32_t bcon_time; /* beacon timer */ uint32_t tsf_low; /* network timestamp function timer */ uint32_t tsf_hi; /* network timestamp function timer */ uint32_t gp1; /* GP1 timer register */ uint32_t gp2; /* GP2 timer register */ uint32_t fw_rev_type; /* firmware revision type */ uint32_t major; /* uCode version major */ uint32_t minor; /* uCode version minor */ uint32_t hw_ver; /* HW Silicon version */ uint32_t brd_ver; /* HW board version */ uint32_t log_pc; /* log program counter */ uint32_t frame_ptr; /* frame pointer */ uint32_t stack_ptr; /* stack pointer */ uint32_t hcmd; /* last host command header */ uint32_t isr0; /* isr status register LMPM_NIC_ISR0: * rxtx_flag */ uint32_t isr1; /* isr status register LMPM_NIC_ISR1: * host_flag */ uint32_t isr2; /* isr status register LMPM_NIC_ISR2: * enc_flag */ uint32_t isr3; /* isr status register LMPM_NIC_ISR3: * time_flag */ uint32_t isr4; /* isr status register LMPM_NIC_ISR4: * wico interrupt */ uint32_t last_cmd_id; /* last HCMD id handled by the firmware */ uint32_t wait_event; /* wait event() caller address */ uint32_t l2p_control; /* L2pControlField */ uint32_t l2p_duration; /* L2pDurationField */ uint32_t l2p_mhvalid; /* L2pMhValidBits */ uint32_t l2p_addr_match; /* L2pAddrMatchStat */ uint32_t lmpm_pmg_sel; /* indicate which clocks are turned on * (LMPM_PMG_SEL) */ uint32_t u_timestamp; /* indicate when the date and time of the * compilation */ uint32_t flow_handler; /* FH read/write pointers, RX credit */ } __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; /* * UMAC error struct - relevant starting from family 8000 chip. * Note: This structure is read from the device with IO accesses, * and the reading already does the endian conversion. As it is * read with u32-sized accesses, any members with a different size * need to be ordered correctly though! */ struct iwm_umac_error_event_table { uint32_t valid; /* (nonzero) valid, (0) log is empty */ uint32_t error_id; /* type of error */ uint32_t blink1; /* branch link */ uint32_t blink2; /* branch link */ uint32_t ilink1; /* interrupt link */ uint32_t ilink2; /* interrupt link */ uint32_t data1; /* error-specific data */ uint32_t data2; /* error-specific data */ uint32_t data3; /* error-specific data */ uint32_t umac_major; uint32_t umac_minor; uint32_t frame_pointer; /* core register 27*/ uint32_t stack_pointer; /* core register 28 */ uint32_t cmd_header; /* latest host cmd sent to UMAC */ uint32_t nic_isr_pref; /* ISR status register */ } __packed; #define ERROR_START_OFFSET (1 * sizeof(uint32_t)) #define ERROR_ELEM_SIZE (7 * sizeof(uint32_t)) void ItlIwm:: iwm_nic_umac_error(struct iwm_softc *sc) { struct iwm_umac_error_event_table table; uint32_t base; base = sc->sc_uc.uc_umac_error_event_table; if (base < 0x800000) { XYLog("%s: Invalid error log pointer 0x%08x\n", DEVNAME(sc), base); return; } if (iwm_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t))) { XYLog("%s: reading errlog failed\n", DEVNAME(sc)); return; } if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { XYLog("%s: Start UMAC Error Log Dump:\n", DEVNAME(sc)); XYLog("%s: Status: 0x%x, count: %d\n", DEVNAME(sc), sc->sc_flags, table.valid); } XYLog("%s: 0x%08X | %s\n", DEVNAME(sc), table.error_id, iwm_desc_lookup(table.error_id)); XYLog("%s: 0x%08X | umac branchlink1\n", DEVNAME(sc), table.blink1); XYLog("%s: 0x%08X | umac branchlink2\n", DEVNAME(sc), table.blink2); XYLog("%s: 0x%08X | umac interruptlink1\n", DEVNAME(sc), table.ilink1); XYLog("%s: 0x%08X | umac interruptlink2\n", DEVNAME(sc), table.ilink2); XYLog("%s: 0x%08X | umac data1\n", DEVNAME(sc), table.data1); XYLog("%s: 0x%08X | umac data2\n", DEVNAME(sc), table.data2); XYLog("%s: 0x%08X | umac data3\n", DEVNAME(sc), table.data3); XYLog("%s: 0x%08X | umac major\n", DEVNAME(sc), table.umac_major); XYLog("%s: 0x%08X | umac minor\n", DEVNAME(sc), table.umac_minor); XYLog("%s: 0x%08X | frame pointer\n", DEVNAME(sc), table.frame_pointer); XYLog("%s: 0x%08X | stack pointer\n", DEVNAME(sc), table.stack_pointer); XYLog("%s: 0x%08X | last host cmd\n", DEVNAME(sc), table.cmd_header); XYLog("%s: 0x%08X | isr status reg\n", DEVNAME(sc), table.nic_isr_pref); } #define IWM_FW_SYSASSERT_CPU_MASK 0xf0000000 static struct { const char *name; uint8_t num; } advanced_lookup[] = { { "NMI_INTERRUPT_WDG", 0x34 }, { "SYSASSERT", 0x35 }, { "UCODE_VERSION_MISMATCH", 0x37 }, { "BAD_COMMAND", 0x38 }, { "BAD_COMMAND", 0x39 }, { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, { "FATAL_ERROR", 0x3D }, { "NMI_TRM_HW_ERR", 0x46 }, { "NMI_INTERRUPT_TRM", 0x4C }, { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, { "NMI_INTERRUPT_HOST", 0x66 }, { "NMI_INTERRUPT_LMAC_FATAL", 0x70 }, { "NMI_INTERRUPT_UMAC_FATAL", 0x71 }, { "NMI_INTERRUPT_OTHER_LMAC_FATAL", 0x73 }, { "NMI_INTERRUPT_ACTION_PT", 0x7C }, { "NMI_INTERRUPT_UNKNOWN", 0x84 }, { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, { "ADVANCED_SYSASSERT", 0 }, }; const char *ItlIwm:: iwm_desc_lookup(uint32_t num) { int i; for (i = 0; i < nitems(advanced_lookup) - 1; i++) if (advanced_lookup[i].num == (num & ~IWM_FW_SYSASSERT_CPU_MASK)) return advanced_lookup[i].name; /* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */ return advanced_lookup[i].name; } /* * Support for dumping the error log seemed like a good idea ... * but it's mostly hex junk and the only sensible thing is the * hw/ucode revision (which we know anyway). Since it's here, * I'll just leave it in, just in case e.g. the Intel guys want to * help us decipher some "ADVANCED_SYSASSERT" later. */ void ItlIwm:: iwm_nic_error(struct iwm_softc *sc) { struct iwm_error_event_table table; uint32_t base; XYLog("%s: dumping device error log\n", DEVNAME(sc)); base = sc->sc_uc.uc_error_event_table; if (base < 0x800000) { XYLog("%s: Invalid error log pointer 0x%08x\n", DEVNAME(sc), base); return; } if (iwm_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t))) { XYLog("%s: reading errlog failed\n", DEVNAME(sc)); return; } if (!table.valid) { XYLog("%s: errlog not found, skipping\n", DEVNAME(sc)); return; } if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { XYLog("%s: Start Error Log Dump:\n", DEVNAME(sc)); XYLog("%s: Status: 0x%x, count: %d\n", DEVNAME(sc), sc->sc_flags, table.valid); } XYLog("%s: 0x%08X | %-28s\n", DEVNAME(sc), table.error_id, iwm_desc_lookup(table.error_id)); XYLog("%s: %08X | trm_hw_status0\n", DEVNAME(sc), table.trm_hw_status0); XYLog("%s: %08X | trm_hw_status1\n", DEVNAME(sc), table.trm_hw_status1); XYLog("%s: %08X | branchlink2\n", DEVNAME(sc), table.blink2); XYLog("%s: %08X | interruptlink1\n", DEVNAME(sc), table.ilink1); XYLog("%s: %08X | interruptlink2\n", DEVNAME(sc), table.ilink2); XYLog("%s: %08X | data1\n", DEVNAME(sc), table.data1); XYLog("%s: %08X | data2\n", DEVNAME(sc), table.data2); XYLog("%s: %08X | data3\n", DEVNAME(sc), table.data3); XYLog("%s: %08X | beacon time\n", DEVNAME(sc), table.bcon_time); XYLog("%s: %08X | tsf low\n", DEVNAME(sc), table.tsf_low); XYLog("%s: %08X | tsf hi\n", DEVNAME(sc), table.tsf_hi); XYLog("%s: %08X | time gp1\n", DEVNAME(sc), table.gp1); XYLog("%s: %08X | time gp2\n", DEVNAME(sc), table.gp2); XYLog("%s: %08X | uCode revision type\n", DEVNAME(sc), table.fw_rev_type); XYLog("%s: %08X | uCode version major\n", DEVNAME(sc), table.major); XYLog("%s: %08X | uCode version minor\n", DEVNAME(sc), table.minor); XYLog("%s: %08X | hw version\n", DEVNAME(sc), table.hw_ver); XYLog("%s: %08X | board version\n", DEVNAME(sc), table.brd_ver); XYLog("%s: %08X | hcmd\n", DEVNAME(sc), table.hcmd); XYLog("%s: %08X | isr0\n", DEVNAME(sc), table.isr0); XYLog("%s: %08X | isr1\n", DEVNAME(sc), table.isr1); XYLog("%s: %08X | isr2\n", DEVNAME(sc), table.isr2); XYLog("%s: %08X | isr3\n", DEVNAME(sc), table.isr3); XYLog("%s: %08X | isr4\n", DEVNAME(sc), table.isr4); XYLog("%s: %08X | last cmd Id\n", DEVNAME(sc), table.last_cmd_id); XYLog("%s: %08X | wait_event\n", DEVNAME(sc), table.wait_event); XYLog("%s: %08X | l2p_control\n", DEVNAME(sc), table.l2p_control); XYLog("%s: %08X | l2p_duration\n", DEVNAME(sc), table.l2p_duration); XYLog("%s: %08X | l2p_mhvalid\n", DEVNAME(sc), table.l2p_mhvalid); XYLog("%s: %08X | l2p_addr_match\n", DEVNAME(sc), table.l2p_addr_match); XYLog("%s: %08X | lmpm_pmg_sel\n", DEVNAME(sc), table.lmpm_pmg_sel); XYLog("%s: %08X | timestamp\n", DEVNAME(sc), table.u_timestamp); XYLog("%s: %08X | flow_handler\n", DEVNAME(sc), table.flow_handler); if (sc->sc_uc.uc_umac_error_event_table) iwm_nic_umac_error(sc); } #endif #define ADVANCE_RXQ(sc) (sc->rxq.cur = (sc->rxq.cur + 1) % count); void ItlIwm:: iwm_notif_intr(struct iwm_softc *sc) { struct mbuf_list ml = MBUF_LIST_INITIALIZER(); uint32_t wreg; uint16_t hw; int count; // bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map, // 0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD); if (sc->sc_mqrx_supported) { count = IWM_RX_MQ_RING_COUNT; wreg = IWM_RFH_Q0_FRBDCB_WIDX_TRG; } else { count = IWM_RX_RING_COUNT; wreg = IWM_FH_RSCSR_CHNL0_WPTR; } hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff; hw &= (count - 1); while (sc->rxq.cur != hw) { struct iwm_rx_data *data = &sc->rxq.data[sc->rxq.cur]; iwm_rx_pkt(sc, data, &ml); ADVANCE_RXQ(sc); } if_input(&sc->sc_ic.ic_if, &ml); /* * Tell the firmware what we have processed. * Seems like the hardware gets upset unless we align the write by 8?? */ hw = (hw == 0) ? count - 1 : hw - 1; IWM_WRITE(sc, wreg, hw & ~7); } int ItlIwm:: iwm_intr(OSObject *arg, IOInterruptEventSource* sender, int count) { ItlIwm *that = (ItlIwm*)arg; struct iwm_softc *sc = &that->com; int handled = 0; int rv = 0; uint32_t r1, r2; if (sc->sc_flags & IWM_FLAG_USE_ICT) { uint32_t *ict = (uint32_t *)sc->ict_dma.vaddr; int tmp; tmp = htole32(ict[sc->ict_cur]); if (!tmp) goto out_ena; /* * ok, there was something. keep plowing until we have all. */ r1 = r2 = 0; while (tmp) { r1 |= tmp; ict[sc->ict_cur] = 0; sc->ict_cur = (sc->ict_cur+1) % IWM_ICT_COUNT; tmp = htole32(ict[sc->ict_cur]); } /* this is where the fun begins. don't ask */ if (r1 == 0xffffffff) r1 = 0; /* * Workaround for hardware bug where bits are falsely cleared * when using interrupt coalescing. Bit 15 should be set if * bits 18 and 19 are set. */ if (r1 & 0xc0000) r1 |= 0x8000; r1 = (0xff & r1) | ((0xff00 & r1) << 16); } else { r1 = IWM_READ(sc, IWM_CSR_INT); r2 = IWM_READ(sc, IWM_CSR_FH_INT_STATUS); } if (r1 == 0 && r2 == 0) { goto out_ena; } if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) goto out; IWM_WRITE(sc, IWM_CSR_INT, r1 | ~sc->sc_intmask); /* ignored */ handled |= (r1 & (IWM_CSR_INT_BIT_ALIVE /*| IWM_CSR_INT_BIT_SCD*/)); if (r1 & IWM_CSR_INT_BIT_RF_KILL) { handled |= IWM_CSR_INT_BIT_RF_KILL; XYLog("%s RF_KILL has been toggled\n", __FUNCTION__); that->iwm_check_rfkill(sc); task_add(systq, &sc->init_task); rv = 1; goto out_ena; } if (r1 & IWM_CSR_INT_BIT_SW_ERR) { #ifdef IWM_DEBUG int i; that->iwm_nic_error(sc); /* Dump driver status (TX and RX rings) while we're here. */ XYLog("driver status:\n"); for (i = 0; i < IWM_MAX_QUEUES; i++) { struct iwm_tx_ring *ring = &sc->txq[i]; XYLog(" tx ring %2d: qid=%-2d cur=%-3d " "queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); } XYLog(" rx ring: cur=%d\n", sc->rxq.cur); XYLog(" 802.11 state %s\n", ieee80211_state_name[sc->sc_ic.ic_state]); #endif XYLog("%s: fatal firmware error\n", DEVNAME(sc)); if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) == 0) task_add(systq, &sc->init_task); rv = 1; goto out; } if (r1 & IWM_CSR_INT_BIT_HW_ERR) { handled |= IWM_CSR_INT_BIT_HW_ERR; XYLog("%s: hardware error, stopping device \n", DEVNAME(sc)); if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) == 0) { sc->sc_flags |= IWM_FLAG_HW_ERR; task_add(systq, &sc->init_task); } rv = 1; goto out; } /* firmware chunk loaded */ if (r1 & IWM_CSR_INT_BIT_FH_TX) { IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_TX_MASK); handled |= IWM_CSR_INT_BIT_FH_TX; sc->sc_fw_chunk_done = 1; that->wakeupOn(&sc->sc_fw); } if (r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX | IWM_CSR_INT_BIT_RX_PERIODIC)) { if (r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) { handled |= (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX); IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_RX_MASK); } if (r1 & IWM_CSR_INT_BIT_RX_PERIODIC) { handled |= IWM_CSR_INT_BIT_RX_PERIODIC; IWM_WRITE(sc, IWM_CSR_INT, IWM_CSR_INT_BIT_RX_PERIODIC); } /* Disable periodic interrupt; we use it as just a one-shot. */ IWM_WRITE_1(sc, IWM_CSR_INT_PERIODIC_REG, IWM_CSR_INT_PERIODIC_DIS); /* * Enable periodic interrupt in 8 msec only if we received * real RX interrupt (instead of just periodic int), to catch * any dangling Rx interrupt. If it was just the periodic * interrupt, there was no dangling Rx activity, and no need * to extend the periodic interrupt; one-shot is enough. */ if (r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) IWM_WRITE_1(sc, IWM_CSR_INT_PERIODIC_REG, IWM_CSR_INT_PERIODIC_ENA); that->iwm_notif_intr(sc); } rv = 1; out_ena: that->iwm_restore_interrupts(sc); out: return rv; } int ItlIwm:: iwm_intr_msix(OSObject *object, IOInterruptEventSource* sender, int count) { ItlIwm *that = (ItlIwm*)object; struct iwm_softc *sc = &that->com; uint32_t inta_fh, inta_hw; int vector = 0; inta_fh = IWM_READ(sc, IWM_CSR_MSIX_FH_INT_CAUSES_AD); inta_hw = IWM_READ(sc, IWM_CSR_MSIX_HW_INT_CAUSES_AD); IWM_WRITE(sc, IWM_CSR_MSIX_FH_INT_CAUSES_AD, inta_fh); IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_CAUSES_AD, inta_hw); inta_fh &= sc->sc_fh_mask; inta_hw &= sc->sc_hw_mask; if (inta_fh & IWM_MSIX_FH_INT_CAUSES_Q0 || inta_fh & IWM_MSIX_FH_INT_CAUSES_Q1) { that->iwm_notif_intr(sc); } /* firmware chunk loaded */ if (inta_fh & IWM_MSIX_FH_INT_CAUSES_D2S_CH0_NUM) { sc->sc_fw_chunk_done = 1; that->wakeupOn(&sc->sc_fw); } if ((inta_fh & IWM_MSIX_FH_INT_CAUSES_FH_ERR) || (inta_hw & IWM_MSIX_HW_INT_CAUSES_REG_SW_ERR) || (inta_hw & IWM_MSIX_HW_INT_CAUSES_REG_SW_ERR_V2)) { #ifdef IWM_DEBUG int i; that->iwm_nic_error(sc); /* Dump driver status (TX and RX rings) while we're here. */ XYLog("driver status:\n"); for (i = 0; i < IWM_MAX_QUEUES; i++) { struct iwm_tx_ring *ring = &sc->txq[i]; XYLog(" tx ring %2d: qid=%-2d cur=%-3d " "queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); } XYLog(" rx ring: cur=%d\n", sc->rxq.cur); XYLog(" 802.11 state %s\n", ieee80211_state_name[sc->sc_ic.ic_state]); #endif XYLog("%s: fatal firmware error\n", DEVNAME(sc)); if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) == 0) task_add(systq, &sc->init_task); return 1; } if (inta_hw & IWM_MSIX_HW_INT_CAUSES_REG_RF_KILL) { that->iwm_check_rfkill(sc); task_add(systq, &sc->init_task); } if (inta_hw & IWM_MSIX_HW_INT_CAUSES_REG_HW_ERR) { XYLog("%s: hardware error, stopping device \n", DEVNAME(sc)); if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) == 0) { sc->sc_flags |= IWM_FLAG_HW_ERR; task_add(systq, &sc->init_task); } return 1; } /* * Before sending the interrupt the HW disables it to prevent * a nested interrupt. This is done by writing 1 to the corresponding * bit in the mask register. After handling the interrupt, it should be * re-enabled by clearing this bit. This register is defined as * write 1 clear (W1C) register, meaning that it's being clear * by writing 1 to the bit. */ IWM_WRITE(sc, IWM_CSR_MSIX_AUTOMASK_ST_AD, 1 << vector); return 1; } typedef void *iwm_match_t; #define PCI_VENDOR_INTEL 0x8086 #define PCI_PRODUCT_INTEL_WL_7260_1 0x08b1 /* Dual Band Wireless AC 7260 */ #define PCI_PRODUCT_INTEL_WL_7260_2 0x08b2 /* Dual Band Wireless AC 7260 */ #define PCI_PRODUCT_INTEL_WL_3160_1 0x08b3 /* Dual Band Wireless AC 3160 */ #define PCI_PRODUCT_INTEL_WL_3160_2 0x08b4 /* Dual Band Wireless AC 3160 */ #define PCI_PRODUCT_INTEL_WL_7265_1 0x095a /* Dual Band Wireless AC 7265 */ #define PCI_PRODUCT_INTEL_WL_7265_2 0x095b /* Dual Band Wireless AC 7265 */ #define PCI_PRODUCT_INTEL_WL_3165_1 0x3165 /* Dual Band Wireless AC 3165 */ #define PCI_PRODUCT_INTEL_WL_3165_2 0x3166 /* Dual Band Wireless AC 3165 */ #define PCI_PRODUCT_INTEL_WL_8260_1 0x24f3 /* Dual Band Wireless AC 8260 */ #define PCI_PRODUCT_INTEL_WL_8260_2 0x24f4 /* Dual Band Wireless AC 8260 */ #define PCI_PRODUCT_INTEL_WL_4165_1 0x24f5 /* Dual Band Wireless AC 4165 */ #define PCI_PRODUCT_INTEL_WL_4165_2 0x24f6 /* Dual Band Wireless AC 4165 */ #define PCI_PRODUCT_INTEL_WL_3168_1 0x24fb /* Dual Band Wireless-AC 3168 */ #define PCI_PRODUCT_INTEL_WL_8265_1 0x24fd /* Dual Band Wireless-AC 8265 */ #define PCI_PRODUCT_INTEL_WL_9260_1 0x2526 #define PCI_PRODUCT_INTEL_WL_9560_1 0x9df0 /* Dual Band Wireless AC 9560 */ #define PCI_PRODUCT_INTEL_WL_9560_2 0xa370 /* Dual Band Wireless AC 9560 */ #define PCI_PRODUCT_INTEL_WL_9560_3 0x31DC /* Dual Band Wireless AC 9560 */ #define PCI_PRODUCT_INTEL_WL_9560_4 0x30DC /* Dual Band Wireless AC 9560 */ #define PCI_PRODUCT_INTEL_WL_9560_5 0x271C /* Dual Band Wireless AC 9560 */ #define PCI_PRODUCT_INTEL_WL_9560_6 0x271B /* Dual Band Wireless AC 9560 */ #define PCI_PRODUCT_INTEL_WL_9462_1 0x42a4 /* Dual Band Wireless AC 9462 */ #define PCI_PRODUCT_INTEL_WL_9462_2 0x00a0 /* Dual Band Wireless AC 9462 */ #define PCI_PRODUCT_INTEL_WL_9462_3 0x00a4 /* Dual Band Wireless AC 9462 */ #define PCI_PRODUCT_INTEL_WL_9462_4 0x02a0 /* Dual Band Wireless AC 9462 */ //#define PCI_PRODUCT_INTEL_WL_9462_5 0x02a4 /* Dual Band Wireless AC 9462 */ #define PCI_PRODUCT_INTEL_WL_9462_6 0x40a4 /* Dual Band Wireless AC 9462 */ #define PCI_PRODUCT_INTEL_WL_9461_1 0x0060 /* Dual Band Wireless AC 9461 */ #define PCI_PRODUCT_INTEL_WL_9461_2 0x0064 /* Dual Band Wireless AC 9461 */ #define PCI_PRODUCT_INTEL_WL_9461_3 0x0260 /* Dual Band Wireless AC 9461 */ #define PCI_PRODUCT_INTEL_WL_9461_4 0x0264 /* Dual Band Wireless AC 9461 */ static const struct pci_matchid iwm_devices[] = { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_3160_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_3160_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_3165_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_3165_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_3168_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_7260_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_7260_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_7265_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_7265_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_8260_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_8260_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_8265_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9260_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9560_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9560_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9560_3 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9560_4 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9560_5 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9560_6 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9462_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9462_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9462_3 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9462_4 }, //{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9462_5 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9462_6 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9461_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9461_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9461_3 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_9461_4 } }; int ItlIwm:: iwm_match(struct IOPCIDevice *device) { int devId = device->configRead16(kIOPCIConfigDeviceID); XYLog("%s devId=0x%04X\n", __FUNCTION__, devId); return pci_matchbyid(PCI_VENDOR_INTEL, devId, iwm_devices, nitems(iwm_devices)); } int ItlIwm:: iwm_preinit(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); int err; static int attached; err = iwm_prepare_card_hw(sc); if (err) { XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); return err; } if (attached) { /* Update MAC in case the upper layers changed it. */ IEEE80211_ADDR_COPY(sc->sc_ic.ic_myaddr, ((struct arpcom *)ifp)->ac_enaddr); return 0; } err = iwm_start_hw(sc); if (err) { XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); return err; } err = iwm_run_init_mvm_ucode(sc, 1); iwm_stop_device(sc); if (err) return err; /* Print version info and MAC address on first successful fw load. */ attached = 1; XYLog("%s: hw rev 0x%x, fw ver %s, address %s\n", DEVNAME(sc), sc->sc_hw_rev & IWM_CSR_HW_REV_TYPE_MSK, sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr)); if (sc->sc_nvm.sku_cap_11n_enable) iwm_setup_ht_rates(sc); if (sc->sc_nvm.sku_cap_11ac_enable) { iwm_setup_vht_rates(sc); } /* not all hardware can do 5GHz band */ if (!sc->sc_nvm.sku_cap_band_52GHz_enable) memset(&ic->ic_sup_rates[IEEE80211_MODE_11A], 0, sizeof(ic->ic_sup_rates[IEEE80211_MODE_11A])); /* Configure channel information obtained from firmware. */ ieee80211_channel_init(ifp); /* Configure MAC address. */ err = if_setlladdr(ifp, ic->ic_myaddr); if (err) XYLog("%s: could not set MAC address (error %d)\n", DEVNAME(sc), err); ieee80211_media_init(ifp); iwm_rs_free(sc); iwm_rs_alloc(sc); return 0; } void ItlIwm:: iwm_attach_hook(struct device *self) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc *)self; KASSERT(!cold, "!cold"); iwm_preinit(sc); } bool ItlIwm:: intrFilter(OSObject *object, IOFilterInterruptEventSource *src) { ItlIwm *that = (ItlIwm*)object; IWM_WRITE(&that->com, IWM_CSR_INT_MASK, 0); return true; } bool ItlIwm:: iwm_attach(struct iwm_softc *sc, struct pci_attach_args *pa) { XYLog("%s\n", __FUNCTION__); pcireg_t reg, memtype; struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; int err; int txq_i, i, j; sc->sc_pct = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; sc->sc_dmat = pa->pa_dmat; // rw_init(&sc->ioctl_rwl, "iwmioctl"); err = pci_get_capability(sc->sc_pct, sc->sc_pcitag, PCI_CAP_PCIEXPRESS, &sc->sc_cap_off, NULL); if (err == 0) { XYLog("%s: PCIe capability structure not found!\n", DEVNAME(sc)); return false; } /* Clear device-specific "PCI retry timeout" register (41h). */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40); pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00); /* Enable bus-mastering and hardware bug workaround. */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); reg |= PCI_COMMAND_MASTER_ENABLE; /* if !MSI */ if (reg & PCI_COMMAND_INTERRUPT_DISABLE) { reg &= ~PCI_COMMAND_INTERRUPT_DISABLE; } pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START); err = pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0, &sc->sc_st, &sc->sc_sh, NULL, &sc->sc_sz, 0); if (err) { XYLog("%s: can't map mem space\n", DEVNAME(sc)); return false; } if (0) { // if (pci_intr_map_msix(pa, 0, &sc->ih) == 0) { sc->sc_msix = 1; } else if (pci_intr_map_msi(pa, &sc->ih)) { XYLog("%s: can't map interrupt\n", DEVNAME(sc)); return false; } if (!sc->sc_msix) { /* Hardware bug workaround. */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); if (reg & PCI_COMMAND_INTERRUPT_DISABLE) reg &= ~PCI_COMMAND_INTERRUPT_DISABLE; pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); } int msiIntrIndex = -1; for (int index = 0; ; index++) { int interruptType; int ret = pa->pa_tag->getInterruptType(index, &interruptType); if (ret != kIOReturnSuccess) break; if (interruptType & kIOInterruptTypePCIMessaged) { msiIntrIndex = index; break; } } if (msiIntrIndex == -1) { XYLog("%s: can't find MSI interrupt controller\n", DEVNAME(sc)); return false; } if (sc->sc_msix) sc->sc_ih = IOFilterInterruptEventSource::filterInterruptEventSource(this, (IOInterruptEventSource::Action)&ItlIwm::iwm_intr_msix, &ItlIwm::intrFilter ,pa->pa_tag, msiIntrIndex); else sc->sc_ih = IOFilterInterruptEventSource::filterInterruptEventSource(this, (IOInterruptEventSource::Action)&ItlIwm::iwm_intr, &ItlIwm::intrFilter , pa->pa_tag, msiIntrIndex); if (sc->sc_ih == NULL || pa->workloop->addEventSource(sc->sc_ih) != kIOReturnSuccess) { XYLog("%s: can't establish interrupt\n", DEVNAME(sc)); return false; } sc->sc_ih->enable(); sc->sc_hw_rev = IWM_READ(sc, IWM_CSR_HW_REV); int pa_id = pa->pa_tag->configRead16(kIOPCIConfigDeviceID); switch (pa_id) { case PCI_PRODUCT_INTEL_WL_3160_1: case PCI_PRODUCT_INTEL_WL_3160_2: sc->sc_fwname = "iwm-3160-17"; sc->host_interrupt_operation_mode = 1; sc->sc_device_family = IWM_DEVICE_FAMILY_7000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; sc->sc_nvm_max_section_size = 16384; sc->nvm_type = IWM_NVM; sc->support_ldpc = 0; sc->non_shared_ant = IWM_ANT_A; break; case PCI_PRODUCT_INTEL_WL_3165_1: case PCI_PRODUCT_INTEL_WL_3165_2: sc->sc_fwname = "iwm-7265-17"; sc->host_interrupt_operation_mode = 0; sc->sc_device_family = IWM_DEVICE_FAMILY_7000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; sc->sc_nvm_max_section_size = 16384; sc->nvm_type = IWM_NVM; sc->support_ldpc = 0; sc->non_shared_ant = IWM_ANT_A; break; case PCI_PRODUCT_INTEL_WL_3168_1: sc->sc_fwname = "iwm-3168-29"; sc->host_interrupt_operation_mode = 0; sc->sc_device_family = IWM_DEVICE_FAMILY_7000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; sc->sc_nvm_max_section_size = 16384; sc->nvm_type = IWM_NVM_SDP; sc->support_ldpc = 0; sc->non_shared_ant = IWM_ANT_A; break; case PCI_PRODUCT_INTEL_WL_7260_1: case PCI_PRODUCT_INTEL_WL_7260_2: sc->sc_fwname = "iwm-7260-17"; sc->host_interrupt_operation_mode = 1; sc->sc_device_family = IWM_DEVICE_FAMILY_7000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; sc->sc_nvm_max_section_size = 16384; sc->nvm_type = IWM_NVM; sc->support_ldpc = 0; sc->non_shared_ant = IWM_ANT_A; break; case PCI_PRODUCT_INTEL_WL_7265_1: case PCI_PRODUCT_INTEL_WL_7265_2: sc->sc_fwname = "iwm-7265-17"; sc->host_interrupt_operation_mode = 0; sc->sc_device_family = IWM_DEVICE_FAMILY_7000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ; sc->sc_nvm_max_section_size = 16384; sc->nvm_type = IWM_NVM; sc->support_ldpc = 1; sc->non_shared_ant = IWM_ANT_A; break; case PCI_PRODUCT_INTEL_WL_8260_1: case PCI_PRODUCT_INTEL_WL_8260_2: sc->sc_fwname = "iwm-8000C-36"; sc->host_interrupt_operation_mode = 0; sc->sc_device_family = IWM_DEVICE_FAMILY_8000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ_8000; sc->sc_nvm_max_section_size = 32768; sc->nvm_type = IWM_NVM_EXT; sc->support_ldpc = 1; sc->non_shared_ant = IWM_ANT_A; break; case PCI_PRODUCT_INTEL_WL_8265_1: sc->sc_fwname = "iwm-8265-36"; sc->host_interrupt_operation_mode = 0; sc->sc_device_family = IWM_DEVICE_FAMILY_8000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ_8000; sc->sc_nvm_max_section_size = 32768; sc->nvm_type = IWM_NVM_EXT; sc->support_ldpc = 1; sc->non_shared_ant = IWM_ANT_A; break; case PCI_PRODUCT_INTEL_WL_9260_1: sc->sc_fwname = "iwm-9260-46"; sc->host_interrupt_operation_mode = 0; sc->sc_device_family = IWM_DEVICE_FAMILY_9000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ_8000; sc->sc_nvm_max_section_size = 32768; sc->sc_mqrx_supported = 1; sc->support_ldpc = 1; sc->non_shared_ant = IWM_ANT_B; break; case PCI_PRODUCT_INTEL_WL_9560_1: case PCI_PRODUCT_INTEL_WL_9560_2: case PCI_PRODUCT_INTEL_WL_9560_3: case PCI_PRODUCT_INTEL_WL_9560_4: case PCI_PRODUCT_INTEL_WL_9560_5: case PCI_PRODUCT_INTEL_WL_9560_6: case PCI_PRODUCT_INTEL_WL_9462_1: case PCI_PRODUCT_INTEL_WL_9462_2: case PCI_PRODUCT_INTEL_WL_9462_3: case PCI_PRODUCT_INTEL_WL_9462_4: //case PCI_PRODUCT_INTEL_WL_9462_5: case PCI_PRODUCT_INTEL_WL_9462_6: case PCI_PRODUCT_INTEL_WL_9461_1: case PCI_PRODUCT_INTEL_WL_9461_2: case PCI_PRODUCT_INTEL_WL_9461_3: case PCI_PRODUCT_INTEL_WL_9461_4: sc->sc_fwname = "iwm-9000-46"; sc->host_interrupt_operation_mode = 0; sc->sc_device_family = IWM_DEVICE_FAMILY_9000; sc->sc_fwdmasegsz = IWM_FWDMASEGSZ_8000; sc->sc_nvm_max_section_size = 32768; sc->sc_mqrx_supported = 1; sc->sc_integrated = 1; sc->support_ldpc = 1; sc->sc_xtal_latency = 650; sc->non_shared_ant = IWM_ANT_B; break; default: XYLog("%s: unknown adapter type\n", DEVNAME(sc)); return false; } /* * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have * changed, and now the revision step also includes bit 0-1 (no more * "dash" value). To keep hw_rev backwards compatible - we'll store it * in the old format. */ if (sc->sc_device_family >= IWM_DEVICE_FAMILY_8000) { uint32_t hw_step; sc->sc_hw_rev = (sc->sc_hw_rev & 0xfff0) | (IWM_CSR_HW_REV_STEP(sc->sc_hw_rev << 2) << 2); if (iwm_prepare_card_hw(sc) != 0) { XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); return false; } /* * In order to recognize C step the driver should read the * chip version id located at the AUX bus MISC address. */ IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE); DELAY(2); err = iwm_poll_bit(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (!err) { XYLog("%s: Failed to wake up the nic\n", DEVNAME(sc)); return false; } if (iwm_nic_lock(sc)) { hw_step = iwm_read_prph(sc, IWM_WFPM_CTRL_REG); hw_step |= IWM_ENABLE_WFPM; iwm_write_prph(sc, IWM_WFPM_CTRL_REG, hw_step); hw_step = iwm_read_prph(sc, IWM_AUX_MISC_REG); hw_step = (hw_step >> IWM_HW_STEP_LOCATION_BITS) & 0xF; if (hw_step == 0x3) sc->sc_hw_rev = (sc->sc_hw_rev & 0xFFFFFFF3) | (IWM_SILICON_C_STEP << 2); iwm_nic_unlock(sc); } else { XYLog("%s: Failed to lock the nic\n", DEVNAME(sc)); return false; } } XYLog("alloc contig\n"); /* * Allocate DMA memory for firmware transfers. * Must be aligned on a 16-byte boundary. */ err = iwm_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma, sc->sc_fwdmasegsz, 16); if (err) { XYLog("%s: could not allocate memory for firmware\n", DEVNAME(sc)); return false; } /* Allocate "Keep Warm" page, used internally by the card. */ err = iwm_dma_contig_alloc(sc->sc_dmat, &sc->kw_dma, 4096, 4096); if (err) { XYLog("%s: could not allocate keep warm page\n", DEVNAME(sc)); goto fail1; } /* Allocate interrupt cause table (ICT).*/ err = iwm_dma_contig_alloc(sc->sc_dmat, &sc->ict_dma, IWM_ICT_SIZE, 1<sc_dmat, &sc->sched_dma, nitems(sc->txq) * sizeof(struct iwm_agn_scd_bc_tbl), 1024); if (err) { XYLog("%s: could not allocate TX scheduler rings\n", DEVNAME(sc)); goto fail3; } for (txq_i = 0; txq_i < nitems(sc->txq); txq_i++) { err = iwm_alloc_tx_ring(sc, &sc->txq[txq_i], txq_i); if (err) { XYLog("%s: could not allocate TX ring %d\n", DEVNAME(sc), txq_i); goto fail4; } } err = iwm_alloc_rx_ring(sc, &sc->rxq); if (err) { XYLog("%s: could not allocate RX ring\n", DEVNAME(sc)); goto fail4; } taskq_init(); sc->sc_nswq = taskq_create("iwmns", 1, IPL_NET, 0); if (sc->sc_nswq == NULL) goto fail4; XYLog("config ieee80211\n"); /* Clear pending interrupts. */ IWM_WRITE(sc, IWM_CSR_INT, 0xffffffff); ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ ic->ic_state = IEEE80211_S_INIT; /* Set device capabilities. */ ic->ic_caps = IEEE80211_C_WEP | /* WEP */ IEEE80211_C_RSN | /* WPA/RSN */ IEEE80211_C_SCANALL | /* device scans all channels at once */ IEEE80211_C_SCANALLBAND | /* device scans all bands at once */ IEEE80211_C_MONITOR | /* monitor mode supported */ IEEE80211_C_SHSLOT | /* short slot time supported */ IEEE80211_C_SHPREAMBLE; /* short preamble supported */ ic->ic_htcaps = IEEE80211_HTCAP_SGI20; ic->ic_htcaps |= (IEEE80211_HTCAP_SMPS_DIS << IEEE80211_HTCAP_SMPS_SHIFT); ic->ic_htcaps |= (IEEE80211_HTCAP_CBW20_40 | IEEE80211_HTCAP_SGI40); ic->ic_htxcaps = 0; ic->ic_txbfcaps = 0; ic->ic_aselcaps = 0; ic->ic_ampdu_params = (IEEE80211_AMPDU_PARAM_SS_4 | 0x3 /* 64k */); ic->ic_caps |= (IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU | IEEE80211_C_AMSDU_IN_AMPDU); ic->ic_caps |= IEEE80211_C_SUPPORTS_VHT_EXT_NSS_BW; #if 0 ic->ic_caps |= IEEE80211_C_TX_AMPDU_SETUP_IN_RS; #endif ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; for (i = 0; i < nitems(sc->sc_phyctxt); i++) { sc->sc_phyctxt[i].id = i; } sc->sc_amrr.amrr_min_success_threshold = 1; sc->sc_amrr.amrr_max_success_threshold = 15; /* IBSS channel undefined for now. */ ic->ic_ibss_chan = &ic->ic_channels[1]; ic->ic_max_rssi = IWM_MAX_DBM - IWM_MIN_DBM; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_DEBUG; ifp->if_ioctl = iwm_ioctl; ifp->if_start = iwm_start; ifp->if_watchdog = iwm_watchdog; memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); if_attach(ifp); ieee80211_ifattach(ifp, getController()); ieee80211_media_init(ifp); #if NBPFILTER > 0 iwm_radiotap_attach(sc); #endif timeout_set(&sc->sc_calib_to, iwm_calib_timeout, sc); timeout_set(&sc->sc_led_blink_to, iwm_led_blink_timeout, sc); for (i = 0; i < nitems(sc->sc_rxba_data); i++) { struct iwm_rxba_data *rxba = &sc->sc_rxba_data[i]; rxba->baid = IWM_RX_REORDER_DATA_INVALID_BAID; rxba->sc = sc; timeout_set(&rxba->session_timer, iwm_rx_ba_session_expired, rxba); timeout_set(&rxba->reorder_buf.reorder_timer, iwm_reorder_timer_expired, &rxba->reorder_buf); for (j = 0; j < nitems(rxba->entries); j++) ml_init(&rxba->entries[j].frames); } task_set(&sc->init_task, iwm_init_task, sc, "init_task"); task_set(&sc->newstate_task, iwm_newstate_task, sc, "newstate_task"); task_set(&sc->ba_task, iwm_ba_task, sc, "ba_task"); task_set(&sc->mac_ctxt_task, iwm_mac_ctxt_task, sc, "mac_ctxt_task"); task_set(&sc->chan_ctxt_task, iwm_chan_ctxt_task, sc, "chan_ctxt_task"); ic->ic_node_alloc = iwm_node_alloc; ic->ic_bgscan_start = iwm_bgscan; ic->ic_set_key = iwm_set_key; ic->ic_delete_key = iwm_delete_key; /* Override 802.11 state transition machine. */ sc->sc_newstate = ic->ic_newstate; ic->ic_newstate = iwm_newstate; ic->ic_updateprot = iwm_updateprot; ic->ic_updateslot = iwm_updateslot; ic->ic_updateedca = iwm_updateedca; ic->ic_updatedtim = iwm_updatedtim; ic->ic_ampdu_rx_start = iwm_ampdu_rx_start; ic->ic_ampdu_rx_stop = iwm_ampdu_rx_stop; ic->ic_ampdu_tx_start = iwm_ampdu_tx_start; ic->ic_ampdu_tx_stop = iwm_ampdu_tx_stop; ic->ic_update_chw = iwm_update_chw; /* * We cannot read the MAC address without loading the * firmware from disk. Postpone until mountroot is done. */ // config_mountroot(self, iwm_attach_hook); if (iwm_preinit(sc)) { goto fail5; } XYLog("attach succeed.\n"); return true; fail5: for (i = 0; i < nitems(sc->sc_rxba_data); i++) { struct iwm_rxba_data *rxba = &sc->sc_rxba_data[i]; iwm_clear_reorder_buffer(sc, rxba); } fail4: while (--txq_i >= 0) iwm_free_tx_ring(sc, &sc->txq[txq_i]); iwm_free_rx_ring(sc, &sc->rxq); iwm_dma_contig_free(&sc->sched_dma); fail3: if (sc->ict_dma.vaddr != NULL) iwm_dma_contig_free(&sc->ict_dma); fail2: iwm_dma_contig_free(&sc->kw_dma); fail1: iwm_dma_contig_free(&sc->fw_dma); XYLog("attach failed.\n"); return false; } #if NBPFILTER > 0 void ItlIwm:: iwm_radiotap_attach(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); bpfattach(&sc->sc_drvbpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO, sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN); sc->sc_rxtap_len = sizeof sc->sc_rxtapu; sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); sc->sc_rxtap.wr_ihdr.it_present = htole32(IWM_RX_RADIOTAP_PRESENT); sc->sc_txtap_len = sizeof sc->sc_txtapu; sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); sc->sc_txtap.wt_ihdr.it_present = htole32(IWM_TX_RADIOTAP_PRESENT); } #endif void ItlIwm:: iwm_init_task(void *arg1) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc *)arg1; ItlIwm *that = container_of(sc, ItlIwm, com); struct _ifnet *ifp = &sc->sc_ic.ic_if; int s = splnet(); int generation = sc->sc_generation; int fatal = (sc->sc_flags & (IWM_FLAG_HW_ERR | IWM_FLAG_RFKILL)); // rw_enter_write(&sc->ioctl_rwl); if (generation != sc->sc_generation) { // rw_exit(&sc->ioctl_rwl); splx(s); return; } if (ifp->if_flags & IFF_RUNNING) that->iwm_stop(ifp); else sc->sc_flags &= ~IWM_FLAG_HW_ERR; if (!fatal && (ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP) that->iwm_init(ifp); // rw_exit(&sc->ioctl_rwl); splx(s); } void ItlIwm:: iwm_mac_ctxt_task(void *arg) { struct iwm_softc *sc = (struct iwm_softc *)arg; ItlIwm *that = container_of(sc, ItlIwm, com); struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; int err, s = splnet(); if (sc->sc_flags & IWM_FLAG_SHUTDOWN || ic->ic_state != IEEE80211_S_RUN || in->in_phyctxt == NULL) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } err = that->iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 1); if (err) printf("%s: failed to update MAC\n", DEVNAME(sc)); that->iwm_unprotect_session(sc, in); // refcnt_rele_wake(&sc->task_refs); splx(s); } void ItlIwm:: iwm_chan_ctxt_task(void *arg) { struct iwm_softc *sc = (struct iwm_softc *)arg; struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; ItlIwm *that = container_of(sc, ItlIwm, com); int err, s = splnet(); if (sc->sc_flags & IWM_FLAG_SHUTDOWN || ic->ic_state != IEEE80211_S_RUN || in->in_phyctxt == NULL) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } int chains = that->iwm_mimo_enabled(sc) ? 2 : 1; err = that->iwm_phy_ctxt_update(sc, in->in_phyctxt, in->in_ni.ni_chan, chains, chains, 0); if (err) { XYLog("%s: failed to update PHY\n", __FUNCTION__); // refcnt_rele_wake(&sc->task_refs); splx(s); return; } rs_drv_rate_update(sc, &in->in_ni, IEEE80211_IS_CHAN_2GHZ(in->in_ni.ni_chan) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ, true); iwl_mvm_send_lq_cmd(sc, &sc->lq_sta.rs_drv.lq); // refcnt_rele_wake(&sc->task_refs); splx(s); } void ItlIwm:: iwm_ba_task(void *arg) { struct iwm_softc *sc = (struct iwm_softc *)arg; ItlIwm *that = container_of(sc, ItlIwm, com); struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; int s = splnet(); int tid, err = 0; if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) || ic->ic_state != IEEE80211_S_RUN) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } for (tid = 0; tid < IWM_MAX_TID_COUNT; tid++) { if (sc->sc_flags & IWM_FLAG_SHUTDOWN) break; if (sc->ba_rx.start_tidmask & (1 << tid)) { struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; err = that->iwm_sta_rx_agg(sc, ni, tid, ba->ba_winstart, ba->ba_winsize, ba->ba_timeout_val, 1); sc->ba_rx.start_tidmask &= ~(1 << tid); } else if (sc->ba_rx.stop_tidmask & (1 << tid)) { err = that->iwm_sta_rx_agg(sc, ni, tid, 0, 0, 0, 0); sc->ba_rx.stop_tidmask &= ~(1 << tid); } } for (tid = 0; tid < IWM_MAX_TID_COUNT && !err; tid++) { if (sc->sc_flags & IWM_FLAG_SHUTDOWN) break; struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; int qid = IWM_FIRST_AGG_TX_QUEUE + tid; struct iwm_tx_ring *ring = &sc->txq[qid]; struct iwm_tx_ba *tx_ba; uint16_t ssn = ba->ba_winstart; if (sc->ba_tx.start_tidmask & (1 << tid)) { uint8_t fifo = iwm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; XYLog("%s tx_start ssn=%d, tid=%d scd_queue=%d\n", __FUNCTION__, ssn, tid, qid); if (!that->iwm_nic_lock(sc)) goto out; if (that->iwm_enable_txq(sc, IWM_STATION_ID, qid, fifo, ssn, tid, 1)) goto out; /* * If iwm_enable_txq() employed the SCD hardware bug * workaround we must skip the frame with seqnum SSN. */ if (IWM_AGG_SSN_TO_TXQ_IDX(ring->cur) != IWM_AGG_SSN_TO_TXQ_IDX(ssn)) { ssn = (ssn + 1) & 0xfff; ieee80211_output_ba_move_window(ic, ni, tid, ssn); ni->ni_qos_txseqs[tid] = ssn; } if (that->iwm_add_sta_cmd(sc, (struct iwm_node *)ni, 1, IWM_STA_MODIFY_QUEUES)) goto out; sc->agg_tid_disable &= ~(1 << tid); sc->agg_queue_mask |= (1 << qid); sc->sc_tx_ba[tid].wn = (iwm_node *)ni; ba->ba_bitmap = 0; if (!that->iwm_sta_tx_agg(sc, ni, tid, 0, ssn, 1)) { ieee80211_addba_resp_accept(ic, ni, tid); sc->lq_sta.rs_drv.lq.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; XYLog("Tx aggregation enabled on ra = %s tid = %d\n", ether_sprintf(ni->ni_macaddr), tid); iwl_mvm_send_lq_cmd(sc, &sc->lq_sta.rs_drv.lq); } else { out: ieee80211_addba_resp_refuse(ic, ni, tid, IEEE80211_STATUS_UNSPECIFIED); } that->iwm_nic_unlock(sc); sc->ba_tx.start_tidmask &= ~(1 << tid); } else if (sc->ba_tx.stop_tidmask & (1 << tid)) { sc->agg_tid_disable |= (1 << tid); that->iwm_sta_tx_agg(sc, ni, tid, 0, 0, 0); that->iwm_ampdu_txq_advance(sc, ring, ring->cur); that->iwm_clear_oactive(sc, ring); /* In DQA-mode the queue isn't removed on agg termination */ tx_ba = &sc->sc_tx_ba[tid]; tx_ba->wn = NULL; tx_ba->lq_color = 0; tx_ba->rate_n_flags = 0; tx_ba->tpt_meas_start = 0; tx_ba->tx_count = 0; tx_ba->tx_count_last = 0; tx_ba->tx_time = 0; ba->ba_bitmap = 0; sc->ba_tx.stop_tidmask &= ~(1 << tid); } } // refcnt_rele_wake(&sc->task_refs); splx(s); } int ItlIwm:: iwm_resume(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); pcireg_t reg; /* Clear device-specific "PCI retry timeout" register (41h). */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40); pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00); if (!sc->sc_msix) { /* Hardware bug workaround. */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); if (reg & PCI_COMMAND_INTERRUPT_DISABLE) reg &= ~PCI_COMMAND_INTERRUPT_DISABLE; pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); } iwm_enable_rfkill_int(sc); iwm_check_rfkill(sc); return iwm_prepare_card_hw(sc); } void ItlIwm:: iwm_add_task(struct iwm_softc *sc, struct taskq *taskq, struct task *task) { int s = splnet(); if (sc->sc_flags & IWM_FLAG_SHUTDOWN) { splx(s); return; } // refcnt_take(&sc->task_refs); if (!task_add(taskq, task)) { // refcnt_rele_wake(&sc->task_refs); } splx(s); } void ItlIwm:: iwm_del_task(struct iwm_softc *sc, struct taskq *taskq, struct task *task) { if (task_del(taskq, task)) { // refcnt_rele(&sc->task_refs); } } int ItlIwm:: iwm_activate(struct iwm_softc *sc, int act) { struct _ifnet *ifp = &sc->sc_ic.ic_if; int err = 0; switch (act) { case DVACT_QUIESCE: if (ifp->if_flags & IFF_RUNNING) { // rw_enter_write(&sc->ioctl_rwl); iwm_stop(ifp); // rw_exit(&sc->ioctl_rwl); } break; case DVACT_RESUME: err = iwm_resume(sc); if (err) XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); break; case DVACT_WAKEUP: /* Hardware should be up at this point. */ if (iwm_set_hw_ready(sc)) task_add(systq, &sc->init_task); break; } return 0; } ================================================ FILE: itlwm/hal_iwm/nvm.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" /* * NVM read access and content parsing. We do not support * external NVM or writing NVM. */ /* list of NVM sections we are allowed/need to read */ const int iwm_nvm_to_read[] = { IWM_NVM_SECTION_TYPE_HW, IWM_NVM_SECTION_TYPE_SW, IWM_NVM_SECTION_TYPE_REGULATORY, IWM_NVM_SECTION_TYPE_CALIBRATION, IWM_NVM_SECTION_TYPE_PRODUCTION, IWM_NVM_SECTION_TYPE_REGULATORY_SDP, IWM_NVM_SECTION_TYPE_HW_8000, IWM_NVM_SECTION_TYPE_MAC_OVERRIDE, IWM_NVM_SECTION_TYPE_PHY_SKU, }; #define IWM_NVM_DEFAULT_CHUNK_SIZE (2*1024) #define IWM_NVM_WRITE_OPCODE 1 #define IWM_NVM_READ_OPCODE 0 int ItlIwm:: iwm_nvm_read_chunk(struct iwm_softc *sc, uint16_t section, uint16_t offset, uint16_t length, uint8_t *data, uint16_t *len) { offset = 0; struct iwm_nvm_access_cmd nvm_access_cmd = { .offset = htole16(offset), .length = htole16(length), .type = htole16(section), .op_code = IWM_NVM_READ_OPCODE, }; struct iwm_nvm_access_resp *nvm_resp; struct iwm_rx_packet *pkt; struct iwm_host_cmd cmd = { .id = IWM_NVM_ACCESS_CMD, .flags = (IWM_CMD_WANT_RESP | IWM_CMD_SEND_IN_RFKILL), .resp_pkt_len = IWM_CMD_RESP_MAX, .data = { &nvm_access_cmd, }, }; int err, offset_read; size_t bytes_read; uint8_t *resp_data; cmd.len[0] = sizeof(struct iwm_nvm_access_cmd); err = iwm_send_cmd(sc, &cmd); if (err) return err; pkt = cmd.resp_pkt; if (pkt->hdr.flags & IWM_CMD_FAILED_MSK) { err = EIO; goto exit; } /* Extract NVM response */ nvm_resp = (struct iwm_nvm_access_resp *)pkt->data; if (nvm_resp == NULL) return EIO; err = le16toh(nvm_resp->status); bytes_read = le16toh(nvm_resp->length); offset_read = le16toh(nvm_resp->offset); resp_data = nvm_resp->data; if (err) { err = EINVAL; goto exit; } if (offset_read != offset) { err = EINVAL; goto exit; } if (bytes_read > length) { err = EINVAL; goto exit; } memcpy(data + offset, resp_data, bytes_read); *len = bytes_read; exit: iwm_free_resp(sc, &cmd); return err; } /* * Reads an NVM section completely. * NICs prior to 7000 family doesn't have a real NVM, but just read * section 0 which is the EEPROM. Because the EEPROM reading is unlimited * by uCode, we need to manually check in this case that we don't * overflow and try to read more than the EEPROM size. */ int ItlIwm:: iwm_nvm_read_section(struct iwm_softc *sc, uint16_t section, uint8_t *data, uint16_t *len, size_t max_len) { XYLog("%s\n", __FUNCTION__); uint16_t chunklen, seglen; int err = 0; chunklen = seglen = IWM_NVM_DEFAULT_CHUNK_SIZE; *len = 0; /* Read NVM chunks until exhausted (reading less than requested) */ while (seglen == chunklen && *len < max_len) { err = iwm_nvm_read_chunk(sc, section, *len, chunklen, data, &seglen); if (err) return err; *len += seglen; } return err; } int ItlIwm:: iwm_parse_nvm_data(struct iwm_softc *sc, const uint16_t *nvm_hw, const uint16_t *nvm_sw, const uint16_t *nvm_calib, const uint16_t *mac_override, const uint16_t *phy_sku, const uint16_t *regulatory, int n_regulatory) { struct iwm_nvm_data *data = &sc->sc_nvm; uint8_t hw_addr[ETHER_ADDR_LEN]; uint32_t sku; uint16_t lar_config; data->nvm_version = le16_to_cpup(nvm_sw + IWM_NVM_VERSION); if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { uint16_t radio_cfg = le16_to_cpup(nvm_sw + IWM_RADIO_CFG); data->radio_cfg_type = IWM_NVM_RF_CFG_TYPE_MSK(radio_cfg); data->radio_cfg_step = IWM_NVM_RF_CFG_STEP_MSK(radio_cfg); data->radio_cfg_dash = IWM_NVM_RF_CFG_DASH_MSK(radio_cfg); data->radio_cfg_pnum = IWM_NVM_RF_CFG_PNUM_MSK(radio_cfg); sku = le16_to_cpup(nvm_sw + IWM_SKU); } else { uint32_t radio_cfg = le32_to_cpup((uint32_t *)(phy_sku + IWM_RADIO_CFG_8000)); data->radio_cfg_type = IWM_NVM_RF_CFG_TYPE_MSK_8000(radio_cfg); data->radio_cfg_step = IWM_NVM_RF_CFG_STEP_MSK_8000(radio_cfg); data->radio_cfg_dash = IWM_NVM_RF_CFG_DASH_MSK_8000(radio_cfg); data->radio_cfg_pnum = IWM_NVM_RF_CFG_PNUM_MSK_8000(radio_cfg); data->valid_tx_ant = IWM_NVM_RF_CFG_TX_ANT_MSK_8000(radio_cfg); data->valid_rx_ant = IWM_NVM_RF_CFG_RX_ANT_MSK_8000(radio_cfg); sku = le32_to_cpup((uint32_t *)(phy_sku + IWM_SKU_8000)); } data->sku_cap_band_24GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_24GHZ; data->sku_cap_band_52GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_52GHZ; data->sku_cap_11n_enable = sku & IWM_NVM_SKU_CAP_11N_ENABLE; data->sku_cap_11ac_enable = sku & IWM_NVM_SKU_CAP_11AC_ENABLE; data->sku_cap_mimo_disable = sku & IWM_NVM_SKU_CAP_MIMO_DISABLE; if (sc->sc_device_family >= IWM_DEVICE_FAMILY_8000) { uint16_t lar_offset = data->nvm_version < 0xE39 ? IWM_NVM_LAR_OFFSET_8000_OLD : IWM_NVM_LAR_OFFSET_8000; lar_config = le16_to_cpup(regulatory + lar_offset); data->lar_enabled = !!(lar_config & IWM_NVM_LAR_ENABLED_8000); data->n_hw_addrs = le16_to_cpup(nvm_sw + IWM_N_HW_ADDRS_8000); } else data->n_hw_addrs = le16_to_cpup(nvm_sw + IWM_N_HW_ADDRS); /* The byte order is little endian 16 bit, meaning 214365 */ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { memcpy(hw_addr, nvm_hw + IWM_HW_ADDR, ETHER_ADDR_LEN); data->hw_addr[0] = hw_addr[1]; data->hw_addr[1] = hw_addr[0]; data->hw_addr[2] = hw_addr[3]; data->hw_addr[3] = hw_addr[2]; data->hw_addr[4] = hw_addr[5]; data->hw_addr[5] = hw_addr[4]; } else iwm_set_hw_address_8000(sc, data, mac_override, nvm_hw); if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { if (sc->nvm_type == IWM_NVM_SDP) { iwm_init_channel_map(sc, regulatory, iwm_nvm_channels, MIN(n_regulatory, nitems(iwm_nvm_channels))); } else { iwm_init_channel_map(sc, &nvm_sw[IWM_NVM_CHANNELS], iwm_nvm_channels, nitems(iwm_nvm_channels)); } } else iwm_init_channel_map(sc, ®ulatory[IWM_NVM_CHANNELS_8000], iwm_nvm_channels_8000, MIN(n_regulatory, nitems(iwm_nvm_channels_8000))); data->calib_version = 255; /* TODO: this value will prevent some checks from failing, we need to check if this field is still needed, and if it does, where is it in the NVM */ return 0; } int ItlIwm:: iwm_parse_nvm_sections(struct iwm_softc *sc, struct iwm_nvm_section *sections) { XYLog("%s\n", __FUNCTION__); const uint16_t *hw, *sw, *calib, *mac_override = NULL, *phy_sku = NULL; const uint16_t *regulatory = NULL; int n_regulatory = 0; /* Checking for required sections */ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { if (!sections[IWM_NVM_SECTION_TYPE_SW].data || !sections[IWM_NVM_SECTION_TYPE_HW].data) { return ENOENT; } hw = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_HW].data; if (sc->nvm_type == IWM_NVM_SDP) { if (!sections[IWM_NVM_SECTION_TYPE_REGULATORY_SDP].data) return ENOENT; regulatory = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_REGULATORY_SDP].data; n_regulatory = sections[IWM_NVM_SECTION_TYPE_REGULATORY_SDP].length; } } else if (sc->sc_device_family >= IWM_DEVICE_FAMILY_8000) { /* SW and REGULATORY sections are mandatory */ if (!sections[IWM_NVM_SECTION_TYPE_SW].data || !sections[IWM_NVM_SECTION_TYPE_REGULATORY].data) { return ENOENT; } /* MAC_OVERRIDE or at least HW section must exist */ if (!sections[IWM_NVM_SECTION_TYPE_HW_8000].data && !sections[IWM_NVM_SECTION_TYPE_MAC_OVERRIDE].data) { return ENOENT; } /* PHY_SKU section is mandatory in B0 */ if (!sections[IWM_NVM_SECTION_TYPE_PHY_SKU].data) { return ENOENT; } regulatory = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_REGULATORY].data; n_regulatory = sections[IWM_NVM_SECTION_TYPE_REGULATORY].length; hw = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_HW_8000].data; mac_override = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_MAC_OVERRIDE].data; phy_sku = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_PHY_SKU].data; } else { panic("unknown device family %d\n", sc->sc_device_family); } sw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_SW].data; calib = (const uint16_t *) sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data; /* XXX should pass in the length of every section */ return iwm_parse_nvm_data(sc, hw, sw, calib, mac_override, phy_sku, regulatory, n_regulatory); } int ItlIwm:: iwm_nvm_init(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwm_nvm_section nvm_sections[IWM_NVM_NUM_OF_SECTIONS]; int i, section, err = 0; uint16_t len; uint8_t *buf; const size_t bufsz = sc->sc_nvm_max_section_size; memset(nvm_sections, 0, sizeof(nvm_sections)); buf = (uint8_t*)malloc(bufsz, M_DEVBUF, M_WAIT); if (buf == NULL) return ENOMEM; for (i = 0; i < nitems(iwm_nvm_to_read); i++) { section = iwm_nvm_to_read[i]; _KASSERT(section <= nitems(nvm_sections)); err = iwm_nvm_read_section(sc, section, buf, &len, bufsz); if (err) { err = 0; continue; } nvm_sections[section].data = (uint8_t*)malloc(len, M_DEVBUF, M_WAIT); if (nvm_sections[section].data == NULL) { err = ENOMEM; break; } memcpy(nvm_sections[section].data, buf, len); nvm_sections[section].length = len; } ::free(buf); if (err == 0) err = iwm_parse_nvm_sections(sc, nvm_sections); for (i = 0; i < IWM_NVM_NUM_OF_SECTIONS; i++) { if (nvm_sections[i].data != NULL) ::free(nvm_sections[i].data); } return err; } ================================================ FILE: itlwm/hal_iwm/phy.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" struct iwm_phy_db_entry * ItlIwm:: iwm_phy_db_get_section(struct iwm_softc *sc, uint16_t type, uint16_t chg_id) { struct iwm_phy_db *phy_db = &sc->sc_phy_db; if (type >= IWM_PHY_DB_MAX) return NULL; switch (type) { case IWM_PHY_DB_CFG: return &phy_db->cfg; case IWM_PHY_DB_CALIB_NCH: return &phy_db->calib_nch; case IWM_PHY_DB_CALIB_CHG_PAPD: if (chg_id >= IWM_NUM_PAPD_CH_GROUPS) return NULL; return &phy_db->calib_ch_group_papd[chg_id]; case IWM_PHY_DB_CALIB_CHG_TXP: if (chg_id >= IWM_NUM_TXP_CH_GROUPS) return NULL; return &phy_db->calib_ch_group_txp[chg_id]; default: return NULL; } return NULL; } int ItlIwm:: iwm_phy_db_set_section(struct iwm_softc *sc, struct iwm_calib_res_notif_phy_db *phy_db_notif) { uint16_t type = le16toh(phy_db_notif->type); uint16_t size = le16toh(phy_db_notif->length); struct iwm_phy_db_entry *entry; uint16_t chg_id = 0; if (type == IWM_PHY_DB_CALIB_CHG_PAPD || type == IWM_PHY_DB_CALIB_CHG_TXP) chg_id = le16toh(*(uint16_t *)phy_db_notif->data); entry = iwm_phy_db_get_section(sc, type, chg_id); if (!entry) return EINVAL; if (entry->data) ::free(entry->data); entry->data = (uint8_t*)malloc(size, M_DEVBUF, M_NOWAIT); if (!entry->data) { entry->size = 0; return ENOMEM; } memcpy(entry->data, phy_db_notif->data, size); entry->size = size; return 0; } int ItlIwm:: iwm_phy_db_get_section_data(struct iwm_softc *sc, uint32_t type, uint8_t **data, uint16_t *size, uint16_t ch_id) { struct iwm_phy_db_entry *entry; uint16_t ch_group_id = 0; if (type == IWM_PHY_DB_CALIB_CHG_PAPD) ch_group_id = iwm_channel_id_to_papd(ch_id); else if (type == IWM_PHY_DB_CALIB_CHG_TXP) ch_group_id = iwm_channel_id_to_txp(sc, ch_id); entry = iwm_phy_db_get_section(sc, type, ch_group_id); if (!entry) return EINVAL; *data = entry->data; *size = entry->size; return 0; } int ItlIwm:: iwm_send_phy_db_cmd(struct iwm_softc *sc, uint16_t type, uint16_t length, void *data) { XYLog("%s\n", __FUNCTION__); struct iwm_phy_db_cmd phy_db_cmd; struct iwm_host_cmd cmd = { .id = IWM_PHY_DB_CMD, .flags = IWM_CMD_ASYNC, }; phy_db_cmd.type = le16toh(type); phy_db_cmd.length = le16toh(length); cmd.data[0] = &phy_db_cmd; cmd.len[0] = sizeof(struct iwm_phy_db_cmd); cmd.data[1] = data; cmd.len[1] = length; return iwm_send_cmd(sc, &cmd); } int ItlIwm:: iwm_phy_db_send_all_channel_groups(struct iwm_softc *sc, uint16_t type, uint8_t max_ch_groups) { XYLog("%s\n", __FUNCTION__); uint16_t i; int err; struct iwm_phy_db_entry *entry; for (i = 0; i < max_ch_groups; i++) { entry = iwm_phy_db_get_section(sc, type, i); if (!entry) return EINVAL; if (!entry->size) continue; err = iwm_send_phy_db_cmd(sc, type, entry->size, entry->data); if (err) return err; DELAY(1000); } return 0; } int ItlIwm:: iwm_send_phy_db_data(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); uint8_t *data = NULL; uint16_t size = 0; int err; err = iwm_phy_db_get_section_data(sc, IWM_PHY_DB_CFG, &data, &size, 0); if (err) return err; err = iwm_send_phy_db_cmd(sc, IWM_PHY_DB_CFG, size, data); if (err) return err; err = iwm_phy_db_get_section_data(sc, IWM_PHY_DB_CALIB_NCH, &data, &size, 0); if (err) return err; err = iwm_send_phy_db_cmd(sc, IWM_PHY_DB_CALIB_NCH, size, data); if (err) return err; err = iwm_phy_db_send_all_channel_groups(sc, IWM_PHY_DB_CALIB_CHG_PAPD, IWM_NUM_PAPD_CH_GROUPS); if (err) return err; err = iwm_phy_db_send_all_channel_groups(sc, IWM_PHY_DB_CALIB_CHG_TXP, IWM_NUM_TXP_CH_GROUPS); if (err) return err; return 0; } /* * For the high priority TE use a time event type that has similar priority to * the FW's action scan priority. */ #define IWM_ROC_TE_TYPE_NORMAL IWM_TE_P2P_DEVICE_DISCOVERABLE #define IWM_ROC_TE_TYPE_MGMT_TX IWM_TE_P2P_CLIENT_ASSOC int ItlIwm:: iwm_send_time_event_cmd(struct iwm_softc *sc, const struct iwm_time_event_cmd *cmd) { struct iwm_rx_packet *pkt; struct iwm_time_event_resp *resp; struct iwm_host_cmd hcmd = { .id = IWM_TIME_EVENT_CMD, .flags = IWM_CMD_WANT_RESP, .resp_pkt_len = sizeof(*pkt) + sizeof(*resp), }; uint32_t resp_len; int err; hcmd.data[0] = cmd; hcmd.len[0] = sizeof(*cmd); err = iwm_send_cmd(sc, &hcmd); if (err) return err; pkt = hcmd.resp_pkt; if (!pkt || (pkt->hdr.flags & IWM_CMD_FAILED_MSK)) { err = EIO; goto out; } resp_len = iwm_rx_packet_payload_len(pkt); if (resp_len != sizeof(*resp)) { err = EIO; goto out; } resp = (struct iwm_time_event_resp *)pkt->data; if (le32toh(resp->status) == 0) sc->sc_time_event_uid = le32toh(resp->unique_id); else err = EIO; out: iwm_free_resp(sc, &hcmd); return err; } void ItlIwm:: iwm_protect_session(struct iwm_softc *sc, struct iwm_node *in, uint32_t duration, uint32_t max_delay) { struct iwm_time_event_cmd time_cmd; /* Do nothing if a time event is already scheduled. */ if (sc->sc_flags & IWM_FLAG_TE_ACTIVE) return; memset(&time_cmd, 0, sizeof(time_cmd)); time_cmd.action = htole32(IWM_FW_CTXT_ACTION_ADD); time_cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); time_cmd.id = htole32(IWM_TE_BSS_STA_AGGRESSIVE_ASSOC); time_cmd.apply_time = htole32(0); time_cmd.max_frags = IWM_TE_V2_FRAG_NONE; time_cmd.max_delay = htole32(max_delay); /* TODO: why do we need to interval = bi if it is not periodic? */ time_cmd.interval = htole32(1); time_cmd.duration = htole32(duration); time_cmd.repeat = 1; time_cmd.policy = htole16(IWM_TE_V2_NOTIF_HOST_EVENT_START | IWM_TE_V2_NOTIF_HOST_EVENT_END | IWM_T2_V2_START_IMMEDIATELY); if (iwm_send_time_event_cmd(sc, &time_cmd) == 0) sc->sc_flags |= IWM_FLAG_TE_ACTIVE; DELAY(100); } void ItlIwm:: iwm_unprotect_session(struct iwm_softc *sc, struct iwm_node *in) { struct iwm_time_event_cmd time_cmd; /* Do nothing if the time event has already ended. */ if ((sc->sc_flags & IWM_FLAG_TE_ACTIVE) == 0) return; memset(&time_cmd, 0, sizeof(time_cmd)); time_cmd.action = htole32(IWM_FW_CTXT_ACTION_REMOVE); time_cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); time_cmd.id = htole32(sc->sc_time_event_uid); if (iwm_send_time_event_cmd(sc, &time_cmd) == 0) sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE; DELAY(100); } int ItlIwm:: iwm_send_phy_cfg_cmd(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwm_phy_cfg_cmd phy_cfg_cmd; enum iwm_ucode_type ucode_type = sc->sc_uc_current; phy_cfg_cmd.phy_cfg = htole32(sc->sc_fw_phy_config); phy_cfg_cmd.calib_control.event_trigger = sc->sc_default_calib[ucode_type].event_trigger; phy_cfg_cmd.calib_control.flow_trigger = sc->sc_default_calib[ucode_type].flow_trigger; return iwm_send_cmd_pdu(sc, IWM_PHY_CONFIGURATION_CMD, 0, sizeof(phy_cfg_cmd), &phy_cfg_cmd); } int ItlIwm:: iwm_send_dqa_cmd(struct iwm_softc *sc) { struct iwm_dqa_enable_cmd dqa_cmd = { .cmd_queue = htole32(IWM_DQA_CMD_QUEUE), }; uint32_t cmd_id; cmd_id = iwm_cmd_id(IWM_DQA_ENABLE_CMD, IWM_DATA_PATH_GROUP, 0); return iwm_send_cmd_pdu(sc, cmd_id, 0, sizeof(dqa_cmd), &dqa_cmd); } int ItlIwm:: iwm_binding_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action) { struct iwm_binding_cmd cmd; struct iwm_phy_ctxt *phyctxt = in->in_phyctxt; uint32_t mac_id = IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color); int i, err, active = (sc->sc_flags & IWM_FLAG_BINDING_ACTIVE); uint32_t status; size_t len; if (action == IWM_FW_CTXT_ACTION_ADD && active) { XYLog("binding already added\n"); return 0; } if (action == IWM_FW_CTXT_ACTION_REMOVE && !active) { XYLog("binding already removed\n"); return 0; } if (phyctxt == NULL) /* XXX race with iwm_stop() */ return EINVAL; memset(&cmd, 0, sizeof(cmd)); cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color)); cmd.action = htole32(action); cmd.phy = htole32(IWM_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color)); cmd.macs[0] = htole32(mac_id); for (i = 1; i < IWM_MAX_MACS_IN_BINDING; i++) cmd.macs[i] = htole32(IWM_FW_CTXT_INVALID); if (IEEE80211_IS_CHAN_2GHZ(phyctxt->channel) || !isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_CDB_SUPPORT)) cmd.lmac_id = htole32(IWM_LMAC_24G_INDEX); else cmd.lmac_id = htole32(IWM_LMAC_5G_INDEX); if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) len = sizeof(cmd); else len = sizeof(struct iwm_binding_cmd_v1); status = 0; err = iwm_send_cmd_pdu_status(sc, IWM_BINDING_CONTEXT_CMD, len, &cmd, &status); if (err == 0 && status != 0) err = EIO; return err; } int ItlIwm:: iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd) { struct iwm_tx_ring *ring = &sc->txq[sc->cmdqid]; struct iwm_tfd *desc; struct iwm_tx_data *txdata; struct iwm_device_cmd *cmd; mbuf_t m; bus_addr_t paddr; uint32_t addr_lo; int err = 0, i, paylen, off, s; int idx, code, async, group_id; size_t hdrlen, datasz; uint8_t *data; int generation = sc->sc_generation; unsigned int max_chunks = 1; IOPhysicalSegment seg; code = hcmd->id; async = hcmd->flags & IWM_CMD_ASYNC; idx = ring->cur; for (i = 0, paylen = 0; i < nitems(hcmd->len); i++) { paylen += hcmd->len[i]; } /* If this command waits for a response, allocate response buffer. */ hcmd->resp_pkt = NULL; if (hcmd->flags & IWM_CMD_WANT_RESP) { uint8_t *resp_buf; _KASSERT(!async); _KASSERT(hcmd->resp_pkt_len >= sizeof(struct iwm_rx_packet)); _KASSERT(hcmd->resp_pkt_len <= IWM_CMD_RESP_MAX); if (sc->sc_cmd_resp_pkt[idx] != NULL) return ENOSPC; resp_buf = (uint8_t *)malloc(hcmd->resp_pkt_len, M_DEVBUF, M_NOWAIT | M_ZERO); if (resp_buf == NULL) return ENOMEM; sc->sc_cmd_resp_pkt[idx] = resp_buf; sc->sc_cmd_resp_len[idx] = hcmd->resp_pkt_len; } else { sc->sc_cmd_resp_pkt[idx] = NULL; } s = splnet(); desc = &ring->desc[idx]; txdata = &ring->data[idx]; group_id = iwm_cmd_groupid(code); if (group_id != 0) { hdrlen = sizeof(cmd->hdr_wide); datasz = sizeof(cmd->data_wide); } else { hdrlen = sizeof(cmd->hdr); datasz = sizeof(cmd->data); } if (paylen > datasz) { /* Command is too large to fit in pre-allocated space. */ size_t totlen = hdrlen + paylen; if (paylen > IWM_MAX_CMD_PAYLOAD_SIZE) { XYLog("%s: firmware command too long (%zd bytes)\n", DEVNAME(sc), totlen); err = EINVAL; goto out; } mbuf_allocpacket(MBUF_WAITOK, totlen, &max_chunks, &m); if (m == NULL) { XYLog("%s: could not get fw cmd mbuf (%zd bytes)\n", DEVNAME(sc), totlen); err = ENOMEM; goto out; } mbuf_setlen(m, totlen); mbuf_pkthdr_setlen(m, totlen); cmd = mtod(m, struct iwm_device_cmd *); txdata->map->dm_nsegs = txdata->map->cursor->getPhysicalSegmentsWithCoalesce(m, &seg, 1); if (txdata->map->dm_nsegs == 0) { XYLog("%s: could not load fw cmd mbuf (%zd bytes)\n", DEVNAME(sc), totlen); mbuf_freem(m); goto out; } // XYLog("map fw cmd dm_nsegs=%d\n", txdata->map->dm_nsegs); txdata->m = m; /* mbuf will be freed in iwm_cmd_done() */ paddr = seg.location; } else { cmd = &ring->cmd[idx]; paddr = txdata->cmd_paddr; } if (group_id != 0) { cmd->hdr_wide.opcode = iwm_cmd_opcode(code); cmd->hdr_wide.group_id = group_id; cmd->hdr_wide.qid = ring->qid; cmd->hdr_wide.idx = idx; cmd->hdr_wide.length = htole16(paylen); cmd->hdr_wide.version = iwm_cmd_version(code); data = cmd->data_wide; } else { cmd->hdr.code = code; cmd->hdr.flags = 0; cmd->hdr.qid = ring->qid; cmd->hdr.idx = idx; data = cmd->data; } for (i = 0, off = 0; i < nitems(hcmd->data); i++) { if (hcmd->len[i] == 0) continue; memcpy(data + off, hcmd->data[i], hcmd->len[i]); off += hcmd->len[i]; } KASSERT(off == paylen, "off == paylen"); /* lo field is not aligned */ addr_lo = htole32((uint32_t)paddr); memcpy(&desc->tbs[0].lo, &addr_lo, sizeof(uint32_t)); desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(paddr) | ((hdrlen + paylen) << 4)); desc->num_tbs = 1; // if (paylen > datasz) { // bus_dmamap_sync(sc->sc_dmat, txdata->map, 0, // hdrlen + paylen, BUS_DMASYNC_PREWRITE); // } else { // bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map, // (char *)(void *)cmd - (char *)(void *)ring->cmd_dma.vaddr, // hdrlen + paylen, BUS_DMASYNC_PREWRITE); // } // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, // (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr, // sizeof (*desc), BUS_DMASYNC_PREWRITE); /* * Wake up the NIC to make sure that the firmware will see the host * command - we will let the NIC sleep once all the host commands * returned. This needs to be done only on 7000 family NICs. */ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) { if (ring->queued == 0 && !iwm_nic_lock(sc)) { err = EBUSY; goto out; } } DPRINTFN(2, ("%s: sending command 0x%x\n", __func__, code)); iwm_update_sched(sc, ring->qid, ring->cur, 0, 0); /* Kick command ring. */ ring->queued++; ring->cur = (ring->cur + 1) % IWM_TX_RING_COUNT; IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); if (!async) { err = tsleep_nsec(desc, PCATCH, "iwmcmd", SEC_TO_NSEC(2)); if (err == 0) { /* if hardware is no longer up, return error */ if (generation != sc->sc_generation) { err = ENXIO; goto out; } /* Response buffer will be freed in iwm_free_resp(). */ hcmd->resp_pkt = (struct iwm_rx_packet *)sc->sc_cmd_resp_pkt[idx]; sc->sc_cmd_resp_pkt[idx] = NULL; } else if (generation == sc->sc_generation) { ::free(sc->sc_cmd_resp_pkt[idx]); sc->sc_cmd_resp_pkt[idx] = NULL; } } out: splx(s); return err; } int ItlIwm:: iwm_send_cmd_pdu(struct iwm_softc *sc, uint32_t id, uint32_t flags, uint16_t len, const void *data) { struct iwm_host_cmd cmd = { .id = id, .len = { len, }, .data = { data, }, .flags = flags, }; return iwm_send_cmd(sc, &cmd); } int ItlIwm:: iwm_send_cmd_status(struct iwm_softc *sc, struct iwm_host_cmd *cmd, uint32_t *status) { struct iwm_rx_packet *pkt; struct iwm_cmd_response *resp; int err, resp_len; KASSERT((cmd->flags & IWM_CMD_WANT_RESP) == 0, "(cmd->flags & IWM_CMD_WANT_RESP) == 0"); cmd->flags |= IWM_CMD_WANT_RESP; cmd->resp_pkt_len = sizeof(*pkt) + sizeof(*resp); err = iwm_send_cmd(sc, cmd); if (err) return err; pkt = cmd->resp_pkt; if (pkt == NULL || (pkt->hdr.flags & IWM_CMD_FAILED_MSK)) return EIO; resp_len = iwm_rx_packet_payload_len(pkt); if (resp_len != sizeof(*resp)) { iwm_free_resp(sc, cmd); return EIO; } resp = (struct iwm_cmd_response *)pkt->data; *status = le32toh(resp->status); iwm_free_resp(sc, cmd); return err; } int ItlIwm:: iwm_send_cmd_pdu_status(struct iwm_softc *sc, uint32_t id, uint16_t len, const void *data, uint32_t *status) { struct iwm_host_cmd cmd = { .id = id, .len = { len, }, .data = { data, }, }; return iwm_send_cmd_status(sc, &cmd, status); } void ItlIwm:: iwm_free_resp(struct iwm_softc *sc, struct iwm_host_cmd *hcmd) { _KASSERT((hcmd->flags & (IWM_CMD_WANT_RESP)) == IWM_CMD_WANT_RESP); ::free(hcmd->resp_pkt); hcmd->resp_pkt = NULL; } void ItlIwm:: iwm_cmd_done(struct iwm_softc *sc, int qid, int idx, int code) { struct iwm_tx_ring *ring = &sc->txq[sc->cmdqid]; struct iwm_tx_data *data; if (qid != sc->cmdqid) { return; /* Not a command ack. */ } data = &ring->data[idx]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } wakeupOn(&ring->desc[idx]); DPRINTFN(2, ("%s: command 0x%x done\n", __func__, code)); if (ring->queued == 0) { XYLog("%s: unexpected firmware response to command 0x%x\n", DEVNAME(sc), code); } else if (--ring->queued == 0) { /* * 7000 family NICs are locked while commands are in progress. * All commands are now done so we may unlock the NIC again. */ if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) iwm_nic_unlock(sc); } } int ItlIwm:: iwm_phy_ctxt_update(struct iwm_softc *sc, struct iwm_phy_ctxt *phyctxt, struct ieee80211_channel *chan, uint8_t chains_static, uint8_t chains_dynamic, uint32_t apply_time) { uint16_t band_flags = (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ); int err; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && (phyctxt->channel->ic_flags & band_flags) != (chan->ic_flags & band_flags)) { err = iwm_phy_ctxt_cmd(sc, phyctxt, chains_static, chains_dynamic, IWM_FW_CTXT_ACTION_REMOVE, apply_time); if (err) { printf("%s: could not remove PHY context " "(error %d)\n", DEVNAME(sc), err); return err; } phyctxt->channel = chan; err = iwm_phy_ctxt_cmd(sc, phyctxt, chains_static, chains_dynamic, IWM_FW_CTXT_ACTION_ADD, apply_time); if (err) { printf("%s: could not remove PHY context " "(error %d)\n", DEVNAME(sc), err); return err; } } else { phyctxt->channel = chan; err = iwm_phy_ctxt_cmd(sc, phyctxt, chains_static, chains_dynamic, IWM_FW_CTXT_ACTION_MODIFY, apply_time); if (err) { printf("%s: could not update PHY context (error %d)\n", DEVNAME(sc), err); return err; } } return 0; } ================================================ FILE: itlwm/hal_iwm/power.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" #define IWM_POWER_KEEP_ALIVE_PERIOD_SEC 25 int ItlIwm:: iwm_beacon_filter_send_cmd(struct iwm_softc *sc, struct iwm_beacon_filter_cmd *cmd) { return iwm_send_cmd_pdu(sc, IWM_REPLY_BEACON_FILTERING_CMD, 0, sizeof(struct iwm_beacon_filter_cmd), cmd); } void ItlIwm:: iwm_beacon_filter_set_cqm_params(struct iwm_softc *sc, struct iwm_node *in, struct iwm_beacon_filter_cmd *cmd) { cmd->ba_enable_beacon_abort = htole32(sc->sc_bf.ba_enabled); } int ItlIwm:: iwm_update_beacon_abort(struct iwm_softc *sc, struct iwm_node *in, int enable) { struct iwm_beacon_filter_cmd cmd = { IWM_BF_CMD_CONFIG_DEFAULTS, .bf_enable_beacon_filter = htole32(1), .ba_enable_beacon_abort = htole32(enable), }; if (!sc->sc_bf.bf_enabled) return 0; sc->sc_bf.ba_enabled = enable; iwm_beacon_filter_set_cqm_params(sc, in, &cmd); return iwm_beacon_filter_send_cmd(sc, &cmd); } void ItlIwm:: iwm_power_build_cmd(struct iwm_softc *sc, struct iwm_node *in, struct iwm_mac_power_cmd *cmd) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = &in->in_ni; int dtim_period, dtim_msec, keep_alive; cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); if (ni->ni_dtimperiod) dtim_period = ni->ni_dtimperiod; else dtim_period = 1; /* * Regardless of power management state the driver must set * keep alive period. FW will use it for sending keep alive NDPs * immediately after association. Check that keep alive period * is at least 3 * DTIM. */ dtim_msec = dtim_period * ni->ni_intval; keep_alive = MAX(3 * dtim_msec, 1000 * IWM_POWER_KEEP_ALIVE_PERIOD_SEC); keep_alive = roundup(keep_alive, 1000) / 1000; cmd->keep_alive_seconds = htole16(keep_alive); if (ic->ic_opmode != IEEE80211_M_MONITOR) cmd->flags = htole16(IWM_POWER_FLAGS_POWER_SAVE_ENA_MSK); } int ItlIwm:: iwm_power_mac_update_mode(struct iwm_softc *sc, struct iwm_node *in) { int err; int ba_enable; struct iwm_mac_power_cmd cmd; memset(&cmd, 0, sizeof(cmd)); iwm_power_build_cmd(sc, in, &cmd); err = iwm_send_cmd_pdu(sc, IWM_MAC_PM_POWER_TABLE, 0, sizeof(cmd), &cmd); if (err != 0) return err; ba_enable = !!(cmd.flags & htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); return iwm_update_beacon_abort(sc, in, ba_enable); } int ItlIwm:: iwm_power_update_device(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwm_device_power_cmd cmd = { }; struct ieee80211com *ic = &sc->sc_ic; if (ic->ic_opmode != IEEE80211_M_MONITOR) cmd.flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); return iwm_send_cmd_pdu(sc, IWM_POWER_TABLE_CMD, 0, sizeof(cmd), &cmd); } int ItlIwm:: iwm_enable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in) { struct iwm_beacon_filter_cmd cmd = { IWM_BF_CMD_CONFIG_DEFAULTS, .bf_enable_beacon_filter = htole32(1), }; int err; iwm_beacon_filter_set_cqm_params(sc, in, &cmd); err = iwm_beacon_filter_send_cmd(sc, &cmd); if (err == 0) sc->sc_bf.bf_enabled = 1; return err; } int ItlIwm:: iwm_disable_beacon_filter(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwm_beacon_filter_cmd cmd; int err; memset(&cmd, 0, sizeof(cmd)); err = iwm_beacon_filter_send_cmd(sc, &cmd); if (err == 0) sc->sc_bf.bf_enabled = 0; return err; } int ItlIwm:: iwm_add_sta_cmd(struct iwm_softc *sc, struct iwm_node *in, int update, unsigned int flags) { struct iwm_add_sta_cmd add_sta_cmd; int err; uint32_t status; size_t cmdsize; uint32_t aggsize = 0; uint32_t max_aggsize = (IWM_STA_FLG_MAX_AGG_SIZE_4M >> IWM_STA_FLG_MAX_AGG_SIZE_SHIFT); struct ieee80211com *ic = &sc->sc_ic; if (!update && (sc->sc_flags & IWM_FLAG_STA_ACTIVE)) { XYLog("STA already added\n"); return 0; } memset(&add_sta_cmd, 0, sizeof(add_sta_cmd)); if (ic->ic_opmode == IEEE80211_M_MONITOR) add_sta_cmd.sta_id = IWM_MONITOR_STA_ID; else add_sta_cmd.sta_id = IWM_STATION_ID; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_STA_TYPE)) { if (ic->ic_opmode == IEEE80211_M_MONITOR) add_sta_cmd.station_type = IWM_STA_GENERAL_PURPOSE; else add_sta_cmd.station_type = IWM_STA_LINK; } add_sta_cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); if (ic->ic_opmode == IEEE80211_M_MONITOR) { int qid; IEEE80211_ADDR_COPY(&add_sta_cmd.addr, etheranyaddr); if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) qid = IWM_DQA_INJECT_MONITOR_QUEUE; else qid = IWM_AUX_QUEUE; add_sta_cmd.tfd_queue_msk |= htole32(1 << qid); } else if (!update || (flags & IWM_STA_MODIFY_QUEUES)) { if (!update) { int ac; sc->agg_queue_mask = 0; sc->agg_tid_disable = 0xffff; for (ac = 0; ac < EDCA_NUM_AC; ac++) { int qid = ac; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) qid += IWM_DQA_MIN_MGMT_QUEUE; sc->agg_queue_mask |= htole32(1 << qid); } } add_sta_cmd.tfd_queue_msk = sc->agg_queue_mask; IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_macaddr); } add_sta_cmd.add_modify = update ? 1 : 0; add_sta_cmd.station_flags_msk |= htole32(IWM_STA_FLG_FAT_EN_MSK | IWM_STA_FLG_MIMO_EN_MSK); add_sta_cmd.tid_disable_tx = htole16(sc->agg_tid_disable); if (update) add_sta_cmd.modify_mask |= (IWM_STA_MODIFY_TID_DISABLE_TX); if ((in->in_ni.ni_flags & IEEE80211_NODE_HT) || (in->in_ni.ni_flags & IEEE80211_NODE_VHT)) { add_sta_cmd.station_flags_msk |= htole32(IWM_STA_FLG_MAX_AGG_SIZE_MSK | IWM_STA_FLG_AGG_MPDU_DENS_MSK); if (ic->ic_state >= IEEE80211_S_ASSOC) { switch (in->in_ni.ni_chw) { case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_FAT_EN_160MHZ); case IEEE80211_CHAN_WIDTH_80: add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_FAT_EN_80MHZ); case IEEE80211_CHAN_WIDTH_40: add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_FAT_EN_40MHZ); case IEEE80211_CHAN_WIDTH_20: default: add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_FAT_EN_20MHZ); break; } } if (iwm_mimo_enabled(sc) && ic->ic_bss->ni_rx_nss > 1) add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_MIMO_EN_MIMO2); else add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_MIMO_EN_SISO); if (in->in_ni.ni_flags & IEEE80211_NODE_VHT) { aggsize = in->in_ni.ni_vhtcaps & IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; aggsize >>= IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; add_sta_cmd.station_flags |= htole32(min(max_aggsize, aggsize) << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT); } else if (in->in_ni.ni_flags & IEEE80211_NODE_HT) add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_MAX_AGG_SIZE_64K); switch (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_SS) { case IEEE80211_AMPDU_PARAM_SS_2: add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_AGG_MPDU_DENS_2US); break; case IEEE80211_AMPDU_PARAM_SS_4: add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_AGG_MPDU_DENS_4US); break; case IEEE80211_AMPDU_PARAM_SS_8: add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_AGG_MPDU_DENS_8US); break; case IEEE80211_AMPDU_PARAM_SS_16: add_sta_cmd.station_flags |= htole32(IWM_STA_FLG_AGG_MPDU_DENS_16US); break; default: break; } } status = IWM_ADD_STA_SUCCESS; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_STA_TYPE)) cmdsize = sizeof(add_sta_cmd); else cmdsize = sizeof(struct iwm_add_sta_cmd_v7); err = iwm_send_cmd_pdu_status(sc, IWM_ADD_STA, cmdsize, &add_sta_cmd, &status); if (!err && (status & IWM_ADD_STA_STATUS_MASK) != IWM_ADD_STA_SUCCESS) { err = EIO; XYLog("%s failed\n", __FUNCTION__); } else sc->sc_flags |= IWM_FLAG_STA_ACTIVE; return err; } int ItlIwm:: iwm_add_aux_sta(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwm_add_sta_cmd cmd; int err, qid; uint32_t status; size_t cmdsize; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) { qid = IWM_DQA_AUX_QUEUE; err = iwm_enable_txq(sc, IWM_AUX_STA_ID, qid, IWM_TX_FIFO_MCAST, 0, IWM_MAX_TID_COUNT, 0); } else { qid = IWM_AUX_QUEUE; err = iwm_enable_ac_txq(sc, qid, IWM_TX_FIFO_MCAST); } if (err) return err; memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = IWM_AUX_STA_ID; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_STA_TYPE)) cmd.station_type = IWM_STA_AUX_ACTIVITY; cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(IWM_MAC_INDEX_AUX, 0)); cmd.tfd_queue_msk = htole32(1 << qid); cmd.tid_disable_tx = htole16(0xffff); status = IWM_ADD_STA_SUCCESS; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_STA_TYPE)) cmdsize = sizeof(cmd); else cmdsize = sizeof(struct iwm_add_sta_cmd_v7); err = iwm_send_cmd_pdu_status(sc, IWM_ADD_STA, cmdsize, &cmd, &status); if (!err && (status & IWM_ADD_STA_STATUS_MASK) != IWM_ADD_STA_SUCCESS) err = EIO; return err; } int ItlIwm:: iwm_drain_sta(struct iwm_softc *sc, struct iwm_node *in, bool drain) { struct iwm_add_sta_cmd cmd = {}; int err; uint32_t status; size_t cmdsize; cmd.mac_id_n_color = cpu_to_le32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); cmd.sta_id = IWM_STATION_ID; cmd.add_modify = IWM_STA_MODE_MODIFY; cmd.station_flags = drain ? cpu_to_le32(IWM_STA_FLG_DRAIN_FLOW) : 0; cmd.station_flags_msk = cpu_to_le32(IWM_STA_FLG_DRAIN_FLOW); status = IWM_ADD_STA_SUCCESS; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_STA_TYPE)) cmdsize = sizeof(cmd); else cmdsize = sizeof(struct iwm_add_sta_cmd_v7); err = iwm_send_cmd_pdu_status(sc, IWM_ADD_STA, cmdsize, &cmd, &status); return err; } int ItlIwm:: iwm_rm_sta_cmd(struct iwm_softc *sc, struct iwm_node *in) { struct ieee80211com *ic = &sc->sc_ic; struct iwm_rm_sta_cmd rm_sta_cmd; int err; uint8_t qid; if ((sc->sc_flags & IWM_FLAG_STA_ACTIVE) == 0) { XYLog("sta already removed\n"); return 0; } if (ic->ic_opmode == IEEE80211_M_STA) { err = iwm_drain_sta(sc, in, true); if (err) { XYLog("%s can not drain sta(TRUE)\n", __FUNCTION__); goto done; } err = iwm_flush_tx_path(sc, sc->agg_queue_mask); if (err) { XYLog("%s can not flush sta tx path\n", __FUNCTION__); goto done; } err = iwm_drain_sta(sc, in, false); if (err) { XYLog("%s can not drain sta(FALSE)\n", __FUNCTION__); goto done; } for (qid = IWM_FIRST_AGG_TX_QUEUE; qid <= IWM_LAST_AGG_TX_QUEUE; qid++) { if (sc->agg_queue_mask & (1 << qid)) { iwm_disable_txq(sc, qid, 0, 0); } } } memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); if (ic->ic_opmode == IEEE80211_M_MONITOR) rm_sta_cmd.sta_id = IWM_MONITOR_STA_ID; else rm_sta_cmd.sta_id = IWM_STATION_ID; err = iwm_send_cmd_pdu(sc, IWM_REMOVE_STA, 0, sizeof(rm_sta_cmd), &rm_sta_cmd); done: sc->agg_queue_mask = 0; sc->agg_tid_disable = 0xffff; sc->sc_flags &= ~IWM_FLAG_STA_ACTIVE; return err; } ================================================ FILE: itlwm/hal_iwm/rs.cpp ================================================ // // rs.cpp // itlwm // // Created by zxystd on 2021/8/27. // Copyright © 2021 钟先耀. All rights reserved. // #include "ItlIwm.hpp" #define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */ /* Calculations of success ratio are done in fixed point where 12800 is 100%. * Use this macro when dealing with thresholds consts set as a percentage */ #define RS_PERCENT(x) (128 * x) static u8 rs_ht_to_legacy[] = { [IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX, [IWL_RATE_MCS_1_INDEX] = IWL_RATE_9M_INDEX, [IWL_RATE_MCS_2_INDEX] = IWL_RATE_12M_INDEX, [IWL_RATE_MCS_3_INDEX] = IWL_RATE_18M_INDEX, [IWL_RATE_MCS_4_INDEX] = IWL_RATE_24M_INDEX, [IWL_RATE_MCS_5_INDEX] = IWL_RATE_36M_INDEX, [IWL_RATE_MCS_6_INDEX] = IWL_RATE_48M_INDEX, [IWL_RATE_MCS_7_INDEX] = IWL_RATE_54M_INDEX, [IWL_RATE_MCS_8_INDEX] = IWL_RATE_54M_INDEX, [IWL_RATE_MCS_9_INDEX] = IWL_RATE_54M_INDEX, }; static const u8 ant_toggle_lookup[] = { [ANT_NONE] = ANT_NONE, [ANT_A] = ANT_B, [ANT_B] = ANT_A, [ANT_AB] = ANT_AB, }; #define IWL_DECLARE_RATE_INFO(r, s, rp, rn) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ IWL_RATE_HT_SISO_MCS_##s##_PLCP, \ IWL_RATE_HT_MIMO2_MCS_##s##_PLCP, \ IWL_RATE_VHT_SISO_MCS_##s##_PLCP, \ IWL_RATE_VHT_MIMO2_MCS_##s##_PLCP,\ IWL_RATE_##rp##M_INDEX, \ IWL_RATE_##rn##M_INDEX } #define IWL_DECLARE_MCS_RATE(s) \ [IWL_RATE_MCS_##s##_INDEX] = { IWL_RATE_INVM_PLCP, \ IWL_RATE_HT_SISO_MCS_##s##_PLCP, \ IWL_RATE_HT_MIMO2_MCS_##s##_PLCP, \ IWL_RATE_VHT_SISO_MCS_##s##_PLCP, \ IWL_RATE_VHT_MIMO2_MCS_##s##_PLCP, \ IWL_RATE_INVM_INDEX, \ IWL_RATE_INVM_INDEX } /* * Parameter order: * rate, ht rate, prev rate, next rate * * If there isn't a valid next or previous rate then INV is used which * maps to IWL_RATE_INVALID * */ struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(1, INV, INV, 2), /* 1mbps */ IWL_DECLARE_RATE_INFO(2, INV, 1, 5), /* 2mbps */ IWL_DECLARE_RATE_INFO(5, INV, 2, 11), /*5.5mbps */ IWL_DECLARE_RATE_INFO(11, INV, 9, 12), /* 11mbps */ IWL_DECLARE_RATE_INFO(6, 0, 5, 11), /* 6mbps ; MCS 0 */ IWL_DECLARE_RATE_INFO(9, INV, 6, 11), /* 9mbps */ IWL_DECLARE_RATE_INFO(12, 1, 11, 18), /* 12mbps ; MCS 1 */ IWL_DECLARE_RATE_INFO(18, 2, 12, 24), /* 18mbps ; MCS 2 */ IWL_DECLARE_RATE_INFO(24, 3, 18, 36), /* 24mbps ; MCS 3 */ IWL_DECLARE_RATE_INFO(36, 4, 24, 48), /* 36mbps ; MCS 4 */ IWL_DECLARE_RATE_INFO(48, 5, 36, 54), /* 48mbps ; MCS 5 */ IWL_DECLARE_RATE_INFO(54, 6, 48, INV), /* 54mbps ; MCS 6 */ IWL_DECLARE_MCS_RATE(7), /* MCS 7 */ IWL_DECLARE_MCS_RATE(8), /* MCS 8 */ IWL_DECLARE_MCS_RATE(9), /* MCS 9 */ }; enum rs_action { RS_ACTION_STAY = 0, RS_ACTION_DOWNSCALE = -1, RS_ACTION_UPSCALE = 1, }; enum rs_column_mode { RS_INVALID = 0, RS_LEGACY, RS_SISO, RS_MIMO2, }; #define MAX_NEXT_COLUMNS 7 #define MAX_COLUMN_CHECKS 3 struct rs_tx_column; typedef bool (*allow_column_func_t) (struct iwm_softc *sc, struct ieee80211_node *ni, struct rs_rate *rate, const struct rs_tx_column *next_col); struct rs_tx_column { enum rs_column_mode mode; u8 ant; bool sgi; enum rs_column next_columns[MAX_NEXT_COLUMNS]; allow_column_func_t checks[MAX_COLUMN_CHECKS]; }; static bool rs_ant_allow(struct iwm_softc *sc, struct ieee80211_node *ni, struct rs_rate *rate, const struct rs_tx_column *next_col) { return ItlIwm::iwm_coex_is_ant_avail(sc, next_col->ant); } static bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwm_softc *sc, struct ieee80211_node *ni) { return ItlIwm::iwm_coex_is_mimo_allowed(sc, ni); } static bool rs_mimo_allow(struct iwm_softc *sc, struct ieee80211_node *ni, struct rs_rate *rate, const struct rs_tx_column *next_col) { ItlIwm *that = container_of(sc, ItlIwm, com); if (!ieee80211_node_supports_ht(ni)) return false; // if (sta->smps_mode == IEEE80211_SMPS_STATIC) // return false; if (that->iwm_num_of_ant(that->iwm_fw_valid_tx_ant(sc)) < 2) return false; if (!iwl_mvm_bt_coex_is_mimo_allowed(sc, ni)) return false; if (sc->sc_nvm.sku_cap_mimo_disable) return false; return true; } static bool rs_siso_allow(struct iwm_softc *sc, struct ieee80211_node *ni, struct rs_rate *rate, const struct rs_tx_column *next_col) { if (!ieee80211_node_supports_ht(ni)) return false; return true; } static bool rs_sgi_allow(struct iwm_softc *sc, struct ieee80211_node *ni, struct rs_rate *rate, const struct rs_tx_column *next_col) { if (is_ht20(rate) && (ieee80211_node_supports_ht_sgi20(ni))) return true; if (is_ht40(rate) && (ieee80211_node_supports_ht_sgi40(ni))) return true; if (is_ht80(rate) && (ieee80211_node_supports_vht_sgi80(ni))) return true; if (is_ht160(rate) && (ieee80211_node_supports_vht_sgi160(ni))) return true; return false; } static const struct rs_tx_column rs_tx_columns[] = { [RS_COLUMN_LEGACY_ANT_A] = { .mode = RS_LEGACY, .ant = ANT_A, .next_columns = { RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_SISO_ANT_A, RS_COLUMN_MIMO2, RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, .checks = { rs_ant_allow, }, }, [RS_COLUMN_LEGACY_ANT_B] = { .mode = RS_LEGACY, .ant = ANT_B, .next_columns = { RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, .checks = { rs_ant_allow, }, }, [RS_COLUMN_SISO_ANT_A] = { .mode = RS_SISO, .ant = ANT_A, .next_columns = { RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, rs_ant_allow, }, }, [RS_COLUMN_SISO_ANT_B] = { .mode = RS_SISO, .ant = ANT_B, .next_columns = { RS_COLUMN_SISO_ANT_A, RS_COLUMN_MIMO2, RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, rs_ant_allow, }, }, [RS_COLUMN_SISO_ANT_A_SGI] = { .mode = RS_SISO, .ant = ANT_A, .sgi = true, .next_columns = { RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_MIMO2_SGI, RS_COLUMN_SISO_ANT_A, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, rs_ant_allow, rs_sgi_allow, }, }, [RS_COLUMN_SISO_ANT_B_SGI] = { .mode = RS_SISO, .ant = ANT_B, .sgi = true, .next_columns = { RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_MIMO2_SGI, RS_COLUMN_SISO_ANT_B, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, rs_ant_allow, rs_sgi_allow, }, }, [RS_COLUMN_MIMO2] = { .mode = RS_MIMO2, .ant = ANT_AB, .next_columns = { RS_COLUMN_SISO_ANT_A, RS_COLUMN_MIMO2_SGI, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, .checks = { rs_mimo_allow, }, }, [RS_COLUMN_MIMO2_SGI] = { .mode = RS_MIMO2, .ant = ANT_AB, .sgi = true, .next_columns = { RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_MIMO2, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, .checks = { rs_mimo_allow, rs_sgi_allow, }, }, }; static inline u8 rs_extract_rate(u32 rate_n_flags) { /* also works for HT because bits 7:6 are zero there */ return (u8)(rate_n_flags & RATE_LEGACY_RATE_MSK); } static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) { int idx = 0; if (rate_n_flags & RATE_MCS_HT_MSK) { idx = rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK; idx += IWL_RATE_MCS_0_INDEX; /* skip 9M not supported in HT*/ if (idx >= IWL_RATE_9M_INDEX) idx += 1; if ((idx >= IWL_FIRST_HT_RATE) && (idx <= IWL_LAST_HT_RATE)) return idx; } else if (rate_n_flags & RATE_MCS_VHT_MSK || rate_n_flags & RATE_MCS_HE_MSK) { idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; idx += IWL_RATE_MCS_0_INDEX; /* skip 9M not supported in VHT*/ if (idx >= IWL_RATE_9M_INDEX) idx++; if ((idx >= IWL_FIRST_VHT_RATE) && (idx <= IWL_LAST_VHT_RATE)) return idx; if ((rate_n_flags & RATE_MCS_HE_MSK) && (idx <= IWL_LAST_HE_RATE)) return idx; } else { /* legacy rate format, search for match in table */ u8 legacy_rate = rs_extract_rate(rate_n_flags); for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++) if (iwl_rates[idx].plcp == legacy_rate) return idx; } return IWL_RATE_INVALID; } static void rs_rate_scale_perform(struct iwm_softc *sc, struct ieee80211_node *ni, struct iwl_lq_sta *lq_sta, int tid, bool ndp); static void rs_fill_lq_cmd(struct iwm_softc *sc, struct ieee80211_node *ni, struct iwl_lq_sta *lq_sta, const struct rs_rate *initial_rate); static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search); /* * The following tables contain the expected throughput metrics for all rates * * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits * * where invalid entries are zeros. * * CCK rates are only valid in legacy table and will only be used in G * (2.4 GHz) band. */ static const u16 expected_tpt_legacy[IWL_RATE_COUNT] = { 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0 }; /* Expected TpT tables. 4 indexes: * 0 - NGI, 1 - SGI, 2 - AGG+NGI, 3 - AGG+SGI */ static const u16 expected_tpt_siso_20MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 42, 0, 76, 102, 124, 159, 183, 193, 202, 216, 0}, {0, 0, 0, 0, 46, 0, 82, 110, 132, 168, 192, 202, 210, 225, 0}, {0, 0, 0, 0, 49, 0, 97, 145, 192, 285, 375, 420, 464, 551, 0}, {0, 0, 0, 0, 54, 0, 108, 160, 213, 315, 415, 465, 513, 608, 0}, }; static const u16 expected_tpt_siso_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 77, 0, 127, 160, 184, 220, 242, 250, 257, 269, 275}, {0, 0, 0, 0, 83, 0, 135, 169, 193, 229, 250, 257, 264, 275, 280}, {0, 0, 0, 0, 101, 0, 199, 295, 389, 570, 744, 828, 911, 1070, 1173}, {0, 0, 0, 0, 112, 0, 220, 326, 429, 629, 819, 912, 1000, 1173, 1284}, }; static const u16 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 130, 0, 191, 223, 244, 273, 288, 294, 298, 305, 308}, {0, 0, 0, 0, 138, 0, 200, 231, 251, 279, 293, 298, 302, 308, 312}, {0, 0, 0, 0, 217, 0, 429, 634, 834, 1220, 1585, 1760, 1931, 2258, 2466}, {0, 0, 0, 0, 241, 0, 475, 701, 921, 1343, 1741, 1931, 2117, 2468, 2691}, }; static const u16 expected_tpt_siso_160MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 191, 0, 244, 288, 298, 308, 313, 318, 323, 328, 330}, {0, 0, 0, 0, 200, 0, 251, 293, 302, 312, 317, 322, 327, 332, 334}, {0, 0, 0, 0, 439, 0, 875, 1307, 1736, 2584, 3419, 3831, 4240, 5049, 5581}, {0, 0, 0, 0, 488, 0, 972, 1451, 1925, 2864, 3785, 4240, 4691, 5581, 6165}, }; static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250, 261, 0}, {0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256, 267, 0}, {0, 0, 0, 0, 98, 0, 193, 286, 375, 550, 718, 799, 878, 1032, 0}, {0, 0, 0, 0, 109, 0, 214, 316, 414, 607, 790, 879, 965, 1132, 0}, }; static const u16 expected_tpt_mimo2_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 123, 0, 182, 214, 235, 264, 279, 285, 289, 296, 300}, {0, 0, 0, 0, 131, 0, 191, 222, 242, 270, 284, 289, 293, 300, 303}, {0, 0, 0, 0, 200, 0, 390, 571, 741, 1067, 1365, 1505, 1640, 1894, 2053}, {0, 0, 0, 0, 221, 0, 430, 630, 816, 1169, 1490, 1641, 1784, 2053, 2221}, }; static const u16 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 182, 0, 240, 264, 278, 299, 308, 311, 313, 317, 319}, {0, 0, 0, 0, 190, 0, 247, 269, 282, 302, 310, 313, 315, 319, 320}, {0, 0, 0, 0, 428, 0, 833, 1215, 1577, 2254, 2863, 3147, 3418, 3913, 4219}, {0, 0, 0, 0, 474, 0, 920, 1338, 1732, 2464, 3116, 3418, 3705, 4225, 4545}, }; static const u16 expected_tpt_mimo2_160MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 240, 0, 278, 308, 313, 319, 322, 324, 328, 330, 334}, {0, 0, 0, 0, 247, 0, 282, 310, 315, 320, 323, 325, 329, 332, 338}, {0, 0, 0, 0, 875, 0, 1735, 2582, 3414, 5043, 6619, 7389, 8147, 9629, 10592}, {0, 0, 0, 0, 971, 0, 1925, 2861, 3779, 5574, 7304, 8147, 8976, 10592, 11640}, }; /* mbps, mcs */ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { { "1", "BPSK DSSS"}, { "2", "QPSK DSSS"}, {"5.5", "BPSK CCK"}, { "11", "QPSK CCK"}, { "6", "BPSK 1/2"}, { "9", "BPSK 1/2"}, { "12", "QPSK 1/2"}, { "18", "QPSK 3/4"}, { "24", "16QAM 1/2"}, { "36", "16QAM 3/4"}, { "48", "64QAM 2/3"}, { "54", "64QAM 3/4"}, { "60", "64QAM 5/6"}, }; #define MCS_INDEX_PER_STREAM (8) static const char *rs_pretty_ant(u8 ant) { static const char * const ant_name[] = { [ANT_NONE] = "None", [ANT_A] = "A", [ANT_B] = "B", [ANT_AB] = "AB", [ANT_C] = "C", [ANT_AC] = "AC", [ANT_BC] = "BC", [ANT_ABC] = "ABC", }; if (ant > ANT_ABC) return "UNKNOWN"; return ant_name[ant]; } static const char *rs_pretty_lq_type(enum iwl_table_type type) { static const char * const lq_types[] = { [LQ_NONE] = "NONE", [LQ_LEGACY_A] = "LEGACY_A", [LQ_LEGACY_G] = "LEGACY_G", [LQ_HT_SISO] = "HT SISO", [LQ_HT_MIMO2] = "HT MIMO", [LQ_VHT_SISO] = "VHT SISO", [LQ_VHT_MIMO2] = "VHT MIMO", [LQ_HE_SISO] = "HE SISO", [LQ_HE_MIMO2] = "HE MIMO", }; if (type < LQ_NONE || type >= LQ_MAX) return "UNKNOWN"; return lq_types[type]; } static char *rs_pretty_rate(const struct rs_rate *rate) { static char buf[40]; static const char * const legacy_rates[] = { [IWL_RATE_1M_INDEX] = "1M", [IWL_RATE_2M_INDEX] = "2M", [IWL_RATE_5M_INDEX] = "5.5M", [IWL_RATE_11M_INDEX] = "11M", [IWL_RATE_6M_INDEX] = "6M", [IWL_RATE_9M_INDEX] = "9M", [IWL_RATE_12M_INDEX] = "12M", [IWL_RATE_18M_INDEX] = "18M", [IWL_RATE_24M_INDEX] = "24M", [IWL_RATE_36M_INDEX] = "36M", [IWL_RATE_48M_INDEX] = "48M", [IWL_RATE_54M_INDEX] = "54M", }; static const char *const ht_vht_rates[] = { [IWL_RATE_MCS_0_INDEX] = "MCS0", [IWL_RATE_MCS_1_INDEX] = "MCS1", [IWL_RATE_MCS_2_INDEX] = "MCS2", [IWL_RATE_MCS_3_INDEX] = "MCS3", [IWL_RATE_MCS_4_INDEX] = "MCS4", [IWL_RATE_MCS_5_INDEX] = "MCS5", [IWL_RATE_MCS_6_INDEX] = "MCS6", [IWL_RATE_MCS_7_INDEX] = "MCS7", [IWL_RATE_MCS_8_INDEX] = "MCS8", [IWL_RATE_MCS_9_INDEX] = "MCS9", }; const char *rate_str; if (is_type_legacy(rate->type) && (rate->index <= IWL_RATE_54M_INDEX)) rate_str = legacy_rates[rate->index]; else if ((is_type_ht(rate->type) || is_type_vht(rate->type)) && (rate->index >= IWL_RATE_MCS_0_INDEX) && (rate->index <= IWL_RATE_MCS_9_INDEX)) rate_str = ht_vht_rates[rate->index]; else rate_str = NULL; snprintf(buf, sizeof(buf), "(%s|%s|%s)", rs_pretty_lq_type(rate->type), rs_pretty_ant(rate->ant), rate_str ?: "BAD_RATE"); return buf; } static inline void rs_dump_rate(struct iwm_softc *sc, const struct rs_rate *rate, const char *prefix) { IWL_DEBUG_RATE(sc, "%s: %s BW: %d SGI: %d LDPC: %d STBC: %d\n", prefix, rs_pretty_rate(rate), rate->bw, rate->sgi, rate->ldpc, rate->stbc); } static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) { window->data = 0; window->success_counter = 0; window->success_ratio = IWL_INVALID_VALUE; window->counter = 0; window->average_tpt = IWL_INVALID_VALUE; } static void rs_rate_scale_clear_tbl_windows(struct iwm_softc *sc, struct iwl_scale_tbl_info *tbl) { int i; IWL_DEBUG_RATE(sc, "Clearing up window stats\n"); for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&tbl->win[i]); for (i = 0; i < ARRAY_SIZE(tbl->tpc_win); i++) rs_rate_scale_clear_window(&tbl->tpc_win[i]); } static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type) { return (ant_type & valid_antenna) == ant_type; } extern int ieee80211_can_use_ampdu(struct ieee80211com *, struct ieee80211_node *); static int rs_tl_turn_on_agg_for_tid(struct iwm_softc *sc, struct iwl_lq_sta *lq_data, u8 tid, struct ieee80211_node *ni) { IWL_DEBUG_RATE(sc, "Starting Tx agg: STA: %s tid: %d\n", ether_sprintf(ni->ni_macaddr), tid); /* start BA session until the peer sends del BA */ if (!ieee80211_can_use_ampdu(&sc->sc_ic, ni)) return -1; ieee80211_node_trigger_addba_req(ni, tid); return 0; } static void rs_tl_turn_on_agg(struct iwm_softc *sc, u8 tid, struct iwl_lq_sta *lq_sta, struct ieee80211_node *ni) { struct iwm_tx_ba *tid_data; struct ieee80211_tx_ba *tx_ba; struct ieee80211com *ic = &sc->sc_ic; if ((ic->ic_caps & IEEE80211_C_TX_AMPDU_SETUP_IN_RS) == 0) return; /* * In AP mode, tid can be equal to IWL_MAX_TID_COUNT * when the frame is not QoS */ if (WARN_ON_ONCE(tid > IWL_MAX_TID_COUNT)) { IWL_ERR(mvm, "tid exceeds max TID count: %d/%d\n", tid, IWL_MAX_TID_COUNT); return; } else if (tid == IWL_MAX_TID_COUNT) { return; } tx_ba = &ni->ni_tx_ba[tid]; tid_data = &sc->sc_tx_ba[tid]; if (sc->sc_ic.ic_state >= IEEE80211_S_RUN && tx_ba->ba_state == IEEE80211_BA_INIT && (lq_sta->tx_agg_tid_en & BIT(tid)) && tid_data->tx_count_last >= IWL_MVM_RS_AGG_START_THRESHOLD) { IWL_DEBUG_RATE("RS: try to aggregate tid %d\n", tid); rs_tl_turn_on_agg_for_tid(sc, lq_sta, tid, ni); } } static inline int get_num_of_ant_from_rate(u32 rate_n_flags) { return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) + !!(rate_n_flags & RATE_MCS_ANT_B_MSK) + !!(rate_n_flags & RATE_MCS_ANT_C_MSK); } /* * Static function to get the expected throughput from an iwl_scale_tbl_info * that wraps a NULL pointer check */ static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index) { if (tbl->expected_tpt) return tbl->expected_tpt[rs_index]; return 0; } /* * rs_collect_tx_data - Update the success/failure sliding window * * We keep a sliding window of the last 62 packets transmitted * at this rate. window->data contains the bitmask of successful * packets. */ static int _rs_collect_tx_data(struct iwm_softc *sc, struct iwl_scale_tbl_info *tbl, int scale_index, int attempts, int successes, struct iwl_rate_scale_data *window) { static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1)); s32 fail_count, tpt; /* Get expected throughput */ tpt = get_expected_tpt(tbl, scale_index); /* * Keep track of only the latest 62 tx frame attempts in this rate's * history window; anything older isn't really relevant any more. * If we have filled up the sliding window, drop the oldest attempt; * if the oldest attempt (highest bit in bitmap) shows "success", * subtract "1" from the success counter (this is the main reason * we keep these bitmaps!). */ while (attempts > 0) { if (window->counter >= IWL_RATE_MAX_WINDOW) { /* remove earliest */ window->counter = IWL_RATE_MAX_WINDOW - 1; if (window->data & mask) { window->data &= ~mask; window->success_counter--; } } /* Increment frames-attempted counter */ window->counter++; /* Shift bitmap by one frame to throw away oldest history */ window->data <<= 1; /* Mark the most recent #successes attempts as successful */ if (successes > 0) { window->success_counter++; window->data |= 0x1; successes--; } attempts--; } /* Calculate current success ratio, avoid divide-by-0! */ if (window->counter > 0) window->success_ratio = 128 * (100 * window->success_counter) / window->counter; else window->success_ratio = IWL_INVALID_VALUE; fail_count = window->counter - window->success_counter; /* Calculate average throughput, if we have enough history. */ if ((fail_count >= IWL_MVM_RS_RATE_MIN_FAILURE_TH) || (window->success_counter >= IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) window->average_tpt = (window->success_ratio * tpt + 64) / 128; else window->average_tpt = IWL_INVALID_VALUE; return 0; } static int rs_collect_tpc_data(struct iwm_softc *sc, struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl, int scale_index, int attempts, int successes, u8 reduced_txp) { struct iwl_rate_scale_data *window = NULL; if (WARN_ON_ONCE(reduced_txp > TPC_MAX_REDUCTION)) return -EINVAL; window = &tbl->tpc_win[reduced_txp]; return _rs_collect_tx_data(sc, tbl, scale_index, attempts, successes, window); } static void rs_update_tid_tpt_stats(struct iwm_softc *sc, u8 tid, int successes) { if (tid >= IWL_MAX_TID_COUNT) return; struct iwm_tx_ba *tid_data = &sc->sc_tx_ba[tid]; /* * Measure if there're enough successful transmits per second. * These statistics are used only to decide if we can start a * BA session, so it should be updated only when A-MPDU is * off. */ if (tid_data->wn != NULL) return; if (time_is_before_jiffies(tid_data->tpt_meas_start + hz) || (tid_data->tx_count >= IWL_MVM_RS_AGG_START_THRESHOLD)) { tid_data->tx_count_last = tid_data->tx_count; tid_data->tx_count = 0; tid_data->tpt_meas_start = ticks; } else { tid_data->tx_count += successes; } } static int rs_collect_tlc_data(struct iwm_softc *sc, u8 tid, struct iwl_scale_tbl_info *tbl, int scale_index, int attempts, int successes) { struct iwl_rate_scale_data *window = NULL; if (scale_index < 0 || scale_index >= IWL_RATE_COUNT) return -EINVAL; if (tbl->column != RS_COLUMN_INVALID) { struct lq_sta_pers *pers = &sc->lq_sta.rs_drv.pers; pers->tx_stats[tbl->column][scale_index].total += attempts; pers->tx_stats[tbl->column][scale_index].success += successes; } rs_update_tid_tpt_stats(sc, tid, successes); /* Select window for current tx bit rate */ window = &(tbl->win[scale_index]); return _rs_collect_tx_data(sc, tbl, scale_index, attempts, successes, window); } /* Convert rs_rate object into ucode rate bitmask */ static u32 ucode_rate_from_rs_rate(struct iwm_softc *sc, struct rs_rate *rate) { u32 ucode_rate = 0; int index = rate->index; ucode_rate |= ((rate->ant << RATE_MCS_ANT_POS) & RATE_MCS_ANT_ABC_MSK); if (is_legacy(rate)) { ucode_rate |= iwl_rates[index].plcp; if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) ucode_rate |= RATE_MCS_CCK_MSK; return ucode_rate; } /* set RTS protection for all non legacy rates * This helps with congested environments reducing the conflict cost to * RTS retries only, instead of the entire BA packet. */ ucode_rate |= RATE_MCS_RTS_REQUIRED_MSK; if (is_ht(rate)) { if (index < IWL_FIRST_HT_RATE || index > IWL_LAST_HT_RATE) { IWL_ERR(mvm, "Invalid HT rate index %d\n", index); index = IWL_LAST_HT_RATE; } ucode_rate |= RATE_MCS_HT_MSK; if (is_ht_siso(rate)) ucode_rate |= iwl_rates[index].plcp_ht_siso; else if (is_ht_mimo2(rate)) ucode_rate |= iwl_rates[index].plcp_ht_mimo2; else WARN_ON_ONCE(1); } else if (is_vht(rate)) { if (index < IWL_FIRST_VHT_RATE || index > IWL_LAST_VHT_RATE) { IWL_ERR(mvm, "Invalid VHT rate index %d\n", index); index = IWL_LAST_VHT_RATE; } ucode_rate |= RATE_MCS_VHT_MSK; if (is_vht_siso(rate)) ucode_rate |= iwl_rates[index].plcp_vht_siso; else if (is_vht_mimo2(rate)) ucode_rate |= iwl_rates[index].plcp_vht_mimo2; else WARN_ON_ONCE(1); } else { IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type); } if (is_siso(rate) && rate->stbc) { /* To enable STBC we need to set both a flag and ANT_AB */ ucode_rate |= RATE_MCS_ANT_AB_MSK; ucode_rate |= RATE_MCS_STBC_MSK; } ucode_rate |= rate->bw; if (rate->sgi) ucode_rate |= RATE_MCS_SGI_MSK; if (rate->ldpc) ucode_rate |= RATE_MCS_LDPC_MSK; return ucode_rate; } /* Convert a ucode rate into an rs_rate object */ static int rs_rate_from_ucode_rate(const u32 ucode_rate, enum nl80211_band band, struct rs_rate *rate) { u32 ant_msk = ucode_rate & RATE_MCS_ANT_ABC_MSK; u8 num_of_ant = get_num_of_ant_from_rate(ucode_rate); u8 nss; memset(rate, 0, sizeof(*rate)); rate->index = iwl_hwrate_to_plcp_idx(ucode_rate); if (rate->index == IWL_RATE_INVALID) return -EINVAL; rate->ant = (ant_msk >> RATE_MCS_ANT_POS); /* Legacy */ if (!(ucode_rate & RATE_MCS_HT_MSK) && !(ucode_rate & RATE_MCS_VHT_MSK) && !(ucode_rate & RATE_MCS_HE_MSK)) { if (num_of_ant == 1) { if (band == NL80211_BAND_5GHZ) rate->type = LQ_LEGACY_A; else rate->type = LQ_LEGACY_G; } return 0; } /* HT, VHT or HE */ if (ucode_rate & RATE_MCS_SGI_MSK) rate->sgi = true; if (ucode_rate & RATE_MCS_LDPC_MSK) rate->ldpc = true; if (ucode_rate & RATE_MCS_STBC_MSK) rate->stbc = true; if (ucode_rate & RATE_MCS_BF_MSK) rate->bfer = true; rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; if (ucode_rate & RATE_MCS_HT_MSK) { nss = ((ucode_rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1; if (nss == 1) { rate->type = LQ_HT_SISO; WARN_ON(!rate->stbc && !rate->bfer && num_of_ant != 1, "stbc %d bfer %d", rate->stbc, rate->bfer); } else if (nss == 2) { rate->type = LQ_HT_MIMO2; WARN_ON_ONCE(num_of_ant != 2); } else { WARN_ON_ONCE(1); } } else if (ucode_rate & RATE_MCS_VHT_MSK) { nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >> RATE_VHT_MCS_NSS_POS) + 1; if (nss == 1) { rate->type = LQ_VHT_SISO; WARN_ON(!rate->stbc && !rate->bfer && num_of_ant != 1, "stbc %d bfer %d", rate->stbc, rate->bfer); } else if (nss == 2) { rate->type = LQ_VHT_MIMO2; WARN_ON_ONCE(num_of_ant != 2); } else { WARN_ON_ONCE(1); } } else if (ucode_rate & RATE_MCS_HE_MSK) { nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >> RATE_VHT_MCS_NSS_POS) + 1; if (nss == 1) { rate->type = LQ_HE_SISO; WARN_ON(!rate->stbc && !rate->bfer && num_of_ant != 1, "stbc %d bfer %d", rate->stbc, rate->bfer); } else if (nss == 2) { rate->type = LQ_HE_MIMO2; WARN_ON_ONCE(num_of_ant != 2); } else { WARN_ON_ONCE(1); } } WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_80 && !is_he(rate) && !is_vht(rate)); return 0; } /* switch to another antenna/antennas and return 1 */ /* if no other valid antenna found, return 0 */ static int rs_toggle_antenna(u32 valid_ant, struct rs_rate *rate) { u8 new_ant_type; if (!rate->ant || WARN_ON_ONCE(rate->ant & ANT_C)) return 0; if (!rs_is_valid_ant(valid_ant, rate->ant)) return 0; new_ant_type = ant_toggle_lookup[rate->ant]; while ((new_ant_type != rate->ant) && !rs_is_valid_ant(valid_ant, new_ant_type)) new_ant_type = ant_toggle_lookup[new_ant_type]; if (new_ant_type == rate->ant) return 0; rate->ant = new_ant_type; return 1; } static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta, struct rs_rate *rate) { if (is_legacy(rate)) return lq_sta->active_legacy_rate; else if (is_siso(rate)) return lq_sta->active_siso_rate; else if (is_mimo2(rate)) return lq_sta->active_mimo2_rate; WARN_ON_ONCE(1); return 0; } static u16 rs_get_adjacent_rate(struct iwm_softc *sc, u8 index, u16 rate_mask, int rate_type) { u8 high = IWL_RATE_INVALID; u8 low = IWL_RATE_INVALID; /* 802.11A or ht walks to the next literal adjacent rate in * the rate table */ if (is_type_a_band(rate_type) || !is_type_legacy(rate_type)) { int i; u32 mask; /* Find the previous rate that is in the rate mask */ i = index - 1; if (i >= 0) mask = BIT(i); for (; i >= 0; i--, mask >>= 1) { if (rate_mask & mask) { low = i; break; } } /* Find the next rate that is in the rate mask */ i = index + 1; for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) { if (rate_mask & mask) { high = i; break; } } return (high << 8) | low; } low = index; while (low != IWL_RATE_INVALID) { low = iwl_rates[low].prev_rs; if (low == IWL_RATE_INVALID) break; if (rate_mask & (1 << low)) break; } high = index; while (high != IWL_RATE_INVALID) { high = iwl_rates[high].next_rs; if (high == IWL_RATE_INVALID) break; if (rate_mask & (1 << high)) break; } return (high << 8) | low; } static inline bool rs_rate_supported(struct iwl_lq_sta *lq_sta, struct rs_rate *rate) { return BIT(rate->index) & rs_get_supported_rates(lq_sta, rate); } /* Get the next supported lower rate in the current column. * Return true if bottom rate in the current column was reached */ static bool rs_get_lower_rate_in_column(struct iwl_lq_sta *lq_sta, struct rs_rate *rate) { u8 low; u16 high_low; u16 rate_mask; struct iwm_softc *sc = lq_sta->pers.drv; rate_mask = rs_get_supported_rates(lq_sta, rate); high_low = rs_get_adjacent_rate(sc, rate->index, rate_mask, rate->type); low = high_low & 0xff; /* Bottom rate of column reached */ if (low == IWL_RATE_INVALID) return true; rate->index = low; return false; } /* Get the next rate to use following a column downgrade */ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, struct rs_rate *rate) { struct iwm_softc *sc = lq_sta->pers.drv; ItlIwm *that = container_of(sc, ItlIwm, com); if (is_legacy(rate)) { /* No column to downgrade from Legacy */ return; } else if (is_siso(rate)) { /* Downgrade to Legacy if we were in SISO */ if (lq_sta->band == NL80211_BAND_5GHZ) rate->type = LQ_LEGACY_A; else rate->type = LQ_LEGACY_G; rate->bw = RATE_MCS_CHAN_WIDTH_20; if (WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX)) rate->index = rs_ht_to_legacy[IWL_RATE_MCS_0_INDEX]; else if (WARN_ON_ONCE(rate->index > IWL_RATE_MCS_9_INDEX)) rate->index = rs_ht_to_legacy[IWL_RATE_MCS_9_INDEX]; else rate->index = rs_ht_to_legacy[rate->index]; rate->ldpc = false; } else { /* Downgrade to SISO with same MCS if in MIMO */ rate->type = is_vht_mimo2(rate) ? LQ_VHT_SISO : LQ_HT_SISO; } if (that->iwm_num_of_ant(rate->ant) > 1) rate->ant = first_antenna(that->iwm_fw_valid_tx_ant(sc)); /* Relevant in both switching to SISO or Legacy */ rate->sgi = false; if (!rs_rate_supported(lq_sta, rate)) rs_get_lower_rate_in_column(lq_sta, rate); } /* Check if both rates share the same column */ static inline bool rs_rate_column_match(struct rs_rate *a, struct rs_rate *b) { bool ant_match; if (a->stbc || a->bfer) ant_match = (b->ant == ANT_A || b->ant == ANT_B); else ant_match = (a->ant == b->ant); return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi) && ant_match; } static inline enum rs_column rs_get_column_from_rate(struct rs_rate *rate) { if (is_legacy(rate)) { if (rate->ant == ANT_A) return RS_COLUMN_LEGACY_ANT_A; if (rate->ant == ANT_B) return RS_COLUMN_LEGACY_ANT_B; goto err; } if (is_siso(rate)) { if (rate->ant == ANT_A || rate->stbc || rate->bfer) return rate->sgi ? RS_COLUMN_SISO_ANT_A_SGI : RS_COLUMN_SISO_ANT_A; if (rate->ant == ANT_B) return rate->sgi ? RS_COLUMN_SISO_ANT_B_SGI : RS_COLUMN_SISO_ANT_B; goto err; } if (is_mimo(rate)) return rate->sgi ? RS_COLUMN_MIMO2_SGI : RS_COLUMN_MIMO2; err: return RS_COLUMN_INVALID; } /* * mac80211 sends us Tx status */ void rs_drv_mac80211_tx_status(struct iwm_softc *sc, struct ieee80211_node *sta, struct ieee80211_tx_info *info, int tid, uint16_t fc, int ssn) { if (!ieee80211_is_data(fc) || info->flags & IEEE80211_TX_CTL_NO_ACK) return; iwl_mvm_rs_tx_status(sc, sta, tid, info, false); } /* * Begin a period of staying with a selected modulation mode. * Set "stay_in_tbl" flag to prevent any mode switches. * Set frame tx success limits according to legacy vs. high-throughput, * and reset overall (spanning all rates) tx success history statistics. * These control how long we stay using same modulation mode before * searching for a new mode. */ static void rs_set_stay_in_table(struct iwm_softc *mvm, u8 is_legacy, struct iwl_lq_sta *lq_sta) { IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_STAY_IN_COLUMN\n"); lq_sta->rs_state = RS_STATE_STAY_IN_COLUMN; if (is_legacy) { lq_sta->table_count_limit = IWL_MVM_RS_LEGACY_TABLE_COUNT; lq_sta->max_failure_limit = IWL_MVM_RS_LEGACY_FAILURE_LIMIT; lq_sta->max_success_limit = IWL_MVM_RS_LEGACY_SUCCESS_LIMIT; } else { lq_sta->table_count_limit = IWL_MVM_RS_NON_LEGACY_TABLE_COUNT; lq_sta->max_failure_limit = IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT; lq_sta->max_success_limit = IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT; } lq_sta->table_count = 0; lq_sta->total_failed = 0; lq_sta->total_success = 0; lq_sta->flush_timer = ticks; lq_sta->visited_columns = 0; } static inline int rs_get_max_rate_from_mask(unsigned long rate_mask) { if (rate_mask) return find_last_bit(&rate_mask, BITS_PER_LONG); return IWL_RATE_INVALID; } static int rs_get_max_allowed_rate(struct iwl_lq_sta *lq_sta, const struct rs_tx_column *column) { switch (column->mode) { case RS_LEGACY: return lq_sta->max_legacy_rate_idx; case RS_SISO: return lq_sta->max_siso_rate_idx; case RS_MIMO2: return lq_sta->max_mimo2_rate_idx; default: WARN_ON_ONCE(1); } return lq_sta->max_legacy_rate_idx; } static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, const struct rs_tx_column *column, u32 bw) { /* Used to choose among HT tables */ const u16 (*ht_tbl_pointer)[IWL_RATE_COUNT]; if (WARN_ON_ONCE(column->mode != RS_LEGACY && column->mode != RS_SISO && column->mode != RS_MIMO2)) return expected_tpt_legacy; /* Legacy rates have only one table */ if (column->mode == RS_LEGACY) return expected_tpt_legacy; ht_tbl_pointer = expected_tpt_mimo2_20MHz; /* Choose among many HT tables depending on number of streams * (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation * status */ if (column->mode == RS_SISO) { switch (bw) { case RATE_MCS_CHAN_WIDTH_20: ht_tbl_pointer = expected_tpt_siso_20MHz; break; case RATE_MCS_CHAN_WIDTH_40: ht_tbl_pointer = expected_tpt_siso_40MHz; break; case RATE_MCS_CHAN_WIDTH_80: ht_tbl_pointer = expected_tpt_siso_80MHz; break; case RATE_MCS_CHAN_WIDTH_160: ht_tbl_pointer = expected_tpt_siso_160MHz; break; default: WARN_ON_ONCE(1); } } else if (column->mode == RS_MIMO2) { switch (bw) { case RATE_MCS_CHAN_WIDTH_20: ht_tbl_pointer = expected_tpt_mimo2_20MHz; break; case RATE_MCS_CHAN_WIDTH_40: ht_tbl_pointer = expected_tpt_mimo2_40MHz; break; case RATE_MCS_CHAN_WIDTH_80: ht_tbl_pointer = expected_tpt_mimo2_80MHz; break; case RATE_MCS_CHAN_WIDTH_160: ht_tbl_pointer = expected_tpt_mimo2_160MHz; break; default: WARN_ON_ONCE(1); } } else { WARN_ON_ONCE(1); } if (!column->sgi && !lq_sta->is_agg) /* Normal */ return ht_tbl_pointer[0]; else if (column->sgi && !lq_sta->is_agg) /* SGI */ return ht_tbl_pointer[1]; else if (!column->sgi && lq_sta->is_agg) /* AGG */ return ht_tbl_pointer[2]; else /* AGG+SGI */ return ht_tbl_pointer[3]; } static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl) { struct rs_rate *rate = &tbl->rate; const struct rs_tx_column *column = &rs_tx_columns[tbl->column]; tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw); } /* rs uses two tables, one is active and the second is for searching better * configuration. This function, according to the index of the currently * active table returns the search table, which is located at the * index complementary to 1 according to the active table (active = 1, * search = 0 or active = 0, search = 1). * Since lq_info is an arary of size 2, make sure index cannot be out of bounds. */ static inline u8 rs_search_tbl(u8 active_tbl) { return (active_tbl ^ 1) & 1; } static s32 rs_get_best_rate(struct iwm_softc *sc, struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl, /* "search" */ unsigned long rate_mask, s8 index) { struct iwl_scale_tbl_info *active_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); s32 success_ratio = active_tbl->win[index].success_ratio; u16 expected_current_tpt = active_tbl->expected_tpt[index]; const u16 *tpt_tbl = tbl->expected_tpt; u16 high_low; u32 target_tpt; int rate_idx; if (success_ratio >= RS_PERCENT(IWL_MVM_RS_SR_NO_DECREASE)) { target_tpt = 100 * expected_current_tpt; IWL_DEBUG_RATE(mvm, "SR %d high. Find rate exceeding EXPECTED_CURRENT %d\n", success_ratio, target_tpt); } else { target_tpt = lq_sta->last_tpt; IWL_DEBUG_RATE(mvm, "SR %d not that good. Find rate exceeding ACTUAL_TPT %d\n", success_ratio, target_tpt); } rate_idx = find_first_bit(&rate_mask, BITS_PER_LONG); while (rate_idx != IWL_RATE_INVALID) { if (target_tpt < (100 * tpt_tbl[rate_idx])) break; high_low = rs_get_adjacent_rate(sc, rate_idx, rate_mask, tbl->rate.type); rate_idx = (high_low >> 8) & 0xff; } IWL_DEBUG_RATE(mvm, "Best rate found %d target_tp %d expected_new %d\n", rate_idx, target_tpt, rate_idx != IWL_RATE_INVALID ? 100 * tpt_tbl[rate_idx] : IWL_INVALID_VALUE); return rate_idx; } static u32 rs_bw_from_sta_bw(struct ieee80211_node *ni) { struct ieee80211_vht_cap vht_cap = { .vht_cap_info = cpu_to_le32(ni->ni_vhtcaps), .supp_mcs = ni->ni_vht_mcsinfo, }; if (ni->ni_chw == IEEE80211_CHAN_WIDTH_40 && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) return RATE_MCS_CHAN_WIDTH_20; switch (ni->ni_chw) { case IEEE80211_CHAN_WIDTH_160: /* * Don't use 160 MHz if VHT extended NSS support * says we cannot use 2 streams, we don't want to * deal with this. * We only check MCS 0 - they will support that if * we got here at all and we don't care which MCS, * we want to determine a more global state. */ if (ieee80211_get_vht_max_nss(&vht_cap, IEEE80211_VHT_CHANWIDTH_160MHZ, 0, true, ni->ni_rx_nss) < ni->ni_rx_nss) return RATE_MCS_CHAN_WIDTH_80; return RATE_MCS_CHAN_WIDTH_160; case IEEE80211_CHAN_WIDTH_80: return RATE_MCS_CHAN_WIDTH_80; case IEEE80211_CHAN_WIDTH_40: return RATE_MCS_CHAN_WIDTH_40; case IEEE80211_CHAN_WIDTH_20: default: return RATE_MCS_CHAN_WIDTH_20; } } /* * Check whether we should continue using same modulation mode, or * begin search for a new mode, based on: * 1) # tx successes or failures while using this mode * 2) # times calling this function * 3) elapsed time in this mode (not used, for now) */ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) { struct iwl_scale_tbl_info *tbl; int active_tbl; int flush_interval_passed = 0; struct iwm_softc *sc; sc = lq_sta->pers.drv; active_tbl = lq_sta->active_tbl; tbl = &(lq_sta->lq_info[active_tbl]); /* If we've been disallowing search, see if we should now allow it */ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { /* Elapsed time using current modulation mode */ if (lq_sta->flush_timer) flush_interval_passed = time_after(ticks, (unsigned long)(lq_sta->flush_timer + (IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT * hz))); /* * Check if we should allow search for new modulation mode. * If many frames have failed or succeeded, or we've used * this same modulation for a long time, allow search, and * reset history stats that keep track of whether we should * allow a new search. Also (below) reset all bitmaps and * stats in active history. */ if (force_search || (lq_sta->total_failed > lq_sta->max_failure_limit) || (lq_sta->total_success > lq_sta->max_success_limit) || ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer) && (flush_interval_passed))) { IWL_DEBUG_RATE(mvm, "LQ: stay is expired %d %d %d\n", lq_sta->total_failed, lq_sta->total_success, flush_interval_passed); /* Allow search for new mode */ lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_STARTED; IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_SEARCH_CYCLE_STARTED\n"); lq_sta->total_failed = 0; lq_sta->total_success = 0; lq_sta->flush_timer = 0; /* mark the current column as visited */ lq_sta->visited_columns = BIT(tbl->column); /* * Else if we've used this modulation mode enough repetitions * (regardless of elapsed time or success/failure), reset * history bitmaps and rate-specific stats for all rates in * active table. */ } else { lq_sta->table_count++; if (lq_sta->table_count >= lq_sta->table_count_limit) { lq_sta->table_count = 0; IWL_DEBUG_RATE(sc, "LQ: stay in table clear win\n"); rs_rate_scale_clear_tbl_windows(sc, tbl); } } /* If transitioning to allow "search", reset all history * bitmaps and stats in active table (this will become the new * "search" table). */ if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) { rs_rate_scale_clear_tbl_windows(sc, tbl); } } } static void rs_set_amsdu_len(struct iwm_softc *sc, struct ieee80211_node *ni, struct iwl_scale_tbl_info *tbl, enum rs_action scale_action) { #if 0 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); int i; sta->max_amsdu_len = rs_fw_get_max_amsdu_len(sta); /* * In case TLC offload is not active amsdu_enabled is either 0xFFFF * or 0, since there is no per-TID alg. */ if ((!is_vht(&tbl->rate) && !is_ht(&tbl->rate)) || tbl->rate.index < IWL_RATE_MCS_5_INDEX || scale_action == RS_ACTION_DOWNSCALE) mvmsta->amsdu_enabled = 0; else mvmsta->amsdu_enabled = 0xFFFF; if (mvmsta->vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) mvmsta->max_amsdu_len = sta->max_amsdu_len; else mvmsta->max_amsdu_len = min_t(int, sta->max_amsdu_len, 8500); sta->max_rc_amsdu_len = mvmsta->max_amsdu_len; for (i = 0; i < IWL_MAX_TID_COUNT; i++) { if (mvmsta->amsdu_enabled) sta->max_tid_amsdu_len[i] = iwl_mvm_max_amsdu_size(mvm, sta, i); else /* * Not so elegant, but this will effectively * prevent AMSDU on this TID */ sta->max_tid_amsdu_len[i] = 1; } #endif } /** * iwl_mvm_send_lq_cmd() - Send link quality command * @mvm: Driver data. * @lq: Link quality command to send. * * The link quality command is sent as the last step of station creation. * This is the special case in which init is set and we call a callback in * this case to clear the state indicating that station creation is in * progress. */ int iwl_mvm_send_lq_cmd(struct iwm_softc *sc, struct iwm_lq_cmd *lq) { ItlIwm *that = container_of(sc, ItlIwm, com); struct iwm_host_cmd cmd = { .id = IWM_LQ_CMD, .len = { sizeof(struct iwm_lq_cmd), }, .flags = IWM_CMD_ASYNC, .data = { lq, }, }; return that->iwm_send_cmd(sc, &cmd);; } /* * setup rate table in uCode */ static void rs_update_rate_tbl(struct iwm_softc *sc, struct ieee80211_node *ni, struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl) { rs_fill_lq_cmd(sc, ni, lq_sta, &tbl->rate); iwl_mvm_send_lq_cmd(sc, &lq_sta->lq); } static bool rs_tweak_rate_tbl(struct iwm_softc *sc, struct ieee80211_node *ni, struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl, enum rs_action scale_action) { if (rs_bw_from_sta_bw(ni) != RATE_MCS_CHAN_WIDTH_80) return false; if (!is_vht_siso(&tbl->rate)) return false; if ((tbl->rate.bw == RATE_MCS_CHAN_WIDTH_80) && (tbl->rate.index == IWL_RATE_MCS_0_INDEX) && (scale_action == RS_ACTION_DOWNSCALE)) { tbl->rate.bw = RATE_MCS_CHAN_WIDTH_20; tbl->rate.index = IWL_RATE_MCS_4_INDEX; IWL_DEBUG_RATE(sc, "Switch 80Mhz SISO MCS0 -> 20Mhz MCS4\n"); goto tweaked; } /* Go back to 80Mhz MCS1 only if we've established that 20Mhz MCS5 is * sustainable, i.e. we're past the test window. We can't go back * if MCS5 is just tested as this will happen always after switching * to 20Mhz MCS4 because the rate stats are cleared. */ if ((tbl->rate.bw == RATE_MCS_CHAN_WIDTH_20) && (((tbl->rate.index == IWL_RATE_MCS_5_INDEX) && (scale_action == RS_ACTION_STAY)) || ((tbl->rate.index > IWL_RATE_MCS_5_INDEX) && (scale_action == RS_ACTION_UPSCALE)))) { tbl->rate.bw = RATE_MCS_CHAN_WIDTH_80; tbl->rate.index = IWL_RATE_MCS_1_INDEX; IWL_DEBUG_RATE(sc, "Switch 20Mhz SISO MCS5 -> 80Mhz MCS1\n"); goto tweaked; } return false; tweaked: rs_set_expected_tpt_table(lq_sta, tbl); rs_rate_scale_clear_tbl_windows(sc, tbl); return true; } static enum rs_column rs_get_next_column(struct iwm_softc *sc, struct iwl_lq_sta *lq_sta, struct ieee80211_node *ni, struct iwl_scale_tbl_info *tbl) { int i, j, max_rate; enum rs_column next_col_id; const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column]; const struct rs_tx_column *next_col; allow_column_func_t allow_func; ItlIwm *that = container_of(sc, ItlIwm, com); u8 valid_ants = that->iwm_fw_valid_tx_ant(sc); const u16 *expected_tpt_tbl; u16 tpt, max_expected_tpt; for (i = 0; i < MAX_NEXT_COLUMNS; i++) { next_col_id = curr_col->next_columns[i]; if (next_col_id == RS_COLUMN_INVALID) continue; if (lq_sta->visited_columns & BIT(next_col_id)) { IWL_DEBUG_RATE(sc, "Skip already visited column %d\n", next_col_id); continue; } next_col = &rs_tx_columns[next_col_id]; if (!rs_is_valid_ant(valid_ants, next_col->ant)) { IWL_DEBUG_RATE(sc, "Skip column %d as ANT config isn't supported by chip. valid_ants 0x%x column ant 0x%x\n", next_col_id, valid_ants, next_col->ant); continue; } for (j = 0; j < MAX_COLUMN_CHECKS; j++) { allow_func = next_col->checks[j]; if (allow_func && !allow_func(sc, ni, &tbl->rate, next_col)) break; } if (j != MAX_COLUMN_CHECKS) { IWL_DEBUG_RATE(sc, "Skip column %d: not allowed (check %d failed)\n", next_col_id, j); continue; } tpt = lq_sta->last_tpt / 100; expected_tpt_tbl = rs_get_expected_tpt_table(lq_sta, next_col, rs_bw_from_sta_bw(ni)); if (WARN_ON_ONCE(!expected_tpt_tbl)) continue; max_rate = rs_get_max_allowed_rate(lq_sta, next_col); if (max_rate == IWL_RATE_INVALID) { IWL_DEBUG_RATE(sc, "Skip column %d: no rate is allowed in this column\n", next_col_id); continue; } max_expected_tpt = expected_tpt_tbl[max_rate]; if (tpt >= max_expected_tpt) { IWL_DEBUG_RATE(sc, "Skip column %d: can't beat current TPT. Max expected %d current %d\n", next_col_id, max_expected_tpt, tpt); continue; } IWL_DEBUG_RATE(sc, "Found potential column %d. Max expected %d current %d\n", next_col_id, max_expected_tpt, tpt); break; } if (i == MAX_NEXT_COLUMNS) return RS_COLUMN_INVALID; return next_col_id; } static int rs_switch_to_column(struct iwm_softc *sc, struct iwl_lq_sta *lq_sta, struct ieee80211_node *ni, enum rs_column col_id) { struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl]; struct iwl_scale_tbl_info *search_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; struct rs_rate *rate = &search_tbl->rate; const struct rs_tx_column *column = &rs_tx_columns[col_id]; const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column]; unsigned long rate_mask = 0; u32 rate_idx = 0; memcpy(search_tbl, tbl, offsetof(struct iwl_scale_tbl_info, win)); rate->sgi = column->sgi; rate->ant = column->ant; if (column->mode == RS_LEGACY) { if (lq_sta->band == NL80211_BAND_5GHZ) rate->type = LQ_LEGACY_A; else rate->type = LQ_LEGACY_G; rate->bw = RATE_MCS_CHAN_WIDTH_20; rate->ldpc = false; rate_mask = lq_sta->active_legacy_rate; } else if (column->mode == RS_SISO) { rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; rate_mask = lq_sta->active_siso_rate; } else if (column->mode == RS_MIMO2) { rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; rate_mask = lq_sta->active_mimo2_rate; } else { WARN_ON(1, "Bad column mode"); } if (column->mode != RS_LEGACY) { rate->bw = rs_bw_from_sta_bw(ni); rate->ldpc = lq_sta->ldpc; } search_tbl->column = col_id; rs_set_expected_tpt_table(lq_sta, search_tbl); lq_sta->visited_columns |= BIT(col_id); /* Get the best matching rate if we're changing modes. e.g. * SISO->MIMO, LEGACY->SISO, MIMO->SISO */ if (curr_column->mode != column->mode) { rate_idx = rs_get_best_rate(sc, lq_sta, search_tbl, rate_mask, rate->index); if ((rate_idx == IWL_RATE_INVALID) || !(BIT(rate_idx) & rate_mask)) { IWL_DEBUG_RATE(sc, "can not switch with index %d" " rate mask %lx\n", rate_idx, rate_mask); goto err; } rate->index = rate_idx; } IWL_DEBUG_RATE(sc, "Switched to column %d: Index %d\n", col_id, rate->index); return 0; err: rate->type = LQ_NONE; return -1; } static enum rs_action rs_get_rate_action(struct iwm_softc *sc, struct iwl_scale_tbl_info *tbl, s32 sr, int low, int high, int current_tpt, int low_tpt, int high_tpt) { enum rs_action action = RS_ACTION_STAY; if ((sr <= RS_PERCENT(IWL_MVM_RS_SR_FORCE_DECREASE)) || (current_tpt == 0)) { IWL_DEBUG_RATE(mvm, "Decrease rate because of low SR\n"); return RS_ACTION_DOWNSCALE; } if ((low_tpt == IWL_INVALID_VALUE) && (high_tpt == IWL_INVALID_VALUE) && (high != IWL_RATE_INVALID)) { IWL_DEBUG_RATE(mvm, "No data about high/low rates. Increase rate\n"); return RS_ACTION_UPSCALE; } if ((high_tpt == IWL_INVALID_VALUE) && (high != IWL_RATE_INVALID) && (low_tpt != IWL_INVALID_VALUE) && (low_tpt < current_tpt)) { IWL_DEBUG_RATE(mvm, "No data about high rate and low rate is worse. Increase rate\n"); return RS_ACTION_UPSCALE; } if ((high_tpt != IWL_INVALID_VALUE) && (high_tpt > current_tpt)) { IWL_DEBUG_RATE(mvm, "Higher rate is better. Increate rate\n"); return RS_ACTION_UPSCALE; } if ((low_tpt != IWL_INVALID_VALUE) && (high_tpt != IWL_INVALID_VALUE) && (low_tpt < current_tpt) && (high_tpt < current_tpt)) { IWL_DEBUG_RATE(mvm, "Both high and low are worse. Maintain rate\n"); return RS_ACTION_STAY; } if ((low_tpt != IWL_INVALID_VALUE) && (low_tpt > current_tpt)) { IWL_DEBUG_RATE(mvm, "Lower rate is better\n"); action = RS_ACTION_DOWNSCALE; goto out; } if ((low_tpt == IWL_INVALID_VALUE) && (low != IWL_RATE_INVALID)) { IWL_DEBUG_RATE(mvm, "No data about lower rate\n"); action = RS_ACTION_DOWNSCALE; goto out; } IWL_DEBUG_RATE(mvm, "Maintain rate\n"); out: if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID)) { if (sr >= RS_PERCENT(IWL_MVM_RS_SR_NO_DECREASE)) { IWL_DEBUG_RATE(mvm, "SR is above NO DECREASE. Avoid downscale\n"); action = RS_ACTION_STAY; } else if (current_tpt > (100 * tbl->expected_tpt[low])) { IWL_DEBUG_RATE(mvm, "Current TPT is higher than max expected in low rate. Avoid downscale\n"); action = RS_ACTION_STAY; } else { IWL_DEBUG_RATE(mvm, "Decrease rate\n"); } } return action; } static bool rs_stbc_allow(struct iwm_softc *sc, struct ieee80211_node *ni, struct iwl_lq_sta *lq_sta) { /* Our chip supports Tx STBC and the peer is an HT/VHT STA which * supports STBC of at least 1*SS */ if (!lq_sta->stbc_capable) return false; if (!iwl_mvm_bt_coex_is_mimo_allowed(sc, ni)) return false; return true; } static void rs_get_adjacent_txp(struct iwm_softc *mvm, int index, int *weaker, int *stronger) { *weaker = index + IWL_MVM_RS_TPC_TX_POWER_STEP; if (*weaker > TPC_MAX_REDUCTION) *weaker = TPC_INVALID; *stronger = index - IWL_MVM_RS_TPC_TX_POWER_STEP; if (*stronger < 0) *stronger = TPC_INVALID; } static bool iwl_mvm_bt_coex_is_tpc_allowed(struct iwm_softc *mvm, enum nl80211_band band) { return ItlIwm::iwm_coex_is_tpc_allowed(mvm, band == NL80211_BAND_5GHZ); } static bool rs_tpc_allowed(struct iwm_softc *mvm, struct rs_rate *rate, enum nl80211_band band) { int index = rate->index; bool cam = /*(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)*/ false; bool sta_ps_disabled = /*(vif->type == NL80211_IFTYPE_STATION && !vif->bss_conf.ps)*/ true; IWL_DEBUG_RATE(mvm, "cam: %d sta_ps_disabled %d\n", cam, sta_ps_disabled); /* * allow tpc only if power management is enabled, or bt coex * activity grade allows it and we are on 2.4Ghz. */ if ((cam || sta_ps_disabled) && !iwl_mvm_bt_coex_is_tpc_allowed(mvm, band)) return false; IWL_DEBUG_RATE(mvm, "check rate, table type: %d\n", rate->type); if (is_legacy(rate)) return index == IWL_RATE_54M_INDEX; if (is_ht(rate)) return index == IWL_RATE_MCS_7_INDEX; if (is_vht(rate)) return index == IWL_RATE_MCS_9_INDEX; WARN_ON_ONCE(1); return false; } enum tpc_action { TPC_ACTION_STAY, TPC_ACTION_DECREASE, TPC_ACTION_INCREASE, TPC_ACTION_NO_RESTIRCTION, }; static enum tpc_action rs_get_tpc_action(struct iwm_softc *mvm, s32 sr, int weak, int strong, int current_tpt, int weak_tpt, int strong_tpt) { /* stay until we have valid tpt */ if (current_tpt == IWL_INVALID_VALUE) { IWL_DEBUG_RATE(mvm, "no current tpt. stay.\n"); return TPC_ACTION_STAY; } /* Too many failures, increase txp */ if (sr <= RS_PERCENT(IWL_MVM_RS_TPC_SR_FORCE_INCREASE) || current_tpt == 0) { IWL_DEBUG_RATE(mvm, "increase txp because of weak SR\n"); return TPC_ACTION_NO_RESTIRCTION; } /* try decreasing first if applicable */ if (sr >= RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) && weak != TPC_INVALID) { if (weak_tpt == IWL_INVALID_VALUE && (strong_tpt == IWL_INVALID_VALUE || current_tpt >= strong_tpt)) { IWL_DEBUG_RATE(mvm, "no weak txp measurement. decrease txp\n"); return TPC_ACTION_DECREASE; } if (weak_tpt > current_tpt) { IWL_DEBUG_RATE(mvm, "lower txp has better tpt. decrease txp\n"); return TPC_ACTION_DECREASE; } } /* next, increase if needed */ if (sr < RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) && strong != TPC_INVALID) { if (weak_tpt == IWL_INVALID_VALUE && strong_tpt != IWL_INVALID_VALUE && current_tpt < strong_tpt) { IWL_DEBUG_RATE(mvm, "higher txp has better tpt. increase txp\n"); return TPC_ACTION_INCREASE; } if (weak_tpt < current_tpt && (strong_tpt == IWL_INVALID_VALUE || strong_tpt > current_tpt)) { IWL_DEBUG_RATE(mvm, "lower txp has worse tpt. increase txp\n"); return TPC_ACTION_INCREASE; } } IWL_DEBUG_RATE(mvm, "no need to increase or decrease txp - stay\n"); return TPC_ACTION_STAY; } static bool rs_tpc_perform(struct iwm_softc *mvm, struct ieee80211_node *ni, struct iwl_lq_sta *lq_sta, struct iwl_scale_tbl_info *tbl) { enum nl80211_band band; struct iwl_rate_scale_data *window; struct rs_rate *rate = &tbl->rate; enum tpc_action action; s32 sr; u8 cur = lq_sta->lq.reduced_tpc; int current_tpt; int weak, strong; int weak_tpt = IWL_INVALID_VALUE, strong_tpt = IWL_INVALID_VALUE; if (WARN_ON(!ni->ni_chan)) band = NUM_NL80211_BANDS; else band = IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; if (!rs_tpc_allowed(mvm, rate, band)) { IWL_DEBUG_RATE(mvm, "tpc is not allowed. remove txp restrictions\n"); lq_sta->lq.reduced_tpc = TPC_NO_REDUCTION; return cur != TPC_NO_REDUCTION; } rs_get_adjacent_txp(mvm, cur, &weak, &strong); /* Collect measured throughputs for current and adjacent rates */ window = tbl->tpc_win; sr = window[cur].success_ratio; current_tpt = window[cur].average_tpt; if (weak != TPC_INVALID) weak_tpt = window[weak].average_tpt; if (strong != TPC_INVALID) strong_tpt = window[strong].average_tpt; IWL_DEBUG_RATE(mvm, "(TPC: %d): cur_tpt %d SR %d weak %d strong %d weak_tpt %d strong_tpt %d\n", cur, current_tpt, sr, weak, strong, weak_tpt, strong_tpt); action = rs_get_tpc_action(mvm, sr, weak, strong, current_tpt, weak_tpt, strong_tpt); /* override actions if we are on the edge */ if (weak == TPC_INVALID && action == TPC_ACTION_DECREASE) { IWL_DEBUG_RATE(mvm, "already in lowest txp, stay\n"); action = TPC_ACTION_STAY; } else if (strong == TPC_INVALID && (action == TPC_ACTION_INCREASE || action == TPC_ACTION_NO_RESTIRCTION)) { IWL_DEBUG_RATE(mvm, "already in highest txp, stay\n"); action = TPC_ACTION_STAY; } switch (action) { case TPC_ACTION_DECREASE: lq_sta->lq.reduced_tpc = weak; return true; case TPC_ACTION_INCREASE: lq_sta->lq.reduced_tpc = strong; return true; case TPC_ACTION_NO_RESTIRCTION: lq_sta->lq.reduced_tpc = TPC_NO_REDUCTION; return true; case TPC_ACTION_STAY: /* do nothing */ break; } return false; } /* * Do rate scaling and search for new modulation mode. */ static void rs_rate_scale_perform(struct iwm_softc *mvm, struct ieee80211_node *ni, struct iwl_lq_sta *lq_sta, int tid, bool ndp) { int low = IWL_RATE_INVALID; int high = IWL_RATE_INVALID; int index; struct iwl_rate_scale_data *window = NULL; int current_tpt = IWL_INVALID_VALUE; int low_tpt = IWL_INVALID_VALUE; int high_tpt = IWL_INVALID_VALUE; u32 fail_count; enum rs_action scale_action = RS_ACTION_STAY; u16 rate_mask; u8 update_lq = 0; struct iwl_scale_tbl_info *tbl, *tbl1; u8 active_tbl = 0; u8 done_search = 0; u16 high_low; s32 sr; u8 prev_agg = lq_sta->is_agg; struct rs_rate *rate; int i; lq_sta->is_agg = false; for (i = 0; i <= IWM_MAX_TID_COUNT; i++) { if (mvm->sc_tx_ba[i].wn != NULL) { lq_sta->is_agg = true; break; } } /* * Select rate-scale / modulation-mode table to work with in * the rest of this function: "search" if searching for better * modulation mode, or "active" if doing rate scaling within a mode. */ if (!lq_sta->search_better_tbl) active_tbl = lq_sta->active_tbl; else active_tbl = rs_search_tbl(lq_sta->active_tbl); tbl = &(lq_sta->lq_info[active_tbl]); rate = &tbl->rate; if (prev_agg != lq_sta->is_agg) { XYLog("Aggregation changed: prev %d current %d. Update expected TPT table\n", prev_agg, lq_sta->is_agg); rs_set_expected_tpt_table(lq_sta, tbl); rs_rate_scale_clear_tbl_windows(mvm, tbl); } /* current tx rate */ index = rate->index; /* rates available for this association, and for modulation mode */ rate_mask = rs_get_supported_rates(lq_sta, rate); if (!(BIT(index) & rate_mask)) { IWL_ERR(mvm, "Current Rate is not valid\n"); if (lq_sta->search_better_tbl) { /* revert to active table if search table is not valid*/ rate->type = LQ_NONE; lq_sta->search_better_tbl = 0; tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); rs_update_rate_tbl(mvm, ni, lq_sta, tbl); } return; } /* Get expected throughput table and history window for current rate */ if (!tbl->expected_tpt) { IWL_ERR(mvm, "tbl->expected_tpt is NULL\n"); return; } /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ window = &(tbl->win[index]); /* * If there is not enough history to calculate actual average * throughput, keep analyzing results of more tx frames, without * changing rate or mode (bypass most of the rest of this function). * Set up new rate table in uCode only if old rate is not supported * in current association (use new rate found above). */ fail_count = window->counter - window->success_counter; if ((fail_count < IWL_MVM_RS_RATE_MIN_FAILURE_TH) && (window->success_counter < IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) { IWL_DEBUG_RATE(mvm, "%s: Test Window: succ %d total %d\n", rs_pretty_rate(rate), window->success_counter, window->counter); /* Can't calculate this yet; not enough history */ window->average_tpt = IWL_INVALID_VALUE; /* Should we stay with this modulation mode, * or search for a new one? */ rs_stay_in_table(lq_sta, false); return; } /* If we are searching for better modulation mode, check success. */ if (lq_sta->search_better_tbl) { /* If good success, continue using the "search" mode; * no need to send new link quality command, since we're * continuing to use the setup that we've been trying. */ if (window->average_tpt > lq_sta->last_tpt) { IWL_DEBUG_RATE(mvm, "SWITCHING TO NEW TABLE SR: %d " "cur-tpt %d old-tpt %d\n", window->success_ratio, window->average_tpt, lq_sta->last_tpt); /* Swap tables; "search" becomes "active" */ lq_sta->active_tbl = active_tbl; current_tpt = window->average_tpt; /* Else poor success; go back to mode in "active" table */ } else { IWL_DEBUG_RATE(mvm, "GOING BACK TO THE OLD TABLE: SR %d " "cur-tpt %d old-tpt %d\n", window->success_ratio, window->average_tpt, lq_sta->last_tpt); /* Nullify "search" table */ rate->type = LQ_NONE; /* Revert to "active" table */ active_tbl = lq_sta->active_tbl; tbl = &(lq_sta->lq_info[active_tbl]); /* Revert to "active" rate and throughput info */ index = tbl->rate.index; current_tpt = lq_sta->last_tpt; /* Need to set up a new rate table in uCode */ update_lq = 1; } /* Either way, we've made a decision; modulation mode * search is done, allow rate adjustment next time. */ lq_sta->search_better_tbl = 0; done_search = 1; /* Don't switch modes below! */ goto lq_update; } /* (Else) not in search of better modulation mode, try for better * starting rate, while staying in this mode. */ high_low = rs_get_adjacent_rate(mvm, index, rate_mask, rate->type); low = high_low & 0xff; high = (high_low >> 8) & 0xff; /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ sr = window->success_ratio; /* Collect measured throughputs for current and adjacent rates */ current_tpt = window->average_tpt; if (low != IWL_RATE_INVALID) low_tpt = tbl->win[low].average_tpt; if (high != IWL_RATE_INVALID) high_tpt = tbl->win[high].average_tpt; IWL_DEBUG_RATE(mvm, "%s: cur_tpt %d SR %d low %d high %d low_tpt %d high_tpt %d\n", rs_pretty_rate(rate), current_tpt, sr, low, high, low_tpt, high_tpt); scale_action = rs_get_rate_action(mvm, tbl, sr, low, high, current_tpt, low_tpt, high_tpt); /* Force a search in case BT doesn't like us being in MIMO */ if (is_mimo(rate) && !iwl_mvm_bt_coex_is_mimo_allowed(mvm, ni)) { IWL_DEBUG_RATE(mvm, "BT Coex forbids MIMO. Search for new config\n"); rs_stay_in_table(lq_sta, true); goto lq_update; } switch (scale_action) { case RS_ACTION_DOWNSCALE: /* Decrease starting rate, update uCode's rate table */ if (low != IWL_RATE_INVALID) { update_lq = 1; index = low; } else { IWL_DEBUG_RATE(mvm, "At the bottom rate. Can't decrease\n"); } break; case RS_ACTION_UPSCALE: /* Increase starting rate, update uCode's rate table */ if (high != IWL_RATE_INVALID) { update_lq = 1; index = high; } else { IWL_DEBUG_RATE(mvm, "At the top rate. Can't increase\n"); } break; case RS_ACTION_STAY: /* No change */ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) update_lq = rs_tpc_perform(mvm, ni, lq_sta, tbl); break; default: break; } lq_update: /* Replace uCode's rate table for the destination station. */ if (update_lq) { tbl->rate.index = index; if (IWL_MVM_RS_80_20_FAR_RANGE_TWEAK) rs_tweak_rate_tbl(mvm, ni, lq_sta, tbl, scale_action); rs_set_amsdu_len(mvm, ni, tbl, scale_action); rs_update_rate_tbl(mvm, ni, lq_sta, tbl); } rs_stay_in_table(lq_sta, false); /* * Search for new modulation mode if we're: * 1) Not changing rates right now * 2) Not just finishing up a search * 3) Allowing a new search */ if (!update_lq && !done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED && window->counter) { enum rs_column next_column; /* Save current throughput to compare with "search" throughput*/ lq_sta->last_tpt = current_tpt; IWL_DEBUG_RATE(mvm, "Start Search: update_lq %d done_search %d rs_state %d win->counter %d\n", update_lq, done_search, lq_sta->rs_state, window->counter); next_column = rs_get_next_column(mvm, lq_sta, ni, tbl); if (next_column != RS_COLUMN_INVALID) { int ret = rs_switch_to_column(mvm, lq_sta, ni, next_column); if (!ret) lq_sta->search_better_tbl = 1; } else { IWL_DEBUG_RATE(mvm, "No more columns to explore in search cycle. Go to RS_STATE_SEARCH_CYCLE_ENDED\n"); lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_ENDED; } /* If new "search" mode was selected, set up in uCode table */ if (lq_sta->search_better_tbl) { /* Access the "search" table, clear its history. */ tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; rs_rate_scale_clear_tbl_windows(mvm, tbl); /* Use new "search" start rate */ index = tbl->rate.index; rs_dump_rate(mvm, &tbl->rate, "Switch to SEARCH TABLE:"); rs_update_rate_tbl(mvm, ni, lq_sta, tbl); } else { done_search = 1; } } if (!ndp) rs_tl_turn_on_agg(mvm, tid, lq_sta, ni); if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) { tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); rs_set_stay_in_table(mvm, is_legacy(&tbl1->rate), lq_sta); } } struct rs_init_rate_info { s8 rssi; u8 rate_idx; }; static const struct rs_init_rate_info rs_optimal_rates_24ghz_legacy[] = { { -60, IWL_RATE_54M_INDEX }, { -64, IWL_RATE_48M_INDEX }, { -68, IWL_RATE_36M_INDEX }, { -80, IWL_RATE_24M_INDEX }, { -84, IWL_RATE_18M_INDEX }, { -85, IWL_RATE_12M_INDEX }, { -86, IWL_RATE_11M_INDEX }, { -88, IWL_RATE_5M_INDEX }, { -90, IWL_RATE_2M_INDEX }, { S8_MIN, IWL_RATE_1M_INDEX }, }; static const struct rs_init_rate_info rs_optimal_rates_5ghz_legacy[] = { { -60, IWL_RATE_54M_INDEX }, { -64, IWL_RATE_48M_INDEX }, { -72, IWL_RATE_36M_INDEX }, { -80, IWL_RATE_24M_INDEX }, { -84, IWL_RATE_18M_INDEX }, { -85, IWL_RATE_12M_INDEX }, { -87, IWL_RATE_9M_INDEX }, { S8_MIN, IWL_RATE_6M_INDEX }, }; static const struct rs_init_rate_info rs_optimal_rates_ht[] = { { -60, IWL_RATE_MCS_7_INDEX }, { -64, IWL_RATE_MCS_6_INDEX }, { -68, IWL_RATE_MCS_5_INDEX }, { -72, IWL_RATE_MCS_4_INDEX }, { -80, IWL_RATE_MCS_3_INDEX }, { -84, IWL_RATE_MCS_2_INDEX }, { -85, IWL_RATE_MCS_1_INDEX }, { S8_MIN, IWL_RATE_MCS_0_INDEX}, }; /* MCS index 9 is not valid for 20MHz VHT channel width, * but is ok for 40, 80 and 160MHz channels. */ static const struct rs_init_rate_info rs_optimal_rates_vht_20mhz[] = { { -60, IWL_RATE_MCS_8_INDEX }, { -64, IWL_RATE_MCS_7_INDEX }, { -68, IWL_RATE_MCS_6_INDEX }, { -72, IWL_RATE_MCS_5_INDEX }, { -80, IWL_RATE_MCS_4_INDEX }, { -84, IWL_RATE_MCS_3_INDEX }, { -85, IWL_RATE_MCS_2_INDEX }, { -87, IWL_RATE_MCS_1_INDEX }, { S8_MIN, IWL_RATE_MCS_0_INDEX}, }; static const struct rs_init_rate_info rs_optimal_rates_vht[] = { { -60, IWL_RATE_MCS_9_INDEX }, { -64, IWL_RATE_MCS_8_INDEX }, { -68, IWL_RATE_MCS_7_INDEX }, { -72, IWL_RATE_MCS_6_INDEX }, { -80, IWL_RATE_MCS_5_INDEX }, { -84, IWL_RATE_MCS_4_INDEX }, { -85, IWL_RATE_MCS_3_INDEX }, { -87, IWL_RATE_MCS_2_INDEX }, { -88, IWL_RATE_MCS_1_INDEX }, { S8_MIN, IWL_RATE_MCS_0_INDEX }, }; #define IWL_RS_LOW_RSSI_THRESHOLD (-76) /* dBm */ /* Init the optimal rate based on STA caps * This combined with rssi is used to report the last tx rate * to userspace when we haven't transmitted enough frames. */ static void rs_init_optimal_rate(struct iwm_softc *mvm, struct ieee80211_node *sta, struct iwl_lq_sta *lq_sta) { struct rs_rate *rate = &lq_sta->optimal_rate; if (lq_sta->max_mimo2_rate_idx != IWL_RATE_INVALID) rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; else if (lq_sta->max_siso_rate_idx != IWL_RATE_INVALID) rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; else if (lq_sta->band == NL80211_BAND_5GHZ) rate->type = LQ_LEGACY_A; else rate->type = LQ_LEGACY_G; rate->bw = rs_bw_from_sta_bw(sta); rate->sgi = rs_sgi_allow(mvm, sta, rate, NULL); /* ANT/LDPC/STBC aren't relevant for the rate reported to userspace */ if (is_mimo(rate)) { lq_sta->optimal_rate_mask = lq_sta->active_mimo2_rate; } else if (is_siso(rate)) { lq_sta->optimal_rate_mask = lq_sta->active_siso_rate; } else { lq_sta->optimal_rate_mask = lq_sta->active_legacy_rate; if (lq_sta->band == NL80211_BAND_5GHZ) { lq_sta->optimal_rates = rs_optimal_rates_5ghz_legacy; lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_5ghz_legacy); } else { lq_sta->optimal_rates = rs_optimal_rates_24ghz_legacy; lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); } } if (is_vht(rate)) { if (rate->bw == RATE_MCS_CHAN_WIDTH_20) { lq_sta->optimal_rates = rs_optimal_rates_vht_20mhz; lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz); } else { lq_sta->optimal_rates = rs_optimal_rates_vht; lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_vht); } } else if (is_ht(rate)) { lq_sta->optimal_rates = rs_optimal_rates_ht; lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_ht); } } /* Compute the optimal rate index based on RSSI */ static struct rs_rate *rs_get_optimal_rate(struct iwm_softc *mvm, struct iwl_lq_sta *lq_sta) { struct rs_rate *rate = &lq_sta->optimal_rate; int i; rate->index = find_first_bit(&lq_sta->optimal_rate_mask, BITS_PER_LONG); for (i = 0; i < lq_sta->optimal_nentries; i++) { int rate_idx = lq_sta->optimal_rates[i].rate_idx; if ((lq_sta->pers.last_rssi >= lq_sta->optimal_rates[i].rssi) && (BIT(rate_idx) & lq_sta->optimal_rate_mask)) { rate->index = rate_idx; break; } } return rate; } /* Choose an initial legacy rate and antenna to use based on the RSSI * of last Rx */ static void rs_get_initial_rate(struct iwm_softc *mvm, struct ieee80211_node *sta, struct iwl_lq_sta *lq_sta, enum nl80211_band band, struct rs_rate *rate) { int i, nentries; unsigned long active_rate; s8 best_rssi = S8_MIN; u8 best_ant = ANT_NONE; ItlIwm *that = container_of(mvm, ItlIwm, com); u8 valid_tx_ant = that->iwm_fw_valid_tx_ant(mvm); const struct rs_init_rate_info *initial_rates; for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) { if (!(lq_sta->pers.chains & BIT(i))) continue; if (lq_sta->pers.chain_signal[i] > best_rssi) { best_rssi = lq_sta->pers.chain_signal[i]; best_ant = BIT(i); } } IWL_DEBUG_RATE(mvm, "Best ANT: %s Best RSSI: %d\n", rs_pretty_ant(best_ant), best_rssi); if (best_ant != ANT_A && best_ant != ANT_B) rate->ant = first_antenna(valid_tx_ant); else rate->ant = best_ant; rate->sgi = false; rate->ldpc = false; rate->bw = RATE_MCS_CHAN_WIDTH_20; rate->index = find_first_bit(&lq_sta->active_legacy_rate, BITS_PER_LONG); if (band == NL80211_BAND_5GHZ) { rate->type = LQ_LEGACY_A; initial_rates = rs_optimal_rates_5ghz_legacy; nentries = ARRAY_SIZE(rs_optimal_rates_5ghz_legacy); } else { rate->type = LQ_LEGACY_G; initial_rates = rs_optimal_rates_24ghz_legacy; nentries = ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); } if (!IWL_MVM_RS_RSSI_BASED_INIT_RATE) goto out; /* Start from a higher rate if the corresponding debug capability * is enabled. The rate is chosen according to AP capabilities. * In case of VHT/HT when the rssi is low fallback to the case of * legacy rates. */ if (ieee80211_node_supports_vht(sta) && best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { /* * In AP mode, when a new station associates, rs is initialized * immediately upon association completion, before the phy * context is updated with the association parameters, so the * sta bandwidth might be wider than the phy context allows. * To avoid this issue, always initialize rs with 20mhz * bandwidth rate, and after authorization, when the phy context * is already up-to-date, re-init rs with the correct bw. */ u32 bw = mvm->sc_ic.ic_state < IEEE80211_S_RUN ? RATE_MCS_CHAN_WIDTH_20 : rs_bw_from_sta_bw(sta); switch (bw) { case RATE_MCS_CHAN_WIDTH_40: case RATE_MCS_CHAN_WIDTH_80: case RATE_MCS_CHAN_WIDTH_160: initial_rates = rs_optimal_rates_vht; nentries = ARRAY_SIZE(rs_optimal_rates_vht); break; case RATE_MCS_CHAN_WIDTH_20: initial_rates = rs_optimal_rates_vht_20mhz; nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz); break; default: IWL_ERR(mvm, "Invalid BW %d\n", sta->ni_chw); goto out; } active_rate = lq_sta->active_siso_rate; rate->type = LQ_VHT_SISO; rate->bw = bw; } else if (ieee80211_node_supports_ht(sta) && best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) { initial_rates = rs_optimal_rates_ht; nentries = ARRAY_SIZE(rs_optimal_rates_ht); active_rate = lq_sta->active_siso_rate; rate->type = LQ_HT_SISO; } else { active_rate = lq_sta->active_legacy_rate; } for (i = 0; i < nentries; i++) { int rate_idx = initial_rates[i].rate_idx; if ((best_rssi >= initial_rates[i].rssi) && (BIT(rate_idx) & active_rate)) { rate->index = rate_idx; break; } } out: rs_dump_rate(mvm, rate, "INITIAL"); } /* Save info about RSSI of last Rx */ void rs_update_last_rssi(struct iwm_softc *mvm, struct ieee80211_rx_status *rx_status) { struct iwl_lq_sta *lq_sta = &mvm->lq_sta.rs_drv; int i; lq_sta->pers.chains = rx_status->chains; lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0]; lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1]; lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2]; lq_sta->pers.last_rssi = S8_MIN; for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) { if (!(lq_sta->pers.chains & BIT(i))) continue; if (lq_sta->pers.chain_signal[i] > lq_sta->pers.last_rssi) lq_sta->pers.last_rssi = lq_sta->pers.chain_signal[i]; } } /* * rs_initialize_lq - Initialize a station's hardware rate table * * The uCode's station table contains a table of fallback rates * for automatic fallback during transmission. * * NOTE: This sets up a default set of values. These will be replaced later * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of * rc80211_simple. * * NOTE: Run REPLY_ADD_STA command to set up station table entry, before * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, * which requires station table entry to exist). */ static void rs_initialize_lq(struct iwm_softc *mvm, struct ieee80211_node *sta, struct iwl_lq_sta *lq_sta, enum nl80211_band band) { struct iwl_scale_tbl_info *tbl; struct rs_rate *rate; u8 active_tbl = 0; if (!sta || !lq_sta) return; if (!lq_sta->search_better_tbl) active_tbl = lq_sta->active_tbl; else active_tbl = rs_search_tbl(lq_sta->active_tbl); tbl = &(lq_sta->lq_info[active_tbl]); rate = &tbl->rate; rs_get_initial_rate(mvm, sta, lq_sta, band, rate); rs_init_optimal_rate(mvm, sta, lq_sta); WARN_ON(rate->ant != ANT_A && rate->ant != ANT_B, "ant: 0x%x, chains 0x%x, fw tx ant: 0x%x, nvm tx ant: 0x%x\n", rate->ant, lq_sta->pers.chains, mvm->fw->valid_tx_ant, mvm->nvm_data ? mvm->nvm_data->valid_tx_ant : ANT_INVALID); tbl->column = rs_get_column_from_rate(rate); rs_set_expected_tpt_table(lq_sta, tbl); rs_fill_lq_cmd(mvm, sta, lq_sta, rate); /* TODO restore station should remember the lq cmd */ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); } static void rs_drv_get_rate(struct iwm_softc *mvm, struct ieee80211_node *sta, struct ieee80211_tx_rate *r) { struct iwl_lq_sta *lq_sta; struct rs_rate *optimal_rate; u32 last_ucode_rate; if (!sta) return; lq_sta = &mvm->lq_sta.rs_drv; IOSimpleLockLock(mvm->lq_sta.rs_drv.pers.lock); iwl_mvm_hwrate_to_tx_rate(lq_sta->last_rate_n_flags, IEEE80211_IS_CHAN_2GHZ(sta->ni_chan) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ, r); /* Report the optimal rate based on rssi and STA caps if we haven't * converged yet (too little traffic) or exploring other modulations */ if (lq_sta->rs_state != RS_STATE_STAY_IN_COLUMN) { optimal_rate = rs_get_optimal_rate(mvm, lq_sta); last_ucode_rate = ucode_rate_from_rs_rate(mvm, optimal_rate); iwl_mvm_hwrate_to_tx_rate(last_ucode_rate, IEEE80211_IS_CHAN_2GHZ(sta->ni_chan) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ, r); } IOSimpleLockUnlock(mvm->lq_sta.rs_drv.pers.lock); } void *rs_drv_alloc_sta(iwm_softc *sc, struct ieee80211_node *ni) { struct iwl_lq_sta *lq_sta = &sc->lq_sta.rs_drv; IWL_DEBUG_RATE(mvm, "create station rate scale window\n"); lq_sta->pers.drv = sc; lq_sta->pers.chains = 0; memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal)); lq_sta->pers.last_rssi = S8_MIN; return lq_sta; } void rs_drv_free_sta(iwm_softc *sc, struct ieee80211_node *ni) {} static int rs_vht_highest_rx_mcs_index(struct ieee80211_node *sta, int nss) { u16 rx_mcs = le16_to_cpu(sta->ni_vht_mcsinfo.rx_mcs_map) & (0x3 << (2 * (nss - 1))); rx_mcs >>= (2 * (nss - 1)); if (rx_mcs == IEEE80211_VHT_MCS_SUPPORT_0_7) return IWL_RATE_MCS_7_INDEX; else if (rx_mcs == IEEE80211_VHT_MCS_SUPPORT_0_8) return IWL_RATE_MCS_8_INDEX; else if (rx_mcs == IEEE80211_VHT_MCS_SUPPORT_0_9) return IWL_RATE_MCS_9_INDEX; WARN_ON_ONCE(rx_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED); return -1; } static void rs_vht_set_enabled_rates(struct ieee80211_node *sta, struct iwl_lq_sta *lq_sta) { int i; int highest_mcs = rs_vht_highest_rx_mcs_index(sta, 1); if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { if (i == IWL_RATE_9M_INDEX) continue; /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */ if (i == IWL_RATE_MCS_9_INDEX && sta->ni_chw == IEEE80211_CHAN_WIDTH_20) continue; lq_sta->active_siso_rate |= BIT(i); } } if (sta->ni_rx_nss < 2) return; highest_mcs = rs_vht_highest_rx_mcs_index(sta, 2); if (highest_mcs >= IWL_RATE_MCS_0_INDEX) { for (i = IWL_RATE_MCS_0_INDEX; i <= highest_mcs; i++) { if (i == IWL_RATE_9M_INDEX) continue; /* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */ if (i == IWL_RATE_MCS_9_INDEX && sta->ni_chw == IEEE80211_CHAN_WIDTH_20) continue; lq_sta->active_mimo2_rate |= BIT(i); } } } static void rs_ht_init(struct iwm_softc *mvm, struct ieee80211_node *sta, struct iwl_lq_sta *lq_sta) { ItlIwm *that = container_of(mvm, ItlIwm, com); /* active_siso_rate mask includes 9 MBits (bit 5), * and CCK (bits 0-3), supp_rates[] does not; * shift to convert format, force 9 MBits off. */ lq_sta->active_siso_rate = sta->ni_rxmcs[0] << 1; lq_sta->active_siso_rate |= sta->ni_rxmcs[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; lq_sta->active_mimo2_rate = sta->ni_rxmcs[1] << 1; lq_sta->active_mimo2_rate |= sta->ni_rxmcs[1] & 0x1; lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; if ((sta->ni_htcaps & IEEE80211_HTCAP_LDPC) && mvm->support_ldpc) lq_sta->ldpc = true; if ((that->iwm_num_of_ant(that->iwm_fw_valid_tx_ant(mvm)) > 1) && (sta->ni_htcaps & IEEE80211_HTCAP_RXSTBC_MASK)) lq_sta->stbc_capable = true; lq_sta->is_vht = false; } static void rs_vht_init(struct iwm_softc *mvm, struct ieee80211_node *sta, struct iwl_lq_sta *lq_sta) { ItlIwm *that = container_of(mvm, ItlIwm, com); rs_vht_set_enabled_rates(sta, lq_sta); if ((sta->ni_vhtcaps & IEEE80211_VHTCAP_RXLDPC) && mvm->support_ldpc) lq_sta->ldpc = true; if ((that->iwm_num_of_ant(that->iwm_fw_valid_tx_ant(mvm)) > 1) && (sta->ni_vhtcaps & IEEE80211_VHTCAP_RXSTBC_MASK)) lq_sta->stbc_capable = true; #if 0 if (isset(mvm->sc_enabled_capa, IWM_UCODE_TLV_CAPA_BEAMFORMER) && (that->iwm_num_of_ant(that->iwm_fw_valid_tx_ant(mvm)) > 1) && (sta->ni_vhtcaps & IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE)) lq_sta->bfer_capable = true; #endif lq_sta->is_vht = true; } static u8 iwl_mvm_bt_coex_get_single_ant_msk(struct iwm_softc *mvm, u8 enabled_ants) { if (isset(&mvm->sc_enabled_capa, IWM_UCODE_TLV_CAPA_COEX_SCHEMA_2) && (mvm->non_shared_ant & enabled_ants)) return mvm->non_shared_ant; return first_antenna(enabled_ants); } /** * struct ieee80211_rate - bitrate definition * * This structure describes a bitrate that an 802.11 PHY can * operate with. The two values @hw_value and @hw_value_short * are only for driver use when pointers to this structure are * passed around. * * @flags: rate-specific flags * @bitrate: bitrate in units of 100 Kbps * @hw_value: driver/hardware value for this rate * @hw_value_short: driver/hardware value for this rate when * short preamble is used */ struct ieee80211_rate { u32 flags; u16 bitrate; u16 hw_value, hw_value_short; }; /** * enum ieee80211_rate_flags - rate flags * * Hardware/specification flags for rates. These are structured * in a way that allows using the same bitrate structure for * different bands/PHY modes. * * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short * preamble on this bitrate; only relevant in 2.4GHz band and * with CCK rates. * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate * when used with 802.11a (on the 5 GHz band); filled by the * core code when registering the wiphy. * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate * when used with 802.11b (on the 2.4 GHz band); filled by the * core code when registering the wiphy. * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate * when used with 802.11g (on the 2.4 GHz band); filled by the * core code when registering the wiphy. * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode. * @IEEE80211_RATE_SUPPORTS_5MHZ: Rate can be used in 5 MHz mode * @IEEE80211_RATE_SUPPORTS_10MHZ: Rate can be used in 10 MHz mode */ enum ieee80211_rate_flags { IEEE80211_RATE_SHORT_PREAMBLE = 1<<0, IEEE80211_RATE_MANDATORY_A = 1<<1, IEEE80211_RATE_MANDATORY_B = 1<<2, IEEE80211_RATE_MANDATORY_G = 1<<3, IEEE80211_RATE_ERP_G = 1<<4, IEEE80211_RATE_SUPPORTS_5MHZ = 1<<5, IEEE80211_RATE_SUPPORTS_10MHZ = 1<<6, }; /* * Called after adding a new station to initialize rate scaling */ static void rs_drv_rate_init(struct iwm_softc *mvm, struct ieee80211_node *sta, enum nl80211_band band) { int i, j; struct iwl_lq_sta *lq_sta = &mvm->lq_sta.rs_drv; ItlIwm *that = container_of(mvm, ItlIwm, com); uint8_t rate; // lockdep_assert_held(&mvmsta->lq_sta.rs_drv.pers.lock); /* clear all non-persistent lq data */ memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers)); lq_sta->lq.sta_id = IWM_STATION_ID; #if 0 mvm->amsdu_enabled = 0; mvm->max_amsdu_len = sta->max_amsdu_len; #endif for (j = 0; j < LQ_SIZE; j++) rs_rate_scale_clear_tbl_windows(mvm, &lq_sta->lq_info[j]); lq_sta->flush_timer = 0; lq_sta->last_tx = ticks; IWL_DEBUG_RATE(mvm, "LQ: *** rate scale station global init for station %d ***\n", IWM_STATION_ID); /* TODO: what is a good starting rate for STA? About middle? Maybe not * the lowest or the highest rate.. Could consider using RSSI from * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ lq_sta->missed_rate_counter = IWL_MVM_RS_MISSED_RATE_MAX; lq_sta->band = band; /* * active legacy rates as per supported rates bitmap */ lq_sta->active_legacy_rate = 0; for (i = 0; i < ieee80211_std_rateset_11g.rs_nrates; i++) { for (j = 0; j < sta->ni_rates.rs_nrates; j++) { if (ieee80211_std_rateset_11g.rs_rates[i] == (sta->ni_rates.rs_rates[j] & IEEE80211_RATE_VAL)) { lq_sta->active_legacy_rate |= BIT(i); break; } } } /* TODO: should probably account for rx_highest for both HT/VHT */ if ((sta->ni_flags & IEEE80211_NODE_VHT) == 0) rs_ht_init(mvm, sta, lq_sta); else rs_vht_init(mvm, sta, lq_sta); lq_sta->max_legacy_rate_idx = rs_get_max_rate_from_mask(lq_sta->active_legacy_rate); lq_sta->max_siso_rate_idx = rs_get_max_rate_from_mask(lq_sta->active_siso_rate); lq_sta->max_mimo2_rate_idx = rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate); XYLog("LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d BFER=%d\n", lq_sta->active_legacy_rate, lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc_capable, lq_sta->bfer_capable); XYLog("MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", lq_sta->max_legacy_rate_idx, lq_sta->max_siso_rate_idx, lq_sta->max_mimo2_rate_idx); /* These values will be overridden later */ lq_sta->lq.single_stream_ant_msk = iwl_mvm_bt_coex_get_single_ant_msk(mvm, that->iwm_fw_valid_tx_ant(mvm)); lq_sta->lq.dual_stream_ant_msk = ANT_AB; /* as default allow aggregation for all tids */ lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->is_agg = 0; rs_initialize_lq(mvm, sta, lq_sta, band); } void rs_drv_rate_update(struct iwm_softc *mvm, struct ieee80211_node *sta, enum nl80211_band band, u32 changed) { /* Stop any ongoing aggregations as rs starts off assuming no agg */ ieee80211_stop_ampdu_tx(&mvm->sc_ic, sta, 0); iwl_mvm_rs_rate_init(mvm, sta, band, true); } static void __iwl_mvm_rs_tx_status(struct iwm_softc *mvm, struct ieee80211_node *sta, int tid, struct ieee80211_tx_info *info, bool ndp) { int legacy_success; int retries; int i; struct iwm_lq_cmd *table; u32 lq_hwrate; uint32_t last_rate; struct rs_rate lq_rate, tx_resp_rate; struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; u32 tlc_info = (u32)(uintptr_t)info->status.status_driver_data[0]; u8 reduced_txp = tlc_info & RS_DRV_DATA_TXP_MSK; u8 lq_color = RS_DRV_DATA_LQ_COLOR_GET(tlc_info); u32 tx_resp_hwrate = (u32)(uintptr_t)info->status.status_driver_data[1]; struct iwl_lq_sta *lq_sta = &mvm->lq_sta.rs_drv; char pretty_rate[100]; if (!lq_sta->pers.drv) { IWL_DEBUG_RATE(mvm, "Rate scaling not initialized yet.\n"); return; } /* This packet was aggregated but doesn't carry status info */ if ((info->flags & IEEE80211_TX_CTL_AMPDU) && !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; if (rs_rate_from_ucode_rate(tx_resp_hwrate, (enum nl80211_band)info->band, &tx_resp_rate)) { WARN_ON_ONCE(1); return; } if (time_after(ticks, (unsigned long)(lq_sta->last_tx + (IWL_MVM_RS_IDLE_TIMEOUT * hz)))) { IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); /* reach here only in case of driver RS, call directly * the unlocked version */ rs_drv_rate_init(mvm, sta, (nl80211_band)info->band); return; } lq_sta->last_tx = ticks; /* Ignore this Tx frame response if its initial rate doesn't match * that of latest Link Quality command. There may be stragglers * from a previous Link Quality command, but we're no longer interested * in those; they're either from the "active" mode while we're trying * to check "search" mode, or a prior "search" mode after we've moved * to a new "search" mode (which might become the new "active" mode). */ table = &lq_sta->lq; lq_hwrate = le32_to_cpu(table->rs_table[0]); if (rs_rate_from_ucode_rate(lq_hwrate, (enum nl80211_band)info->band, &lq_rate)) { WARN_ON_ONCE(1); return; } /* Here we actually compare this rate to the latest LQ command */ if (lq_color != LQ_FLAG_COLOR_GET(table->flags)) { IWL_DEBUG_RATE(mvm, "tx resp color 0x%x does not match 0x%x\n", lq_color, LQ_FLAG_COLOR_GET(table->flags)); /* Since rates mis-match, the last LQ command may have failed. * After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with * ... driver. */ lq_sta->missed_rate_counter++; if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) { lq_sta->missed_rate_counter = 0; IWL_DEBUG_RATE(mvm, "Too many rates mismatch. Send sync LQ. rs_state %d\n", lq_sta->rs_state); iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq); } /* Regardless, ignore this status info for outdated rate */ return; } /* Rate did match, so reset the missed_rate_counter */ lq_sta->missed_rate_counter = 0; if (!lq_sta->search_better_tbl) { curr_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; other_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; } else { curr_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; other_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; } if (WARN_ON_ONCE(!rs_rate_column_match(&lq_rate, &curr_tbl->rate))) { IWL_DEBUG_RATE(mvm, "Neither active nor search matches tx rate\n"); tmp_tbl = &lq_sta->lq_info[lq_sta->active_tbl]; rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE"); tmp_tbl = &lq_sta->lq_info[rs_search_tbl(lq_sta->active_tbl)]; rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH"); rs_dump_rate(mvm, &lq_rate, "ACTUAL"); /* no matching table found, let's by-pass the data collection * and continue to perform rate scale to find the rate table */ rs_stay_in_table(lq_sta, true); goto done; } /* Updating the frame history depends on whether packets were * aggregated. * * For aggregation, all packets were transmitted at the same rate, the * first index into rate scale table. */ if (info->flags & IEEE80211_TX_STAT_AMPDU) { rs_collect_tpc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index, info->status.ampdu_len, info->status.ampdu_ack_len, reduced_txp); /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat * it as a single frame loss as we don't want the success ratio * to dip too quickly because a BA wasn't received. * For TPC, there's no need for this optimisation since we want * to recover very quickly from a bad power reduction and, * therefore we'd like the success ratio to get an immediate hit * when failing to get a BA, so we'd switch back to a lower or * zero power reduction. When FW transmits agg with a rate * different from the initial rate, it will not use reduced txp * and will send BA notification twice (one empty with reduced * txp equal to the value from LQ and one with reduced txp 0). * We need to update counters for each txp level accordingly. */ if (info->status.ampdu_ack_len == 0) info->status.ampdu_len = 1; rs_collect_tlc_data(mvm, tid, curr_tbl, tx_resp_rate.index, info->status.ampdu_len, info->status.ampdu_ack_len); /* Update success/fail counts if not searching for new mode */ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { lq_sta->total_success += info->status.ampdu_ack_len; lq_sta->total_failed += (info->status.ampdu_len - info->status.ampdu_ack_len); } } else { /* For legacy, update frame history with for each Tx retry. */ retries = info->status.rates[0].count - 1; /* HW doesn't send more than 15 retries */ retries = min(retries, 15); /* The last transmission may have been successful */ legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK); /* Collect data for each rate used during failed TX attempts */ for (i = 0; i <= retries; ++i) { lq_hwrate = le32_to_cpu(table->rs_table[i]); if (rs_rate_from_ucode_rate(lq_hwrate, (enum nl80211_band)info->band, &lq_rate)) { WARN_ON_ONCE(1); return; } /* Only collect stats if retried rate is in the same RS * table as active/search. */ if (rs_rate_column_match(&lq_rate, &curr_tbl->rate)) tmp_tbl = curr_tbl; else if (rs_rate_column_match(&lq_rate, &other_tbl->rate)) tmp_tbl = other_tbl; else continue; rs_collect_tpc_data(mvm, lq_sta, tmp_tbl, tx_resp_rate.index, 1, i < retries ? 0 : legacy_success, reduced_txp); rs_collect_tlc_data(mvm, tid, tmp_tbl, tx_resp_rate.index, 1, i < retries ? 0 : legacy_success); } /* Update success/fail counts if not searching for new mode */ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) { lq_sta->total_success += legacy_success; lq_sta->total_failed += retries + (1 - legacy_success); } } /* The last TX rate is cached in lq_sta; it's set in if/else above */ last_rate = lq_sta->last_rate_n_flags; lq_sta->last_rate_n_flags = lq_hwrate; if (last_rate != lq_hwrate) { rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate), lq_sta->last_rate_n_flags); XYLog("%s new rate: %s\n", __FUNCTION__, pretty_rate); } if ((lq_sta->last_rate_n_flags & RATE_MCS_VHT_MSK) || (lq_sta->last_rate_n_flags & RATE_MCS_HE_MSK)) { sta->ni_txmcs = (lq_sta->last_rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK); } else if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { sta->ni_txmcs = (lq_sta->last_rate_n_flags & (RATE_HT_MCS_RATE_CODE_MSK | RATE_HT_MCS_NSS_MSK)); } else { int index = iwl_mvm_legacy_rate_to_mac80211_idx(lq_sta->last_rate_n_flags, (enum nl80211_band)info->band); if (index < 0 || index >= ieee80211_std_rateset_11g.rs_nrates) goto done; sta->ni_txrate = ieee80211_std_rateset_11g.rs_rates[index] / 2; } IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp); done: /* See if there's a better rate or modulation mode to try. */ if (/*sta->supp_rates[info->band]*/ true) rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp); } void iwl_mvm_rs_tx_status(struct iwm_softc *mvm, struct ieee80211_node *sta, int tid, struct ieee80211_tx_info *info, bool ndp) { /* If it's locked we are in middle of init flow * just wait for next tx status to update the lq_sta data */ if (!IOSimpleLockTryLock(mvm->lq_sta.rs_drv.pers.lock)) return; __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp); IOSimpleLockUnlock(mvm->lq_sta.rs_drv.pers.lock); } static void rs_fill_rates_for_column(struct iwm_softc *mvm, struct iwl_lq_sta *lq_sta, struct rs_rate *rate, __le32 *rs_table, int *rs_table_index, int num_rates, int num_retries, u8 valid_tx_ant, bool toggle_ant) { int i, j; __le32 ucode_rate; bool bottom_reached = false; int prev_rate_idx = rate->index; int end = LINK_QUAL_MAX_RETRY_NUM; int index = *rs_table_index; for (i = 0; i < num_rates && index < end; i++) { for (j = 0; j < num_retries && index < end; j++, index++) { ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm, rate)); rs_table[index] = ucode_rate; if (toggle_ant) rs_toggle_antenna(valid_tx_ant, rate); } prev_rate_idx = rate->index; bottom_reached = rs_get_lower_rate_in_column(lq_sta, rate); if (bottom_reached && !is_legacy(rate)) break; } if (!bottom_reached && !is_legacy(rate)) rate->index = prev_rate_idx; *rs_table_index = index; } /* Building the rate table is non trivial. When we're in MIMO2/VHT/80Mhz/SGI * column the rate table should look like this: * * rate[0] 0x400F019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI * rate[1] 0x400F019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI * rate[2] 0x400F018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI * rate[3] 0x400F018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI * rate[4] 0x400F017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI * rate[5] 0x400F017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI * rate[6] 0x4005007 VHT | ANT: A BW: 80Mhz MCS: 7 NSS: 1 NGI * rate[7] 0x4009006 VHT | ANT: B BW: 80Mhz MCS: 6 NSS: 1 NGI * rate[8] 0x4005005 VHT | ANT: A BW: 80Mhz MCS: 5 NSS: 1 NGI * rate[9] 0x800B Legacy | ANT: B Rate: 36 Mbps * rate[10] 0x4009 Legacy | ANT: A Rate: 24 Mbps * rate[11] 0x8007 Legacy | ANT: B Rate: 18 Mbps * rate[12] 0x4005 Legacy | ANT: A Rate: 12 Mbps * rate[13] 0x800F Legacy | ANT: B Rate: 9 Mbps * rate[14] 0x400D Legacy | ANT: A Rate: 6 Mbps * rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps */ static void rs_build_rates_table(struct iwm_softc *mvm, struct ieee80211_node *sta, struct iwl_lq_sta *lq_sta, const struct rs_rate *initial_rate) { struct rs_rate rate; int num_rates, num_retries, index = 0; u8 valid_tx_ant = 0; struct iwm_lq_cmd *lq_cmd = &lq_sta->lq; bool toggle_ant = false; u32 color; ItlIwm *that = container_of(mvm, ItlIwm, com); memcpy(&rate, initial_rate, sizeof(rate)); valid_tx_ant = that->iwm_fw_valid_tx_ant(mvm); /* TODO: remove old API when min FW API hits 14 */ if (!isset(&mvm->sc_ucode_api, IWM_UCODE_TLV_API_LQ_SS_PARAMS) && rs_stbc_allow(mvm, sta, lq_sta)) rate.stbc = true; if (is_siso(&rate)) { num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES; num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE; } else if (is_mimo(&rate)) { num_rates = IWL_MVM_RS_INITIAL_MIMO_NUM_RATES; num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE; } else { num_rates = IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES; num_retries = IWL_MVM_RS_INITIAL_LEGACY_RETRIES; toggle_ant = true; } rs_fill_rates_for_column(mvm, lq_sta, &rate, (__le32 *)lq_cmd->rs_table, &index, num_rates, num_retries, valid_tx_ant, toggle_ant); rs_get_lower_rate_down_column(lq_sta, &rate); if (is_siso(&rate)) { num_rates = IWL_MVM_RS_SECONDARY_SISO_NUM_RATES; num_retries = IWL_MVM_RS_SECONDARY_SISO_RETRIES; lq_cmd->mimo_delim = index; } else if (is_legacy(&rate)) { num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES; num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES; } else { WARN_ON_ONCE(1); } toggle_ant = true; rs_fill_rates_for_column(mvm, lq_sta, &rate, (__le32 *)lq_cmd->rs_table, &index, num_rates, num_retries, valid_tx_ant, toggle_ant); rs_get_lower_rate_down_column(lq_sta, &rate); num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES; num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES; rs_fill_rates_for_column(mvm, lq_sta, &rate, (__le32 *)lq_cmd->rs_table, &index, num_rates, num_retries, valid_tx_ant, toggle_ant); /* update the color of the LQ command (as a counter at bits 1-3) */ color = LQ_FLAGS_COLOR_INC(LQ_FLAG_COLOR_GET(lq_cmd->flags)); lq_cmd->flags = LQ_FLAG_COLOR_SET(lq_cmd->flags, color); } #if 0 struct rs_bfer_active_iter_data { struct ieee80211_node *exclude_sta; struct ieee80211_node *bfer_mvmsta; }; static void rs_bfer_active_iter(void *_data, struct ieee80211_node *sta) { struct rs_bfer_active_iter_data *data = (struct rs_bfer_active_iter_data *)_data; struct iwm_lq_cmd *lq_cmd = &sta->ni_ic->lq_sta.rs_drv.lq; u32 ss_params = le32_to_cpu(lq_cmd->ss_params); if (sta == data->exclude_sta) return; /* The current sta has BFER allowed */ if (ss_params & LQ_SS_BFER_ALLOWED) { WARN_ON_ONCE(data->bfer_mvmsta != NULL); data->bfer_mvmsta = mvmsta; } } static int rs_bfer_priority(struct ieee80211_node *sta) { return 1; } /* Returns >0 if sta1 has a higher BFER priority compared to sta2 */ static int rs_bfer_priority_cmp(struct ieee80211_node *sta1, struct ieee80211_node *sta2) { int prio1 = rs_bfer_priority(sta1); int prio2 = rs_bfer_priority(sta2); if (prio1 > prio2) return 1; if (prio1 < prio2) return -1; return 0; } static inline void ieee80211_iterate_stations_atomic(struct iwm_softc *hw, void (*iterator)(void *data, struct ieee80211_node *sta), void *data) { iterator(data, hw->sc_ic.ic_bss); } #endif static void rs_set_lq_ss_params(struct iwm_softc *mvm, struct ieee80211_node *sta, struct iwl_lq_sta *lq_sta, const struct rs_rate *initial_rate) { struct iwm_lq_cmd *lq_cmd = &lq_sta->lq; #if 0 struct rs_bfer_active_iter_data data = { .exclude_sta = sta, .bfer_mvmsta = NULL, }; #endif u32 ss_params = LQ_SS_PARAMS_VALID; if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) goto out; if (lq_sta->stbc_capable) ss_params |= LQ_SS_STBC_1SS_ALLOWED; #if 0 if (!lq_sta->bfer_capable) goto out; ieee80211_iterate_stations_atomic(mvm, rs_bfer_active_iter, &data); bfer_mvmsta = data.bfer_mvmsta; /* This code is safe as it doesn't run concurrently for different * stations. This is guaranteed by the fact that calls to * ieee80211_tx_status wouldn't run concurrently for a single HW. */ if (!bfer_mvmsta) { IWL_DEBUG_RATE(mvm, "No sta with BFER allowed found. Allow\n"); ss_params |= LQ_SS_BFER_ALLOWED; goto out; } IWL_DEBUG_RATE(mvm, "Found existing sta %d with BFER activated\n", bfer_mvmsta->sta_id); /* Disallow BFER on another STA if active and we're a higher priority */ if (rs_bfer_priority_cmp(mvmsta, bfer_mvmsta) > 0) { struct iwm_lq_cmd *bfersta_lq_cmd = &bfer_mvmsta->lq_sta.rs_drv.lq; u32 bfersta_ss_params = le32_to_cpu(bfersta_lq_cmd->ss_params); bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED; bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params); iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd); ss_params |= LQ_SS_BFER_ALLOWED; IWL_DEBUG_RATE(mvm, "Lower priority BFER sta found (%d). Switch BFER\n", bfer_mvmsta->sta_id); } #else if (lq_sta->bfer_capable) ss_params |= LQ_SS_BFER_ALLOWED; #endif out: lq_cmd->ss_params = cpu_to_le32(ss_params); } static void rs_fill_lq_cmd(struct iwm_softc *mvm, struct ieee80211_node *sta, struct iwl_lq_sta *lq_sta, const struct rs_rate *initial_rate) { struct iwm_lq_cmd *lq_cmd = &lq_sta->lq; ItlIwm *that = container_of(mvm, ItlIwm, com); lq_cmd->agg_disable_start_th = IWL_MVM_RS_AGG_DISABLE_START; lq_cmd->agg_time_limit = cpu_to_le16(IWL_MVM_RS_AGG_TIME_LIMIT); if (WARN_ON_ONCE(!sta || !initial_rate)) return; rs_build_rates_table(mvm, sta, lq_sta, initial_rate); if (isset(&mvm->sc_ucode_api, IWM_UCODE_TLV_API_LQ_SS_PARAMS)) rs_set_lq_ss_params(mvm, sta, lq_sta, initial_rate); if (!isset(&mvm->sc_enabled_capa, IWM_UCODE_TLV_CAPA_COEX_SCHEMA_2) && that->iwm_num_of_ant(initial_rate->ant) == 1) lq_cmd->single_stream_ant_msk = initial_rate->ant; lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; #if 0 if (mvmsta->vif->p2p) lq_cmd->flags |= LQ_FLAG_USE_RTS_MSK; #endif lq_cmd->agg_time_limit = cpu_to_le16(that->iwm_coex_agg_time_limit(mvm, sta)); } int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate) { char *type, *bw; u8 mcs = 0, nss = 0; u8 ant = (rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS; if (!(rate & RATE_MCS_HT_MSK) && !(rate & RATE_MCS_VHT_MSK) && !(rate & RATE_MCS_HE_MSK)) { int index = iwl_hwrate_to_plcp_idx(rate); return snprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps", rs_pretty_ant(ant), index == IWL_RATE_INVALID ? "BAD" : iwl_rate_mcs[index].mbps); } if (rate & RATE_MCS_VHT_MSK) { type = "VHT"; mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK; nss = ((rate & RATE_VHT_MCS_NSS_MSK) >> RATE_VHT_MCS_NSS_POS) + 1; } else if (rate & RATE_MCS_HT_MSK) { type = "HT"; mcs = rate & RATE_HT_MCS_INDEX_MSK; nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1; } else if (rate & RATE_MCS_HE_MSK) { type = "HE"; mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK; nss = ((rate & RATE_VHT_MCS_NSS_MSK) >> RATE_VHT_MCS_NSS_POS) + 1; } else { type = "Unknown"; /* shouldn't happen */ } switch (rate & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: bw = "20Mhz"; break; case RATE_MCS_CHAN_WIDTH_40: bw = "40Mhz"; break; case RATE_MCS_CHAN_WIDTH_80: bw = "80Mhz"; break; case RATE_MCS_CHAN_WIDTH_160: bw = "160Mhz"; break; default: bw = "BAD BW"; } return snprintf(buf, bufsz, "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s", rate, type, rs_pretty_ant(ant), bw, mcs, nss, (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ", (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", (rate & RATE_HE_DUAL_CARRIER_MODE_MSK) ? "DCM " : "", (rate & RATE_MCS_BF_MSK) ? "BF " : ""); } void iwl_mvm_rs_rate_init(struct iwm_softc *mvm, struct ieee80211_node *sta, enum nl80211_band band, bool update) { IOSimpleLockLock(mvm->lq_sta.rs_drv.pers.lock); rs_drv_rate_init(mvm, sta, band); IOSimpleLockUnlock(mvm->lq_sta.rs_drv.pers.lock); } static int rs_drv_tx_protection(struct iwm_softc *mvm, bool enable) { struct iwm_lq_cmd *lq = &mvm->lq_sta.rs_drv.lq; if (enable) { if (mvm->tx_protection == 0) lq->flags |= LQ_FLAG_USE_RTS_MSK; mvm->tx_protection++; } else { mvm->tx_protection--; if (mvm->tx_protection == 0) lq->flags &= ~LQ_FLAG_USE_RTS_MSK; } return iwl_mvm_send_lq_cmd(mvm, lq); } /** * iwl_mvm_tx_protection - ask FW to enable RTS/CTS protection * @mvm: The mvm component * @mvmsta: The station * @enable: Enable Tx protection? */ int iwl_mvm_tx_protection(struct iwm_softc *mvm, bool enable) { return rs_drv_tx_protection(mvm, enable); } void iwm_rs_alloc(struct iwm_softc *sc) { sc->lq_sta.rs_drv.pers.lock = IOSimpleLockAlloc(); } void iwm_rs_free(struct iwm_softc *sc) { if (sc->lq_sta.rs_drv.pers.lock) { IOSimpleLockFree(sc->lq_sta.rs_drv.pers.lock); sc->lq_sta.rs_drv.pers.lock = NULL; } } ================================================ FILE: itlwm/hal_iwm/rs.h ================================================ // // rs.hpp // itlwm // // Created by zxystd on 2021/8/27. // Copyright © 2021 钟先耀. All rights reserved. // #ifndef rs_hpp #define rs_hpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IWL_DEBUG_RATE(sc, fmt, x...) //#define IWL_DEBUG_RATE(sc, fmt, x...)\ //do\ //{\ //XYLog("%s: " fmt, "RATE", ##x);\ //}while(0) #define IWL_ERR(sc, fmt, x...)\ do\ {\ XYLog("RS %s: " fmt, "ERR", ##x);\ }while(0) /** * enum nl80211_band - Frequency band * @NL80211_BAND_2GHZ: 2.4 GHz ISM band * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace * since newer kernel versions may support more bands */ enum nl80211_band { NL80211_BAND_2GHZ, NL80211_BAND_5GHZ, NUM_NL80211_BANDS, }; /** * enum mac80211_tx_info_flags - flags to describe transmission information/status * * These flags are used with the @flags member of &ieee80211_tx_info. * * @IEEE80211_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame. * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence * number to this frame, taking care of not overwriting the fragment * number and increasing the sequence number only when the * IEEE80211_TX_CTL_FIRST_FRAGMENT flag is set. mac80211 will properly * assign sequence numbers to QoS-data frames but cannot do so correctly * for non-QoS-data and management frames because beacons need them from * that counter as well and mac80211 cannot guarantee proper sequencing. * If this flag is set, the driver should instruct the hardware to * assign a sequence number to the frame or assign one itself. Cf. IEEE * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for * beacons and always be clear for frames without a sequence number field. * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination * station * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted * because the destination STA was in powersave mode. Note that to * avoid race conditions, the filter must be set by the hardware or * firmware upon receiving a frame that indicates that the station * went to sleep (must be done on device to filter frames already on * the queue) and may only be unset after mac80211 gives the OK for * that by setting the IEEE80211_TX_CTL_CLEAR_PS_FILT (see above), * since only then is it guaranteed that no more frames are in the * hardware queue. * @IEEE80211_TX_STAT_ACK: Frame was acknowledged * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status * is for the whole aggregation. * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned, * so consider using block ack request (BAR). * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be * set by rate control algorithms to indicate probe rate, will * be cleared for fragmented frames (except on the last fragment) * @IEEE80211_TX_INTFL_OFFCHAN_TX_OK: Internal to mac80211. Used to indicate * that a frame can be transmitted while the queues are stopped for * off-channel operation. * @IEEE80211_TX_CTL_HW_80211_ENCAP: This frame uses hardware encapsulation * (header conversion) * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211, * used to indicate that a frame was already retried due to PS * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, * used to indicate frame should not be encrypted * @IEEE80211_TX_CTL_NO_PS_BUFFER: This frame is a response to a poll * frame (PS-Poll or uAPSD) or a non-bufferable MMPDU and must * be sent although the station is in powersave mode. * @IEEE80211_TX_CTL_MORE_FRAMES: More frames will be passed to the * transmit function after the current frame, this can be used * by drivers to kick the DMA queue only if unset or when the * queue gets full. * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted * after TX status because the destination was asleep, it must not * be modified again (no seqno assignment, crypto, etc.) * @IEEE80211_TX_INTFL_MLME_CONN_TX: This frame was transmitted by the MLME * code for connection establishment, this indicates that its status * should kick the MLME state machine. * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211 * MLME command (internal to mac80211 to figure out whether to send TX * status to user space) * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame * @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this * frame and selects the maximum number of streams that it can use. * @IEEE80211_TX_CTL_TX_OFFCHAN: Marks this packet to be transmitted on * the off-channel channel when a remain-on-channel offload is done * in hardware -- normal packets still flow and are expected to be * handled properly by the device. * @IEEE80211_TX_INTFL_TKIP_MIC_FAILURE: Marks this packet to be used for TKIP * testing. It will be sent out with incorrect Michael MIC key to allow * TKIP countermeasures to be tested. * @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate. * This flag is actually used for management frame especially for P2P * frames not being sent at CCK rate in 2GHz band. * @IEEE80211_TX_STATUS_EOSP: This packet marks the end of service period, * when its status is reported the service period ends. For frames in * an SP that mac80211 transmits, it is already set; for driver frames * the driver may set this flag. It is also used to do the same for * PS-Poll responses. * @IEEE80211_TX_CTL_USE_MINRATE: This frame will be sent at lowest rate. * This flag is used to send nullfunc frame at minimum rate when * the nullfunc is used for connection monitoring purpose. * @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it * would be fragmented by size (this is optional, only used for * monitor injection). * @IEEE80211_TX_STAT_NOACK_TRANSMITTED: A frame that was marked with * IEEE80211_TX_CTL_NO_ACK has been successfully transmitted without * any errors (like issues specific to the driver/HW). * This flag must not be set for frames that don't request no-ack * behaviour with IEEE80211_TX_CTL_NO_ACK. * * Note: If you have to add new flags to the enumeration, then don't * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. */ enum mac80211_tx_info_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1), IEEE80211_TX_CTL_NO_ACK = BIT(2), IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(3), IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(4), IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(5), IEEE80211_TX_CTL_AMPDU = BIT(6), IEEE80211_TX_CTL_INJECTED = BIT(7), IEEE80211_TX_STAT_TX_FILTERED = BIT(8), IEEE80211_TX_STAT_ACK = BIT(9), IEEE80211_TX_STAT_AMPDU = BIT(10), IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), IEEE80211_TX_INTFL_OFFCHAN_TX_OK = BIT(13), IEEE80211_TX_CTL_HW_80211_ENCAP = BIT(14), IEEE80211_TX_INTFL_RETRIED = BIT(15), IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17), IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), IEEE80211_TX_INTFL_MLME_CONN_TX = BIT(20), IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21), IEEE80211_TX_CTL_LDPC = BIT(22), IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24), IEEE80211_TX_CTL_TX_OFFCHAN = BIT(25), IEEE80211_TX_INTFL_TKIP_MIC_FAILURE = BIT(26), IEEE80211_TX_CTL_NO_CCK_RATE = BIT(27), IEEE80211_TX_STATUS_EOSP = BIT(28), IEEE80211_TX_CTL_USE_MINRATE = BIT(29), IEEE80211_TX_CTL_DONTFRAG = BIT(30), IEEE80211_TX_STAT_NOACK_TRANSMITTED = BIT(31), }; /** * enum mac80211_rate_control_flags - per-rate flags set by the * Rate Control algorithm. * * These flags are set by the Rate control algorithm for each rate during tx, * in the @flags member of struct ieee80211_tx_rate. * * @IEEE80211_TX_RC_USE_RTS_CTS: Use RTS/CTS exchange for this rate. * @IEEE80211_TX_RC_USE_CTS_PROTECT: CTS-to-self protection is required. * This is set if the current BSS requires ERP protection. * @IEEE80211_TX_RC_USE_SHORT_PREAMBLE: Use short preamble. * @IEEE80211_TX_RC_MCS: HT rate. * @IEEE80211_TX_RC_VHT_MCS: VHT MCS rate, in this case the idx field is split * into a higher 4 bits (Nss) and lower 4 bits (MCS number) * @IEEE80211_TX_RC_GREEN_FIELD: Indicates whether this rate should be used in * Greenfield mode. * @IEEE80211_TX_RC_40_MHZ_WIDTH: Indicates if the Channel Width should be 40 MHz. * @IEEE80211_TX_RC_80_MHZ_WIDTH: Indicates 80 MHz transmission * @IEEE80211_TX_RC_160_MHZ_WIDTH: Indicates 160 MHz transmission * (80+80 isn't supported yet) * @IEEE80211_TX_RC_DUP_DATA: The frame should be transmitted on both of the * adjacent 20 MHz channels, if the current channel type is * NL80211_CHAN_HT40MINUS or NL80211_CHAN_HT40PLUS. * @IEEE80211_TX_RC_SHORT_GI: Short Guard interval should be used for this rate. */ enum mac80211_rate_control_flags { IEEE80211_TX_RC_USE_RTS_CTS = BIT(0), IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1), IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2), /* rate index is an HT/VHT MCS instead of an index */ IEEE80211_TX_RC_MCS = BIT(3), IEEE80211_TX_RC_GREEN_FIELD = BIT(4), IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5), IEEE80211_TX_RC_DUP_DATA = BIT(6), IEEE80211_TX_RC_SHORT_GI = BIT(7), IEEE80211_TX_RC_VHT_MCS = BIT(8), IEEE80211_TX_RC_80_MHZ_WIDTH = BIT(9), IEEE80211_TX_RC_160_MHZ_WIDTH = BIT(10), }; /** * struct ieee80211_rx_status - receive status * * The low-level driver should provide this information (the subset * supported by hardware) to the 802.11 code with each received * frame, in the skb's control buffer (cb). * * @mactime: value in microseconds of the 64-bit Time Synchronization Function * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. * @boottime_ns: CLOCK_BOOTTIME timestamp the frame was received at, this is * needed only for beacons and probe responses that update the scan cache. * @device_timestamp: arbitrary timestamp for the device, mac80211 doesn't use * it but can store it and pass it back to the driver for synchronisation * @band: the active band when this frame was received * @freq: frequency the radio was tuned to when receiving this frame, in MHz * This field must be set for management frames, but isn't strictly needed * for data (other) frames - for those it only affects radiotap reporting. * @freq_offset: @freq has a positive offset of 500Khz. * @signal: signal strength when receiving this frame, either in dBm, in dB or * unspecified depending on the hardware capabilities flags * @IEEE80211_HW_SIGNAL_* * @chains: bitmask of receive chains for which separate signal strength * values were filled. * @chain_signal: per-chain signal strength, in dBm (unlike @signal, doesn't * support dB or unspecified units) * @antenna: antenna used * @rate_idx: index of data rate into band's supported rates or MCS index if * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT) * @nss: number of streams (VHT and HE only) * @flag: %RX_FLAG_\* * @encoding: &enum mac80211_rx_encoding * @bw: &enum rate_info_bw * @enc_flags: uses bits from &enum mac80211_rx_encoding_flags * @he_ru: HE RU, from &enum nl80211_he_ru_alloc * @he_gi: HE GI, from &enum nl80211_he_gi * @he_dcm: HE DCM value * @rx_flags: internal RX flags for mac80211 * @ampdu_reference: A-MPDU reference number, must be a different value for * each A-MPDU but the same for each subframe within one A-MPDU * @ampdu_delimiter_crc: A-MPDU delimiter CRC * @zero_length_psdu_type: radiotap type of the 0-length PSDU */ struct ieee80211_rx_status { // u64 mactime; // u64 boottime_ns; // u32 device_timestamp; // u32 ampdu_reference; // u32 flag; // u16 freq: 13, freq_offset: 1; // u8 enc_flags; // u8 encoding:2, bw:3, he_ru:3; // u8 he_gi:2, he_dcm:1; // u8 rate_idx; // u8 nss; // u8 rx_flags; // u8 band; // u8 antenna; s8 signal; u8 chains; s8 chain_signal[4]; // u8 ampdu_delimiter_crc; // u8 zero_length_psdu_type; }; /** * struct ieee80211_tx_rate - rate selection/status * * @idx: rate index to attempt to send with * @flags: rate control flags (&enum mac80211_rate_control_flags) * @count: number of tries in this rate before going to the next rate * * A value of -1 for @idx indicates an invalid rate and, if used * in an array of retry rates, that no more rates should be tried. * * When used for transmit status reporting, the driver should * always report the rate along with the flags it used. * * &struct ieee80211_tx_info contains an array of these structs * in the control information, and it will be filled by the rate * control algorithm according to what should be sent. For example, * if this array contains, in the format { , } the * information:: * * { 3, 2 }, { 2, 2 }, { 1, 4 }, { -1, 0 }, { -1, 0 } * * then this means that the frame should be transmitted * up to twice at rate 3, up to twice at rate 2, and up to four * times at rate 1 if it doesn't get acknowledged. Say it gets * acknowledged by the peer after the fifth attempt, the status * information should then contain:: * * { 3, 2 }, { 2, 2 }, { 1, 1 }, { -1, 0 } ... * * since it was transmitted twice at rate 3, twice at rate 2 * and once at rate 1 after which we received an acknowledgement. */ struct ieee80211_tx_rate { s8 idx; u16 count:5, flags:11; } __packed; struct ieee80211_tx_info { /* common information */ u32 flags; u32 band:3, ack_frame_id:13, hw_queue:4, tx_time_est:10; /* 2 free bits */ union { struct { struct ieee80211_tx_rate rates[4]; s32 ack_signal; u8 ampdu_ack_len; u8 ampdu_len; u8 antenna; u16 tx_time; bool is_valid_ack_signal; void *status_driver_data[19 / sizeof(void *)]; } status; }; }; /** * struct ieee80211_mcs_info - MCS information * @rx_mask: RX mask * @rx_highest: highest supported RX rate. If set represents * the highest supported RX data rate in units of 1 Mbps. * If this field is 0 this value should not be used to * consider the highest RX data rate supported. * @tx_params: TX parameters */ struct ieee80211_mcs_info { u8 rx_mask[10]; __le16 rx_highest; u8 tx_params; u8 reserved[3]; } __packed; /** * struct ieee80211_sta_ht_cap - STA's HT capabilities * * This structure describes most essential parameters needed * to describe 802.11n HT capabilities for an STA. * * @ht_supported: is HT supported by the STA * @cap: HT capabilities map as described in 802.11n spec * @ampdu_factor: Maximum A-MPDU length factor * @ampdu_density: Minimum A-MPDU spacing * @mcs: Supported MCS rates */ struct ieee80211_sta_ht_cap { u16 cap; /* use IEEE80211_HT_CAP_ */ bool ht_supported; u8 ampdu_factor; u8 ampdu_density; struct ieee80211_mcs_info mcs; }; /** * struct ieee80211_sta_vht_cap - STA's VHT capabilities * * This structure describes most essential parameters needed * to describe 802.11ac VHT capabilities for an STA. * * @vht_supported: is VHT supported by the STA * @cap: VHT capabilities map as described in 802.11ac spec * @vht_mcs: Supported VHT MCS rates */ struct ieee80211_sta_vht_cap { bool vht_supported; u32 cap; /* use IEEE80211_VHT_CAP_ */ struct ieee80211_vht_mcs_info vht_mcs; }; /** * struct ieee80211_vht_cap - VHT capabilities * * This structure is the "VHT capabilities element" as * described in 802.11ac D3.0 8.4.2.160 * @vht_cap_info: VHT capability info * @supp_mcs: VHT MCS supported rates */ struct ieee80211_vht_cap { __le32 vht_cap_info; struct ieee80211_vht_mcs_info supp_mcs; } __packed; static inline int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap, int bw, int mcs, bool ext_nss_bw_capable, unsigned int max_vht_nss) { u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map); int ext_nss_bw; int supp_width; int i, mcs_encoding; if (map == 0xffff) return 0; if (WARN_ON(mcs > 9 || max_vht_nss > 8)) return 0; if (mcs <= 7) mcs_encoding = 0; else if (mcs == 8) mcs_encoding = 1; else mcs_encoding = 2; if (!max_vht_nss) { /* find max_vht_nss for the given MCS */ for (i = 7; i >= 0; i--) { int supp = (map >> (2 * i)) & 3; if (supp == 3) continue; if (supp >= mcs_encoding) { max_vht_nss = i + 1; break; } } } if (!(cap->supp_mcs.tx_mcs_map & cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) return max_vht_nss; ext_nss_bw = le32_get_bits(cap->vht_cap_info, IEEE80211_VHTCAP_EXT_NSS_BW_MASK); supp_width = le32_get_bits(cap->vht_cap_info, IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK); /* if not capable, treat ext_nss_bw as 0 */ if (!ext_nss_bw_capable) ext_nss_bw = 0; /* This is invalid */ if (supp_width == 3) return 0; /* This is an invalid combination so pretend nothing is supported */ if (supp_width == 2 && (ext_nss_bw == 1 || ext_nss_bw == 2)) return 0; /* * Cover all the special cases according to IEEE 802.11-2016 * Table 9-250. All other cases are either factor of 1 or not * valid/supported. */ switch (bw) { case IEEE80211_VHT_CHANWIDTH_USE_HT: case IEEE80211_VHT_CHANWIDTH_80MHZ: if ((supp_width == 1 || supp_width == 2) && ext_nss_bw == 3) return 2 * max_vht_nss; break; case IEEE80211_VHT_CHANWIDTH_160MHZ: if (supp_width == 0 && (ext_nss_bw == 1 || ext_nss_bw == 2)) return max_vht_nss / 2; if (supp_width == 0 && ext_nss_bw == 3) return (3 * max_vht_nss) / 4; if (supp_width == 1 && ext_nss_bw == 3) return 2 * max_vht_nss; break; case IEEE80211_VHT_CHANWIDTH_80P80MHZ: if (supp_width == 0 && ext_nss_bw == 1) return 0; /* not possible */ if (supp_width == 0 && ext_nss_bw == 2) return max_vht_nss / 2; if (supp_width == 0 && ext_nss_bw == 3) return (3 * max_vht_nss) / 4; if (supp_width == 1 && ext_nss_bw == 0) return 0; /* not possible */ if (supp_width == 1 && ext_nss_bw == 1) return max_vht_nss / 2; if (supp_width == 1 && ext_nss_bw == 2) return (3 * max_vht_nss) / 4; break; } /* not covered or invalid combination received */ return max_vht_nss; } #define IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM 20 #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT (2 * 1024) /* defined in TU */ #define IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT (40 * 1024) /* defined in TU */ #define IWL_MVM_P2P_LOWLATENCY_PS_ENABLE 0 #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |\ IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |\ IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) #define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20 #define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8 #define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30 #define IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS 20 #define IWL_MVM_PS_HEAVY_TX_THLD_PERCENT 50 #define IWL_MVM_PS_HEAVY_RX_THLD_PERCENT 50 #define IWL_MVM_PS_SNOOZE_INTERVAL 25 #define IWL_MVM_PS_SNOOZE_WINDOW 50 #define IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW 25 #define IWL_MVM_LOWLAT_QUOTA_MIN_PERCENT 64 #define IWL_MVM_BT_COEX_EN_RED_TXP_THRESH 62 #define IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH 65 #define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_MPLUT 1 #define IWL_MVM_BT_COEX_RRC 1 #define IWL_MVM_BT_COEX_TTC 1 #define IWL_MVM_BT_COEX_MPLUT_REG0 0x22002200 #define IWL_MVM_BT_COEX_MPLUT_REG1 0x11118451 #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 #define IWL_MVM_QUOTA_THRESHOLD 4 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1 #define IWL_MVM_TOF_IS_RESPONDER 0 #define IWL_MVM_HW_CSUM_DISABLE 0 #define IWL_MVM_PARSE_NVM 0 #define IWL_MVM_ADWELL_ENABLE 1 #define IWL_MVM_ADWELL_MAX_BUDGET 0 #define IWL_MVM_TCM_LOAD_MEDIUM_THRESH 10 /* percentage */ #define IWL_MVM_TCM_LOAD_HIGH_THRESH 50 /* percentage */ #define IWL_MVM_TCM_LOWLAT_ENABLE_THRESH 100 /* packets/10 seconds */ #define IWL_MVM_UAPSD_NONAGG_PERIOD 5000 /* msecs */ #define IWL_MVM_UAPSD_NOAGG_LIST_LEN IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM #define IWL_MVM_NON_TRANSMITTING_AP 0 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 #define IWL_MVM_RS_INITIAL_MIMO_NUM_RATES 3 #define IWL_MVM_RS_INITIAL_SISO_NUM_RATES 3 #define IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES 2 #define IWL_MVM_RS_INITIAL_LEGACY_RETRIES 2 #define IWL_MVM_RS_SECONDARY_LEGACY_RETRIES 1 #define IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES 16 #define IWL_MVM_RS_SECONDARY_SISO_NUM_RATES 3 #define IWL_MVM_RS_SECONDARY_SISO_RETRIES 1 #define IWL_MVM_RS_RATE_MIN_FAILURE_TH 3 #define IWL_MVM_RS_RATE_MIN_SUCCESS_TH 8 #define IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT 5 /* Seconds */ #define IWL_MVM_RS_IDLE_TIMEOUT 5 /* Seconds */ #define IWL_MVM_RS_MISSED_RATE_MAX 15 #define IWL_MVM_RS_LEGACY_FAILURE_LIMIT 160 #define IWL_MVM_RS_LEGACY_SUCCESS_LIMIT 480 #define IWL_MVM_RS_LEGACY_TABLE_COUNT 160 #define IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT 400 #define IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT 4500 #define IWL_MVM_RS_NON_LEGACY_TABLE_COUNT 1500 #define IWL_MVM_RS_SR_FORCE_DECREASE 15 /* percent */ #define IWL_MVM_RS_SR_NO_DECREASE 85 /* percent */ #define IWL_MVM_RS_AGG_TIME_LIMIT 4000 /* 4 msecs. valid 100-8000 */ #define IWL_MVM_RS_AGG_DISABLE_START 3 #define IWL_MVM_RS_AGG_START_THRESHOLD 10 /* num frames per second */ #define IWL_MVM_RS_TPC_SR_FORCE_INCREASE 75 /* percent */ #define IWL_MVM_RS_TPC_SR_NO_INCREASE 85 /* percent */ #define IWL_MVM_RS_TPC_TX_POWER_STEP 3 #define IWL_MVM_ENABLE_EBS 1 #define IWL_MVM_FTM_INITIATOR_ALGO IWL_TOF_ALGO_TYPE_MAX_LIKE #define IWL_MVM_FTM_INITIATOR_DYNACK true #define IWL_MVM_FTM_R2I_MAX_REP 7 #define IWL_MVM_FTM_I2R_MAX_REP 7 #define IWL_MVM_FTM_R2I_MAX_STS 1 #define IWL_MVM_FTM_I2R_MAX_STS 1 #define IWL_MVM_FTM_R2I_MAX_TOTAL_LTF 3 #define IWL_MVM_FTM_I2R_MAX_TOTAL_LTF 3 #define IWL_MVM_FTM_INITIATOR_SECURE_LTF false #define IWL_MVM_FTM_RESP_NDP_SUPPORT true #define IWL_MVM_FTM_RESP_LMR_FEEDBACK_SUPPORT true #define IWL_MVM_D3_DEBUG false #define IWL_MVM_USE_TWT true #define IWL_MVM_AMPDU_CONSEC_DROPS_DELBA 10 #define IWL_MVM_USE_NSSN_SYNC 0 #define IWL_MVM_PHY_FILTER_CHAIN_A 0 #define IWL_MVM_PHY_FILTER_CHAIN_B 0 #define IWL_MVM_PHY_FILTER_CHAIN_C 0 #define IWL_MVM_PHY_FILTER_CHAIN_D 0 #define IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH false #define IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA 40 /* 20016 pSec is 6 meter RTT, meaning 3 meter range */ #define IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT 20016 #define IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT 20016 #define IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC 2 #define IWL_MVM_DISABLE_AP_FILS false #define IWL_MVM_6GHZ_PASSIVE_SCAN_TIMEOUT 3000 /* in seconds */ #define IWL_MVM_6GHZ_PASSIVE_SCAN_ASSOC_TIMEOUT 60 /* in seconds */ #define IWL_MAX_TID_COUNT 8 #define IWL_MGMT_TID 15 #define IWL_FRAME_LIMIT 64 #define IWL_MAX_RX_HW_QUEUES 16 #define IWL_9000_MAX_RX_HW_QUEUES 6 /* Antenna presence definitions */ #define ANT_NONE 0x0 #define ANT_INVALID 0xff #define ANT_A BIT(0) #define ANT_B BIT(1) #define ANT_C BIT(2) #define ANT_AB (ANT_A | ANT_B) #define ANT_AC (ANT_A | ANT_C) #define ANT_BC (ANT_B | ANT_C) #define ANT_ABC (ANT_A | ANT_B | ANT_C) #define MAX_ANT_NUM 3 #define IWL_RATE_BIT_MSK(r) BIT(IWL_RATE_##r##M_INDEX) /* fw API values for legacy bit rates, both OFDM and CCK */ enum { IWL_RATE_6M_PLCP = 13, IWL_RATE_9M_PLCP = 15, IWL_RATE_12M_PLCP = 5, IWL_RATE_18M_PLCP = 7, IWL_RATE_24M_PLCP = 9, IWL_RATE_36M_PLCP = 11, IWL_RATE_48M_PLCP = 1, IWL_RATE_54M_PLCP = 3, IWL_RATE_1M_PLCP = 10, IWL_RATE_2M_PLCP = 20, IWL_RATE_5M_PLCP = 55, IWL_RATE_11M_PLCP = 110, IWL_RATE_INVM_PLCP = 0xff, }; /* * Returns the first antenna as ANT_[ABC], as defined in iwl-config.h. * The parameter should also be a combination of ANT_[ABC]. */ static inline u8 first_antenna(u8 mask) { BUILD_BUG_ON(ANT_A != BIT(0)); /* using ffs is wrong if not */ if (WARN_ON_ONCE(!mask)) /* ffs will return 0 if mask is zeroed */ return BIT(0); return BIT(ffs(mask) - 1); } /* * These serve as indexes into * struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT]; * TODO: avoid overlap between legacy and HT rates */ enum { IWL_RATE_1M_INDEX = 0, IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX, IWL_RATE_2M_INDEX, IWL_RATE_5M_INDEX, IWL_RATE_11M_INDEX, IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX, IWL_RATE_6M_INDEX, IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX, IWL_RATE_MCS_0_INDEX = IWL_RATE_6M_INDEX, IWL_FIRST_HT_RATE = IWL_RATE_MCS_0_INDEX, IWL_FIRST_VHT_RATE = IWL_RATE_MCS_0_INDEX, IWL_RATE_9M_INDEX, IWL_RATE_12M_INDEX, IWL_RATE_MCS_1_INDEX = IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, IWL_RATE_MCS_2_INDEX = IWL_RATE_18M_INDEX, IWL_RATE_24M_INDEX, IWL_RATE_MCS_3_INDEX = IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, IWL_RATE_MCS_4_INDEX = IWL_RATE_36M_INDEX, IWL_RATE_48M_INDEX, IWL_RATE_MCS_5_INDEX = IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX, IWL_RATE_MCS_6_INDEX = IWL_RATE_54M_INDEX, IWL_LAST_NON_HT_RATE = IWL_RATE_54M_INDEX, IWL_RATE_60M_INDEX, IWL_RATE_MCS_7_INDEX = IWL_RATE_60M_INDEX, IWL_LAST_HT_RATE = IWL_RATE_MCS_7_INDEX, IWL_RATE_MCS_8_INDEX, IWL_RATE_MCS_9_INDEX, IWL_LAST_VHT_RATE = IWL_RATE_MCS_9_INDEX, IWL_RATE_MCS_10_INDEX, IWL_RATE_MCS_11_INDEX, IWL_LAST_HE_RATE = IWL_RATE_MCS_11_INDEX, IWL_RATE_COUNT_LEGACY = IWL_LAST_NON_HT_RATE + 1, IWL_RATE_COUNT = IWL_LAST_HE_RATE + 1, }; /* * rate_n_flags bit fields * * The 32-bit value has different layouts in the low 8 bites depending on the * format. There are three formats, HT, VHT and legacy (11abg, with subformats * for CCK and OFDM). * * High-throughput (HT) rate format * bit 8 is 1, bit 26 is 0, bit 9 is 0 (OFDM) * Very High-throughput (VHT) rate format * bit 8 is 0, bit 26 is 1, bit 9 is 0 (OFDM) * Legacy OFDM rate format for bits 7:0 * bit 8 is 0, bit 26 is 0, bit 9 is 0 (OFDM) * Legacy CCK rate format for bits 7:0: * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK) */ /* Bit 8: (1) HT format, (0) legacy or VHT format */ #define RATE_MCS_HT_POS 8 #define RATE_MCS_HT_MSK (1 << RATE_MCS_HT_POS) /* Bit 9: (1) CCK, (0) OFDM. HT (bit 8) must be "0" for this bit to be valid */ #define RATE_MCS_CCK_POS 9 #define RATE_MCS_CCK_MSK (1 << RATE_MCS_CCK_POS) /* Bit 26: (1) VHT format, (0) legacy format in bits 8:0 */ #define RATE_MCS_VHT_POS 26 #define RATE_MCS_VHT_MSK (1 << RATE_MCS_VHT_POS) /* * High-throughput (HT) rate format for bits 7:0 * * 2-0: MCS rate base * 0) 6 Mbps * 1) 12 Mbps * 2) 18 Mbps * 3) 24 Mbps * 4) 36 Mbps * 5) 48 Mbps * 6) 54 Mbps * 7) 60 Mbps * 4-3: 0) Single stream (SISO) * 1) Dual stream (MIMO) * 2) Triple stream (MIMO) * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data * (bits 7-6 are zero) * * Together the low 5 bits work out to the MCS index because we don't * support MCSes above 15/23, and 0-7 have one stream, 8-15 have two * streams and 16-23 have three streams. We could also support MCS 32 * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.) */ #define RATE_HT_MCS_RATE_CODE_MSK 0x7 #define RATE_HT_MCS_NSS_POS 3 #define RATE_HT_MCS_NSS_MSK (3 << RATE_HT_MCS_NSS_POS) /* Bit 10: (1) Use Green Field preamble */ #define RATE_HT_MCS_GF_POS 10 #define RATE_HT_MCS_GF_MSK (1 << RATE_HT_MCS_GF_POS) #define RATE_HT_MCS_INDEX_MSK 0x3f /* * Very High-throughput (VHT) rate format for bits 7:0 * * 3-0: VHT MCS (0-9) * 5-4: number of streams - 1: * 0) Single stream (SISO) * 1) Dual stream (MIMO) * 2) Triple stream (MIMO) */ /* Bit 4-5: (0) SISO, (1) MIMO2 (2) MIMO3 */ #define RATE_VHT_MCS_RATE_CODE_MSK 0xf #define RATE_VHT_MCS_NSS_POS 4 #define RATE_VHT_MCS_NSS_MSK (3 << RATE_VHT_MCS_NSS_POS) /* * Legacy OFDM rate format for bits 7:0 * * 3-0: 0xD) 6 Mbps * 0xF) 9 Mbps * 0x5) 12 Mbps * 0x7) 18 Mbps * 0x9) 24 Mbps * 0xB) 36 Mbps * 0x1) 48 Mbps * 0x3) 54 Mbps * (bits 7-4 are 0) * * Legacy CCK rate format for bits 7:0: * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK): * * 6-0: 10) 1 Mbps * 20) 2 Mbps * 55) 5.5 Mbps * 110) 11 Mbps * (bit 7 is 0) */ #define RATE_LEGACY_RATE_MSK 0xff /* Bit 10 - OFDM HE */ #define RATE_MCS_HE_POS 10 #define RATE_MCS_HE_MSK BIT(RATE_MCS_HE_POS) /* * Bit 11-12: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz * 0 and 1 are valid for HT and VHT, 2 and 3 only for VHT */ #define RATE_MCS_CHAN_WIDTH_POS 11 #define RATE_MCS_CHAN_WIDTH_MSK (3 << RATE_MCS_CHAN_WIDTH_POS) #define RATE_MCS_CHAN_WIDTH_20 (0 << RATE_MCS_CHAN_WIDTH_POS) #define RATE_MCS_CHAN_WIDTH_40 (1 << RATE_MCS_CHAN_WIDTH_POS) #define RATE_MCS_CHAN_WIDTH_80 (2 << RATE_MCS_CHAN_WIDTH_POS) #define RATE_MCS_CHAN_WIDTH_160 (3 << RATE_MCS_CHAN_WIDTH_POS) /* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */ #define RATE_MCS_SGI_POS 13 #define RATE_MCS_SGI_MSK (1 << RATE_MCS_SGI_POS) /* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C */ #define RATE_MCS_ANT_POS 14 #define RATE_MCS_ANT_A_MSK (1 << RATE_MCS_ANT_POS) #define RATE_MCS_ANT_B_MSK (2 << RATE_MCS_ANT_POS) #define RATE_MCS_ANT_C_MSK (4 << RATE_MCS_ANT_POS) #define RATE_MCS_ANT_AB_MSK (RATE_MCS_ANT_A_MSK | \ RATE_MCS_ANT_B_MSK) #define RATE_MCS_ANT_ABC_MSK (RATE_MCS_ANT_AB_MSK | \ RATE_MCS_ANT_C_MSK) #define RATE_MCS_ANT_MSK RATE_MCS_ANT_ABC_MSK /* Bit 17: (0) SS, (1) SS*2 */ #define RATE_MCS_STBC_POS 17 #define RATE_MCS_STBC_MSK BIT(RATE_MCS_STBC_POS) /* Bit 18: OFDM-HE dual carrier mode */ #define RATE_HE_DUAL_CARRIER_MODE 18 #define RATE_HE_DUAL_CARRIER_MODE_MSK BIT(RATE_HE_DUAL_CARRIER_MODE) /* Bit 19: (0) Beamforming is off, (1) Beamforming is on */ #define RATE_MCS_BF_POS 19 #define RATE_MCS_BF_MSK (1 << RATE_MCS_BF_POS) /* * Bit 20-21: HE LTF type and guard interval * HE (ext) SU: * 0 1xLTF+0.8us * 1 2xLTF+0.8us * 2 2xLTF+1.6us * 3 & SGI (bit 13) clear 4xLTF+3.2us * 3 & SGI (bit 13) set 4xLTF+0.8us * HE MU: * 0 4xLTF+0.8us * 1 2xLTF+0.8us * 2 2xLTF+1.6us * 3 4xLTF+3.2us * HE TRIG: * 0 1xLTF+1.6us * 1 2xLTF+1.6us * 2 4xLTF+3.2us * 3 (does not occur) */ #define RATE_MCS_HE_GI_LTF_POS 20 #define RATE_MCS_HE_GI_LTF_MSK (3 << RATE_MCS_HE_GI_LTF_POS) /* Bit 22-23: HE type. (0) SU, (1) SU_EXT, (2) MU, (3) trigger based */ #define RATE_MCS_HE_TYPE_POS 22 #define RATE_MCS_HE_TYPE_SU (0 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_EXT_SU (1 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_MU (2 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_TRIG (3 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_MSK (3 << RATE_MCS_HE_TYPE_POS) /* Bit 24-25: (0) 20MHz (no dup), (1) 2x20MHz, (2) 4x20MHz, 3 8x20MHz */ #define RATE_MCS_DUP_POS 24 #define RATE_MCS_DUP_MSK (3 << RATE_MCS_DUP_POS) /* Bit 27: (1) LDPC enabled, (0) LDPC disabled */ #define RATE_MCS_LDPC_POS 27 #define RATE_MCS_LDPC_MSK (1 << RATE_MCS_LDPC_POS) /* Bit 28: (1) 106-tone RX (8 MHz RU), (0) normal bandwidth */ #define RATE_MCS_HE_106T_POS 28 #define RATE_MCS_HE_106T_MSK (1 << RATE_MCS_HE_106T_POS) /* Bit 30-31: (1) RTS, (2) CTS */ #define RATE_MCS_RTS_REQUIRED_POS (30) #define RATE_MCS_RTS_REQUIRED_MSK (0x1 << RATE_MCS_RTS_REQUIRED_POS) #define RATE_MCS_CTS_REQUIRED_POS (31) #define RATE_MCS_CTS_REQUIRED_MSK (0x1 << RATE_MCS_CTS_REQUIRED_POS) /* Link Quality definitions */ /* Link quality command flags bit fields */ /* Bit 0: (0) Don't use RTS (1) Use RTS */ #define LQ_FLAG_USE_RTS_POS 0 #define LQ_FLAG_USE_RTS_MSK (1 << LQ_FLAG_USE_RTS_POS) /* Bit 1-3: LQ command color. Used to match responses to LQ commands */ #define LQ_FLAG_COLOR_POS 1 #define LQ_FLAG_COLOR_MSK (7 << LQ_FLAG_COLOR_POS) #define LQ_FLAG_COLOR_GET(_f) (((_f) & LQ_FLAG_COLOR_MSK) >>\ LQ_FLAG_COLOR_POS) #define LQ_FLAGS_COLOR_INC(_c) ((((_c) + 1) << LQ_FLAG_COLOR_POS) &\ LQ_FLAG_COLOR_MSK) #define LQ_FLAG_COLOR_SET(_f, _c) ((_c) | ((_f) & ~LQ_FLAG_COLOR_MSK)) /* Bit 4-5: Tx RTS BW Signalling * (0) No RTS BW signalling * (1) Static BW signalling * (2) Dynamic BW signalling */ #define LQ_FLAG_RTS_BW_SIG_POS 4 #define LQ_FLAG_RTS_BW_SIG_NONE (0 << LQ_FLAG_RTS_BW_SIG_POS) #define LQ_FLAG_RTS_BW_SIG_STATIC (1 << LQ_FLAG_RTS_BW_SIG_POS) #define LQ_FLAG_RTS_BW_SIG_DYNAMIC (2 << LQ_FLAG_RTS_BW_SIG_POS) /* Bit 6: (0) No dynamic BW selection (1) Allow dynamic BW selection * Dyanmic BW selection allows Tx with narrower BW then requested in rates */ #define LQ_FLAG_DYNAMIC_BW_POS 6 #define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS) /* Single Stream Tx Parameters (lq_cmd->ss_params) * Flags to control a smart FW decision about whether BFER/STBC/SISO will be * used for single stream Tx. */ /* Bit 0-1: Max STBC streams allowed. Can be 0-3. * (0) - No STBC allowed * (1) - 2x1 STBC allowed (HT/VHT) * (2) - 4x2 STBC allowed (HT/VHT) * (3) - 3x2 STBC allowed (HT only) * All our chips are at most 2 antennas so only (1) is valid for now. */ #define LQ_SS_STBC_ALLOWED_POS 0 #define LQ_SS_STBC_ALLOWED_MSK (3 << LQ_SS_STBC_ALLOWED_MSK) /* 2x1 STBC is allowed */ #define LQ_SS_STBC_1SS_ALLOWED (1 << LQ_SS_STBC_ALLOWED_POS) /* Bit 2: Beamformer (VHT only) is allowed */ #define LQ_SS_BFER_ALLOWED_POS 2 #define LQ_SS_BFER_ALLOWED (1 << LQ_SS_BFER_ALLOWED_POS) /* Bit 3: Force BFER or STBC for testing * If this is set: * If BFER is allowed then force the ucode to choose BFER else * If STBC is allowed then force the ucode to choose STBC over SISO */ #define LQ_SS_FORCE_POS 3 #define LQ_SS_FORCE (1 << LQ_SS_FORCE_POS) /* Bit 31: ss_params field is valid. Used for FW backward compatibility * with other drivers which don't support the ss_params API yet */ #define LQ_SS_PARAMS_VALID_POS 31 #define LQ_SS_PARAMS_VALID (1 << LQ_SS_PARAMS_VALID_POS) struct iwl_rs_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ u8 plcp_ht_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ u8 plcp_ht_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ u8 plcp_vht_siso; u8 plcp_vht_mimo2; u8 prev_rs; /* previous rate used in rs algo */ u8 next_rs; /* next rate used in rs algo */ }; extern struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT]; #define IWL_RATE_60M_PLCP 3 enum { IWL_RATE_INVM_INDEX = IWL_RATE_COUNT, IWL_RATE_INVALID = IWL_RATE_COUNT, }; #define LINK_QUAL_MAX_RETRY_NUM 16 enum { IWL_RATE_6M_INDEX_TABLE = 0, IWL_RATE_9M_INDEX_TABLE, IWL_RATE_12M_INDEX_TABLE, IWL_RATE_18M_INDEX_TABLE, IWL_RATE_24M_INDEX_TABLE, IWL_RATE_36M_INDEX_TABLE, IWL_RATE_48M_INDEX_TABLE, IWL_RATE_54M_INDEX_TABLE, IWL_RATE_1M_INDEX_TABLE, IWL_RATE_2M_INDEX_TABLE, IWL_RATE_5M_INDEX_TABLE, IWL_RATE_11M_INDEX_TABLE, IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX - 1, }; /* #define vs. enum to keep from defaulting to 'large integer' */ #define IWL_RATE_6M_MASK (1 << IWL_RATE_6M_INDEX) #define IWL_RATE_9M_MASK (1 << IWL_RATE_9M_INDEX) #define IWL_RATE_12M_MASK (1 << IWL_RATE_12M_INDEX) #define IWL_RATE_18M_MASK (1 << IWL_RATE_18M_INDEX) #define IWL_RATE_24M_MASK (1 << IWL_RATE_24M_INDEX) #define IWL_RATE_36M_MASK (1 << IWL_RATE_36M_INDEX) #define IWL_RATE_48M_MASK (1 << IWL_RATE_48M_INDEX) #define IWL_RATE_54M_MASK (1 << IWL_RATE_54M_INDEX) #define IWL_RATE_60M_MASK (1 << IWL_RATE_60M_INDEX) #define IWL_RATE_1M_MASK (1 << IWL_RATE_1M_INDEX) #define IWL_RATE_2M_MASK (1 << IWL_RATE_2M_INDEX) #define IWL_RATE_5M_MASK (1 << IWL_RATE_5M_INDEX) #define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX) /* uCode API values for HT/VHT bit rates */ enum { IWL_RATE_HT_SISO_MCS_0_PLCP = 0, IWL_RATE_HT_SISO_MCS_1_PLCP = 1, IWL_RATE_HT_SISO_MCS_2_PLCP = 2, IWL_RATE_HT_SISO_MCS_3_PLCP = 3, IWL_RATE_HT_SISO_MCS_4_PLCP = 4, IWL_RATE_HT_SISO_MCS_5_PLCP = 5, IWL_RATE_HT_SISO_MCS_6_PLCP = 6, IWL_RATE_HT_SISO_MCS_7_PLCP = 7, IWL_RATE_HT_MIMO2_MCS_0_PLCP = 0x8, IWL_RATE_HT_MIMO2_MCS_1_PLCP = 0x9, IWL_RATE_HT_MIMO2_MCS_2_PLCP = 0xA, IWL_RATE_HT_MIMO2_MCS_3_PLCP = 0xB, IWL_RATE_HT_MIMO2_MCS_4_PLCP = 0xC, IWL_RATE_HT_MIMO2_MCS_5_PLCP = 0xD, IWL_RATE_HT_MIMO2_MCS_6_PLCP = 0xE, IWL_RATE_HT_MIMO2_MCS_7_PLCP = 0xF, IWL_RATE_VHT_SISO_MCS_0_PLCP = 0, IWL_RATE_VHT_SISO_MCS_1_PLCP = 1, IWL_RATE_VHT_SISO_MCS_2_PLCP = 2, IWL_RATE_VHT_SISO_MCS_3_PLCP = 3, IWL_RATE_VHT_SISO_MCS_4_PLCP = 4, IWL_RATE_VHT_SISO_MCS_5_PLCP = 5, IWL_RATE_VHT_SISO_MCS_6_PLCP = 6, IWL_RATE_VHT_SISO_MCS_7_PLCP = 7, IWL_RATE_VHT_SISO_MCS_8_PLCP = 8, IWL_RATE_VHT_SISO_MCS_9_PLCP = 9, IWL_RATE_VHT_MIMO2_MCS_0_PLCP = 0x10, IWL_RATE_VHT_MIMO2_MCS_1_PLCP = 0x11, IWL_RATE_VHT_MIMO2_MCS_2_PLCP = 0x12, IWL_RATE_VHT_MIMO2_MCS_3_PLCP = 0x13, IWL_RATE_VHT_MIMO2_MCS_4_PLCP = 0x14, IWL_RATE_VHT_MIMO2_MCS_5_PLCP = 0x15, IWL_RATE_VHT_MIMO2_MCS_6_PLCP = 0x16, IWL_RATE_VHT_MIMO2_MCS_7_PLCP = 0x17, IWL_RATE_VHT_MIMO2_MCS_8_PLCP = 0x18, IWL_RATE_VHT_MIMO2_MCS_9_PLCP = 0x19, IWL_RATE_HT_SISO_MCS_INV_PLCP, IWL_RATE_HT_MIMO2_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, IWL_RATE_VHT_SISO_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, IWL_RATE_VHT_MIMO2_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, IWL_RATE_HT_SISO_MCS_8_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, IWL_RATE_HT_SISO_MCS_9_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, IWL_RATE_HT_MIMO2_MCS_8_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, IWL_RATE_HT_MIMO2_MCS_9_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP, }; #define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1) #define IWL_INVALID_VALUE 0xff #define TPC_MAX_REDUCTION 15 #define TPC_NO_REDUCTION 0 #define TPC_INVALID 0xff #define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63) #define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63) /* * FIXME - various places in firmware API still use u8, * e.g. LQ command and SCD config command. * This should be 256 instead. */ #define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF (255) #define LINK_QUAL_AGG_FRAME_LIMIT_GEN2_MAX (255) #define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0) #define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ /* load per tid defines for A-MPDU activation */ #define IWL_AGG_TPT_THREHOLD 0 #define IWL_AGG_ALL_TID 0xff enum iwl_table_type { LQ_NONE, LQ_LEGACY_G, /* legacy types */ LQ_LEGACY_A, LQ_HT_SISO, /* HT types */ LQ_HT_MIMO2, LQ_VHT_SISO, /* VHT types */ LQ_VHT_MIMO2, LQ_HE_SISO, /* HE types */ LQ_HE_MIMO2, LQ_MAX, }; struct rs_rate { int index; enum iwl_table_type type; u8 ant; u32 bw; bool sgi; bool ldpc; bool stbc; bool bfer; }; #define is_type_legacy(type) (((type) == LQ_LEGACY_G) || \ ((type) == LQ_LEGACY_A)) #define is_type_ht_siso(type) ((type) == LQ_HT_SISO) #define is_type_ht_mimo2(type) ((type) == LQ_HT_MIMO2) #define is_type_vht_siso(type) ((type) == LQ_VHT_SISO) #define is_type_vht_mimo2(type) ((type) == LQ_VHT_MIMO2) #define is_type_he_siso(type) ((type) == LQ_HE_SISO) #define is_type_he_mimo2(type) ((type) == LQ_HE_MIMO2) #define is_type_siso(type) (is_type_ht_siso(type) || is_type_vht_siso(type) || \ is_type_he_siso(type)) #define is_type_mimo2(type) (is_type_ht_mimo2(type) || \ is_type_vht_mimo2(type) || is_type_he_mimo2(type)) #define is_type_mimo(type) (is_type_mimo2(type)) #define is_type_ht(type) (is_type_ht_siso(type) || is_type_ht_mimo2(type)) #define is_type_vht(type) (is_type_vht_siso(type) || is_type_vht_mimo2(type)) #define is_type_he(type) (is_type_he_siso(type) || is_type_he_mimo2(type)) #define is_type_a_band(type) ((type) == LQ_LEGACY_A) #define is_type_g_band(type) ((type) == LQ_LEGACY_G) #define is_legacy(rate) is_type_legacy((rate)->type) #define is_ht_siso(rate) is_type_ht_siso((rate)->type) #define is_ht_mimo2(rate) is_type_ht_mimo2((rate)->type) #define is_vht_siso(rate) is_type_vht_siso((rate)->type) #define is_vht_mimo2(rate) is_type_vht_mimo2((rate)->type) #define is_siso(rate) is_type_siso((rate)->type) #define is_mimo2(rate) is_type_mimo2((rate)->type) #define is_mimo(rate) is_type_mimo((rate)->type) #define is_ht(rate) is_type_ht((rate)->type) #define is_vht(rate) is_type_vht((rate)->type) #define is_he(rate) is_type_he((rate)->type) #define is_a_band(rate) is_type_a_band((rate)->type) #define is_g_band(rate) is_type_g_band((rate)->type) #define is_ht20(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_20) #define is_ht40(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_40) #define is_ht80(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_80) #define is_ht160(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_160) #define IWL_MAX_MCS_DISPLAY_SIZE 12 struct iwl_rate_mcs_info { char mbps[IWL_MAX_MCS_DISPLAY_SIZE]; char mcs[IWL_MAX_MCS_DISPLAY_SIZE]; }; /** * struct iwl_lq_sta_rs_fw - rate and related statistics for RS in FW * @last_rate_n_flags: last rate reported by FW * @sta_id: the id of the station #ifdef CONFIG_MAC80211_DEBUGFS * @dbg_fixed_rate: for debug, use fixed rate if not 0 * @dbg_agg_frame_count_lim: for debug, max number of frames in A-MPDU #endif * @chains: bitmask of chains reported in %chain_signal * @chain_signal: per chain signal strength * @last_rssi: last rssi reported * @drv: pointer back to the driver data */ struct iwl_lq_sta_rs_fw { /* last tx rate_n_flags */ u32 last_rate_n_flags; /* persistent fields - initialized only once - keep last! */ struct lq_sta_pers_rs_fw { u32 sta_id; u8 chains; s8 chain_signal[4]; s8 last_rssi; struct iwm_softc *drv; } pers; }; /** * struct iwl_rate_scale_data -- tx success history for one rate */ struct iwl_rate_scale_data { u64 data; /* bitmap of successful frames */ s32 success_counter; /* number of frames successful */ s32 success_ratio; /* per-cent * 128 */ s32 counter; /* number of frames attempted */ s32 average_tpt; /* success ratio * expected throughput */ }; /* Possible Tx columns * Tx Column = a combo of legacy/siso/mimo x antenna x SGI */ enum rs_column { RS_COLUMN_LEGACY_ANT_A = 0, RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_SISO_ANT_A, RS_COLUMN_SISO_ANT_B, RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_MIMO2, RS_COLUMN_MIMO2_SGI, RS_COLUMN_LAST = RS_COLUMN_MIMO2_SGI, RS_COLUMN_COUNT = RS_COLUMN_LAST + 1, RS_COLUMN_INVALID, }; enum rs_ss_force_opt { RS_SS_FORCE_NONE = 0, RS_SS_FORCE_STBC, RS_SS_FORCE_BFER, RS_SS_FORCE_SISO, }; /* Packet stats per rate */ struct rs_rate_stats { u64 success; u64 total; }; /** * struct iwl_scale_tbl_info -- tx params and success history for all rates * * There are two of these in struct iwl_lq_sta, * one for "active", and one for "search". */ struct iwl_scale_tbl_info { struct rs_rate rate; enum rs_column column; const u16 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ /* per txpower-reduction history */ struct iwl_rate_scale_data tpc_win[TPC_MAX_REDUCTION + 1]; }; enum { RS_STATE_SEARCH_CYCLE_STARTED, RS_STATE_SEARCH_CYCLE_ENDED, RS_STATE_STAY_IN_COLUMN, }; struct lq_sta_pers { u8 chains; s8 chain_signal[4]; s8 last_rssi; struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; struct iwm_softc *drv; IOSimpleLock *lock; /* for races in reinit/update table */ }; /** * struct iwl_lq_sta -- driver's rate scaling private structure * * Pointer to this gets passed back and forth between driver and mac80211. */ struct iwl_lq_sta { u8 active_tbl; /* index of active table, range 0-1 */ u8 rs_state; /* RS_STATE_* */ u8 search_better_tbl; /* 1: currently trying alternate mode */ s32 last_tpt; /* The following determine when to search for a new mode */ u32 table_count_limit; u32 max_failure_limit; /* # failed frames before new search */ u32 max_success_limit; /* # successful frames before new search */ u32 table_count; u32 total_failed; /* total failed frames, any/all rates */ u32 total_success; /* total successful frames, any/all rates */ u64 flush_timer; /* time staying in mode before new search */ u32 visited_columns; /* Bitmask marking which Tx columns were * explored during a search cycle */ u64 last_tx; bool is_vht; bool ldpc; /* LDPC Rx is supported by the STA */ bool stbc_capable; /* Tx STBC is supported by chip and Rx by STA */ bool bfer_capable; /* Remote supports beamformee and we BFer */ enum nl80211_band band; /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ unsigned long active_legacy_rate; unsigned long active_siso_rate; unsigned long active_mimo2_rate; /* Highest rate per Tx mode */ u8 max_legacy_rate_idx; u8 max_siso_rate_idx; u8 max_mimo2_rate_idx; /* Optimal rate based on RSSI and STA caps. * Used only to reflect link speed to userspace. */ struct rs_rate optimal_rate; unsigned long optimal_rate_mask; const struct rs_init_rate_info *optimal_rates; int optimal_nentries; u8 missed_rate_counter; struct iwm_lq_cmd lq; struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ u8 tx_agg_tid_en; /* last tx rate_n_flags */ u32 last_rate_n_flags; /* packets destined for this STA are aggregated */ u8 is_agg; /* tx power reduce for this sta */ int tpc_reduce; /* persistent fields - initialized only once - keep last! */ struct lq_sta_pers pers; }; /* ieee80211_tx_info's status_driver_data[0] is packed with lq color and txp * Note, it's iwlmvm <-> mac80211 interface. * bits 0-7: reduced tx power * bits 8-10: LQ command's color */ #define RS_DRV_DATA_TXP_MSK 0xff #define RS_DRV_DATA_LQ_COLOR_POS 8 #define RS_DRV_DATA_LQ_COLOR_MSK (7 << RS_DRV_DATA_LQ_COLOR_POS) #define RS_DRV_DATA_LQ_COLOR_GET(_f) (((_f) & RS_DRV_DATA_LQ_COLOR_MSK) >>\ RS_DRV_DATA_LQ_COLOR_POS) #define RS_DRV_DATA_PACK(_c, _p) ((void *)(uintptr_t)\ (((uintptr_t)_p) |\ ((_c) << RS_DRV_DATA_LQ_COLOR_POS))) #define IWL_DECLARE_RATE_INFO(r) \ [IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP /* * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP */ static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(1), IWL_DECLARE_RATE_INFO(2), IWL_DECLARE_RATE_INFO(5), IWL_DECLARE_RATE_INFO(11), IWL_DECLARE_RATE_INFO(6), IWL_DECLARE_RATE_INFO(9), IWL_DECLARE_RATE_INFO(12), IWL_DECLARE_RATE_INFO(18), IWL_DECLARE_RATE_INFO(24), IWL_DECLARE_RATE_INFO(36), IWL_DECLARE_RATE_INFO(48), IWL_DECLARE_RATE_INFO(54), }; #undef IWL_DECLARE_RATE_INFO /* Convert an MCS index into an iwm_rates[] index. */ const int iwm_mcs2ridx[] = { IWL_RATE_6M_INDEX, IWL_RATE_12M_INDEX, IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX, IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX, IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX, IWL_RATE_54M_INDEX, IWL_RATE_54M_INDEX, }; static inline int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, enum nl80211_band band) { int rate = rate_n_flags & RATE_LEGACY_RATE_MSK; int idx; int band_offset = 0; /* Legacy rate format, search for match in table */ if (band != NL80211_BAND_2GHZ) band_offset = IWL_FIRST_OFDM_RATE; for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) if (fw_rate_idx_to_plcp[idx] == rate) return idx - band_offset; return -1; } static inline u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx) { /* Get PLCP rate for tx_cmd->rate_n_flags */ return fw_rate_idx_to_plcp[rate_idx]; } static inline void ieee80211_rate_set_vht(struct ieee80211_tx_rate *rate, u8 mcs, u8 nss) { WARN_ON(mcs & ~0xF); WARN_ON((nss - 1) & ~0x7); rate->idx = ((nss - 1) << 4) | mcs; } static inline void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, enum nl80211_band band, struct ieee80211_tx_rate *r) { if (rate_n_flags & RATE_HT_MCS_GF_MSK) r->flags |= IEEE80211_TX_RC_GREEN_FIELD; switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { case RATE_MCS_CHAN_WIDTH_20: break; case RATE_MCS_CHAN_WIDTH_40: r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; break; case RATE_MCS_CHAN_WIDTH_80: r->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; break; case RATE_MCS_CHAN_WIDTH_160: r->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH; break; } if (rate_n_flags & RATE_MCS_SGI_MSK) r->flags |= IEEE80211_TX_RC_SHORT_GI; if (rate_n_flags & RATE_MCS_HT_MSK) { r->flags |= IEEE80211_TX_RC_MCS; r->idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; } else if (rate_n_flags & RATE_MCS_VHT_MSK) { ieee80211_rate_set_vht( r, rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK, ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >> RATE_VHT_MCS_NSS_POS) + 1); r->flags |= IEEE80211_TX_RC_VHT_MCS; } else { r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, band); } } /* * translate ucode response to mac80211 tx status control values */ static inline void iwl_mvm_hwrate_to_tx_status(u32 rate_n_flags, struct ieee80211_tx_info *info) { struct ieee80211_tx_rate *r = &info->status.rates[0]; info->status.antenna = ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); iwl_mvm_hwrate_to_tx_rate(rate_n_flags, (enum nl80211_band)info->band, r); } int iwl_mvm_send_lq_cmd(struct iwm_softc *sc, struct iwm_lq_cmd *lq); /* Initialize station's rate scaling information after adding station */ void iwl_mvm_rs_rate_init(struct iwm_softc *mvm, struct ieee80211_node *sta, enum nl80211_band band, bool init); /* Notify RS about Tx status */ void iwl_mvm_rs_tx_status(struct iwm_softc *mvm, struct ieee80211_node *sta, int tid, struct ieee80211_tx_info *info, bool ndp); void rs_drv_mac80211_tx_status(struct iwm_softc *sc, struct ieee80211_node *sta, struct ieee80211_tx_info *info, int tid, uint16_t fc, int ssn); void rs_update_last_rssi(struct iwm_softc *mvm, struct ieee80211_rx_status *rx_status); int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate); void rs_drv_rate_update(struct iwm_softc *mvm, struct ieee80211_node *sta, enum nl80211_band band, u32 changed); void *rs_drv_alloc_sta(iwm_softc *sc, struct ieee80211_node *ni); void rs_drv_free_sta(iwm_softc *sc, struct ieee80211_node *ni); void iwm_rs_alloc(struct iwm_softc *sc); void iwm_rs_free(struct iwm_softc *sc); #endif /* rs_hpp */ ================================================ FILE: itlwm/hal_iwm/rx.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" #include void ItlIwm:: iwm_disable_rx_dma(struct iwm_softc *sc) { int ntries; if (iwm_nic_lock(sc)) { if (sc->sc_mqrx_supported) { iwm_write_prph(sc, IWM_RFH_RXF_DMA_CFG, 0); for (ntries = 0; ntries < 1000; ntries++) { if (iwm_read_prph(sc, IWM_RFH_GEN_STATUS) & IWM_RXF_DMA_IDLE) break; DELAY(10); } } else { IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); for (ntries = 0; ntries < 1000; ntries++) { if (IWM_READ(sc, IWM_FH_MEM_RSSR_RX_STATUS_REG)& IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE) break; DELAY(10); } } iwm_nic_unlock(sc); } } void ItlIwm:: iwm_reset_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) { ring->cur = 0; // bus_dmamap_sync(sc->sc_dmat, ring->stat_dma.map, 0, // ring->stat_dma.size, BUS_DMASYNC_PREWRITE); memset(ring->stat, 0, sizeof(*ring->stat)); // bus_dmamap_sync(sc->sc_dmat, ring->stat_dma.map, 0, // ring->stat_dma.size, BUS_DMASYNC_POSTWRITE); } void ItlIwm:: iwm_free_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) { int count, i; iwm_dma_contig_free(&ring->free_desc_dma); iwm_dma_contig_free(&ring->stat_dma); iwm_dma_contig_free(&ring->used_desc_dma); if (sc->sc_mqrx_supported) count = IWM_RX_MQ_RING_COUNT; else count = IWM_RX_RING_COUNT; for (i = 0; i < count; i++) { struct iwm_rx_data *data = &ring->data[i]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } if (data->map != NULL) { bus_dmamap_destroy(sc->sc_dmat, data->map); data->map = NULL; } } } int ItlIwm:: iwm_alloc_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring) { bus_size_t size; size_t descsz; int count, i, err; ring->cur = 0; if (sc->sc_mqrx_supported) { count = IWM_RX_MQ_RING_COUNT; descsz = sizeof(uint64_t); } else { count = IWM_RX_RING_COUNT; descsz = sizeof(uint32_t); } /* Allocate RX descriptors (256-byte aligned). */ size = count * descsz; err = iwm_dma_contig_alloc(sc->sc_dmat, &ring->free_desc_dma, size, 256); if (err) { XYLog("%s: could not allocate RX ring DMA memory\n", DEVNAME(sc)); goto fail; } ring->desc = ring->free_desc_dma.vaddr; /* Allocate RX status area (16-byte aligned). */ err = iwm_dma_contig_alloc(sc->sc_dmat, &ring->stat_dma, sizeof(*ring->stat), 16); if (err) { XYLog("%s: could not allocate RX status DMA memory\n", DEVNAME(sc)); goto fail; } ring->stat = (struct iwm_rb_status *)ring->stat_dma.vaddr; if (sc->sc_mqrx_supported) { size = count * sizeof(uint32_t); err = iwm_dma_contig_alloc(sc->sc_dmat, &ring->used_desc_dma, size, 256); if (err) { XYLog("%s: could not allocate RX ring DMA memory\n", DEVNAME(sc)); goto fail; } } for (i = 0; i < count; i++) { struct iwm_rx_data *data = &ring->data[i]; memset(data, 0, sizeof(*data)); err = bus_dmamap_create(sc->sc_dmat, IWM_RBUF_SIZE, 1, IWM_RBUF_SIZE, 0, BUS_DMA_NOWAIT, &data->map); if (err) { XYLog("%s: could not create RX buf DMA map\n", DEVNAME(sc)); goto fail; } err = iwm_rx_addbuf(sc, IWM_RBUF_SIZE, i); if (err) goto fail; } return 0; fail: iwm_free_rx_ring(sc, ring); return err; } int ItlIwm:: iwm_rx_addbuf(struct iwm_softc *sc, int size, int idx) { struct iwm_rx_ring *ring = &sc->rxq; struct iwm_rx_data *data = &ring->data[idx]; mbuf_t m; int err; int fatal = 0; unsigned int maxChunks = 1; IOPhysicalSegment seg; // mbuf_allocpacket(MBUF_WAITOK, size, NULL, &m); m = getController()->allocatePacket(size); // if (m == NULL) { XYLog("%s allocatePacket==NULL\n", __FUNCTION__); return ENOMEM; } // mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &m); // if (m == NULL) // return ENOBUFS; // // if (size <= MCLBYTES) { // mbuf_mclget(MBUF_DONTWAIT, MT_DATA, &m); // } else { // mbuf_getcluster(MBUF_DONTWAIT, MT_DATA, IWM_RBUF_SIZE, &m); // } // if ((mbuf_flags(m) & MBUF_EXT) == 0) { // mbuf_freem(m); // return ENOBUFS; // } // // if (data->m != NULL) { // // bus_dmamap_unload(sc->sc_dmat, data->map); // fatal = 1; // } // mbuf_setlen(m, size); // mbuf_pkthdr_setlen(m, size); // m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; // err = bus_dmamap_load(data->map, m); data->map->dm_nsegs = data->map->cursor->getPhysicalSegments(m, &seg, 1); // XYLog("map rx dm_nsegs=%d\n", data->map->dm_nsegs); if (data->map->dm_nsegs == 0) { XYLog("RX Map new address FAIL!!!!\n"); /* XXX */ if (fatal) panic("iwm: could not load RX mbuf"); mbuf_freem(m); return ENOMEM; } data->m = m; // bus_dmamap_sync(sc->sc_dmat, data->map, 0, size, BUS_DMASYNC_PREREAD); /* Update RX descriptor. */ if (sc->sc_mqrx_supported) { ((uint64_t *)ring->desc)[idx] = htole64(seg.location); // bus_dmamap_sync(sc->sc_dmat, ring->free_desc_dma.map, // idx * sizeof(uint64_t), sizeof(uint64_t), // BUS_DMASYNC_PREWRITE); } else { ((uint32_t *)ring->desc)[idx] = htole32(seg.location >> 8); // bus_dmamap_sync(sc->sc_dmat, ring->free_desc_dma.map, // idx * sizeof(uint32_t), sizeof(uint32_t), // BUS_DMASYNC_PREWRITE); } return 0; } void ItlIwm:: iwm_rx_rx_phy_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_rx_data *data) { struct iwm_rx_phy_info *phy_info = (struct iwm_rx_phy_info *)pkt->data; // bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*pkt), // sizeof(*phy_info), BUS_DMASYNC_POSTREAD); memcpy(&sc->sc_last_phy_info, phy_info, sizeof(sc->sc_last_phy_info)); } void ItlIwm:: iwm_rx_mpdu(struct iwm_softc *sc, mbuf_t m, void *pktdata, size_t maxlen, struct mbuf_list *ml) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_rxinfo rxi; struct ieee80211_rx_status rx_status; struct iwm_rx_phy_info *phy_info; struct iwm_rx_mpdu_res_start *rx_res; int device_timestamp; uint16_t phy_flags; uint32_t len; uint32_t rx_pkt_status; int rssi, chanidx, rate_n_flags; memset(&rxi, 0, sizeof(rxi)); memset(&rx_status, 0, sizeof(struct ieee80211_rx_status)); phy_info = &sc->sc_last_phy_info; rx_res = (struct iwm_rx_mpdu_res_start *)pktdata; len = le16toh(rx_res->byte_count); if (ic->ic_opmode == IEEE80211_M_MONITOR) { /* Allow control frames in monitor mode. */ if (len < sizeof(struct ieee80211_frame_cts)) { ic->ic_stats.is_rx_tooshort++; IC2IFP(ic)->netStat->inputErrors++; mbuf_freem(m); return; } } else if (len < sizeof(struct ieee80211_frame)) { ic->ic_stats.is_rx_tooshort++; IC2IFP(ic)->netStat->inputErrors++; mbuf_freem(m); return; } if (len > maxlen - sizeof(*rx_res)) { IC2IFP(ic)->netStat->inputErrors++; mbuf_freem(m); return; } if (phy_info->cfg_phy_cnt > 20) { mbuf_freem(m); return; } rx_pkt_status = le32toh(*(uint32_t *)((uint8_t*)pktdata + sizeof(*rx_res) + len)); if (!(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_CRC_OK) || !(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_OVERRUN_OK)) { mbuf_freem(m); return; /* drop */ } // m->m_data = pktdata + sizeof(*rx_res); // m->m_pkthdr.len = m->m_len = len; mbuf_setdata(m, ((uint8_t*)pktdata + sizeof(*rx_res)), len); mbuf_pkthdr_setlen(m, len); mbuf_setlen(m, len); if (iwm_rx_hwdecrypt(sc, m, rx_pkt_status, &rxi)) { mbuf_freem(m); return; } chanidx = letoh32(phy_info->channel); device_timestamp = le32toh(phy_info->system_timestamp); phy_flags = letoh16(phy_info->phy_flags); rate_n_flags = le32toh(phy_info->rate_n_flags); rssi = iwm_get_signal_strength(sc, &rx_status, phy_info); rs_update_last_rssi(sc, &rx_status); rssi = (0 - IWM_MIN_DBM) + rssi; /* normalize */ rssi = MIN(rssi, ic->ic_max_rssi); /* clip to max. 100% */ rxi.rxi_rssi = rssi; rxi.rxi_tstamp = device_timestamp; rxi.rxi_chan = chanidx; iwm_rx_frame(sc, m, chanidx, rx_pkt_status, (phy_flags & IWM_PHY_INFO_FLAG_SHPREAMBLE), rate_n_flags, device_timestamp, &rxi, ml); } void ItlIwm:: iwm_flip_address(uint8_t *addr) { int i; uint8_t mac_addr[ETHER_ADDR_LEN]; for (i = 0; i < ETHER_ADDR_LEN; i++) mac_addr[i] = addr[ETHER_ADDR_LEN - i - 1]; IEEE80211_ADDR_COPY(addr, mac_addr); } /* * Drop duplicate 802.11 retransmissions * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") * and handle pseudo-duplicate frames which result from deaggregation * of A-MSDU frames in hardware. */ int ItlIwm:: iwm_detect_duplicate(struct iwm_softc *sc, mbuf_t m, struct iwm_rx_mpdu_desc *desc, struct ieee80211_rxinfo *rxi) { struct ieee80211com *ic = &sc->sc_ic; struct iwm_node *in = (struct iwm_node *)ic->ic_bss; struct iwm_rxq_dup_data *dup_data = &in->dup_data; uint8_t tid = IWM_MAX_TID_COUNT, subframe_idx; struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); uint8_t type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; int hasqos = ieee80211_has_qos(wh); uint16_t seq; if (type == IEEE80211_FC0_TYPE_CTL || (hasqos && (subtype & IEEE80211_FC0_SUBTYPE_NODATA)) || IEEE80211_IS_MULTICAST(wh->i_addr1)) return 0; if (hasqos) { tid = (ieee80211_get_qos(wh) & IEEE80211_QOS_TID); if (tid > IWM_MAX_TID_COUNT) tid = IWM_MAX_TID_COUNT; } /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */ subframe_idx = desc->amsdu_info & IWM_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; seq = letoh16(*(u_int16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT; if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && dup_data->last_seq[tid] == seq && dup_data->last_sub_frame[tid] >= subframe_idx) return 1; /* * Allow the same frame sequence number for all A-MSDU subframes * following the first subframe. * Otherwise these subframes would be discarded as replays. */ if (dup_data->last_seq[tid] == seq && subframe_idx > dup_data->last_sub_frame[tid] && (desc->mac_flags2 & IWM_RX_MPDU_MFLG2_AMSDU)) { rxi->rxi_flags |= IEEE80211_RXI_SAME_SEQ; } dup_data->last_seq[tid] = seq; dup_data->last_sub_frame[tid] = subframe_idx; return 0; } /* * Returns true if sn2 - buffer_size < sn1 < sn2. * To be used only in order to compare reorder buffer head with NSSN. * We fully trust NSSN unless it is behind us due to reorder timeout. * Reorder timeout can only bring us up to buffer_size SNs ahead of NSSN. */ int ItlIwm:: iwm_is_sn_less(uint16_t sn1, uint16_t sn2, uint16_t buffer_size) { return SEQ_LT(sn1, sn2) && !SEQ_LT(sn1, sn2 - buffer_size); } void ItlIwm:: iwm_release_frames(struct iwm_softc *sc, struct ieee80211_node *ni, struct iwm_rxba_data *rxba, struct iwm_reorder_buffer *reorder_buf, uint16_t nssn, struct mbuf_list *ml) { struct iwm_reorder_buf_entry *entries = &rxba->entries[0]; uint16_t ssn = reorder_buf->head_sn; /* ignore nssn smaller than head sn - this can happen due to timeout */ if (iwm_is_sn_less(nssn, ssn, reorder_buf->buf_size)) goto set_timer; while (iwm_is_sn_less(ssn, nssn, reorder_buf->buf_size)) { int index = ssn % reorder_buf->buf_size; mbuf_t m; int chanidx, is_shortpre; uint32_t rx_pkt_status, rate_n_flags, device_timestamp; struct ieee80211_rxinfo *rxi; /* This data is the same for all A-MSDU subframes. */ chanidx = entries[index].chanidx; rx_pkt_status = entries[index].rx_pkt_status; is_shortpre = entries[index].is_shortpre; rate_n_flags = entries[index].rate_n_flags; device_timestamp = entries[index].device_timestamp; rxi = &entries[index].rxi; /* * Empty the list. Will have more than one frame for A-MSDU. * Empty list is valid as well since nssn indicates frames were * received. */ while ((m = ml_dequeue(&entries[index].frames)) != NULL) { iwm_rx_frame(sc, m, chanidx, rx_pkt_status, is_shortpre, rate_n_flags, device_timestamp, rxi, ml); reorder_buf->num_stored--; /* * Allow the same frame sequence number and CCMP PN for * all A-MSDU subframes following the first subframe. * Otherwise they would be discarded as replays. */ rxi->rxi_flags |= IEEE80211_RXI_SAME_SEQ; rxi->rxi_flags |= IEEE80211_RXI_HWDEC_SAME_PN; } ssn = (ssn + 1) & 0xfff; } reorder_buf->head_sn = nssn; set_timer: if (reorder_buf->num_stored && !reorder_buf->removed) { timeout_add_usec(&reorder_buf->reorder_timer, RX_REORDER_BUF_TIMEOUT_MQ_USEC); } else timeout_del(&reorder_buf->reorder_timer); } int ItlIwm:: iwm_oldsn_workaround(struct iwm_softc *sc, struct ieee80211_node *ni, int tid, struct iwm_reorder_buffer *buffer, uint32_t reorder_data, uint32_t gp2) { struct ieee80211com *ic = &sc->sc_ic; if (gp2 != buffer->consec_oldsn_ampdu_gp2) { /* we have a new (A-)MPDU ... */ /* * reset counter to 0 if we didn't have any oldsn in * the last A-MPDU (as detected by GP2 being identical) */ if (!buffer->consec_oldsn_prev_drop) buffer->consec_oldsn_drops = 0; /* either way, update our tracking state */ buffer->consec_oldsn_ampdu_gp2 = gp2; } else if (buffer->consec_oldsn_prev_drop) { /* * tracking state didn't change, and we had an old SN * indication before - do nothing in this case, we * already noted this one down and are waiting for the * next A-MPDU (by GP2) */ return 0; } /* return unless this MPDU has old SN */ if (!(reorder_data & IWM_RX_MPDU_REORDER_BA_OLD_SN)) return 0; /* update state */ buffer->consec_oldsn_prev_drop = 1; buffer->consec_oldsn_drops++; /* if limit is reached, send del BA and reset state */ if (buffer->consec_oldsn_drops == IWM_AMPDU_CONSEC_DROPS_DELBA) { XYLog("reached %d old SN frames, stopping BA session on TID %d\n", IWM_AMPDU_CONSEC_DROPS_DELBA, tid); ieee80211_delba_request(ic, ni, IEEE80211_REASON_UNSPECIFIED, 0, tid); buffer->consec_oldsn_prev_drop = 0; buffer->consec_oldsn_drops = 0; return 1; } return 0; } /* * Handle re-ordering of frames which were de-aggregated in hardware. * Returns 1 if the MPDU was consumed (buffered or dropped). * Returns 0 if the MPDU should be passed to upper layer. */ int ItlIwm:: iwm_rx_reorder(struct iwm_softc *sc, mbuf_t m, int chanidx, struct iwm_rx_mpdu_desc *desc, int is_shortpre, int rate_n_flags, uint32_t device_timestamp, struct ieee80211_rxinfo *rxi, struct mbuf_list *ml) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_frame *wh; struct ieee80211_node *ni; struct iwm_rxba_data *rxba; struct iwm_reorder_buffer *buffer; uint32_t reorder_data = le32toh(desc->reorder_data); int is_amsdu = (desc->mac_flags2 & IWM_RX_MPDU_MFLG2_AMSDU); int last_subframe = (desc->amsdu_info & IWM_RX_MPDU_AMSDU_LAST_SUBFRAME); uint8_t tid; uint8_t subframe_idx = (desc->amsdu_info & IWM_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK); struct iwm_reorder_buf_entry *entries; int index; uint16_t nssn, sn; uint8_t baid, type, subtype; int hasqos; wh = mtod(m, struct ieee80211_frame *); hasqos = ieee80211_has_qos(wh); tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; /* * We are only interested in Block Ack requests and unicast QoS data. */ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) return 0; if (hasqos) { if (subtype & IEEE80211_FC0_SUBTYPE_NODATA) return 0; } else { if (type != IEEE80211_FC0_TYPE_CTL || subtype != IEEE80211_FC0_SUBTYPE_BAR) return 0; } baid = (reorder_data & IWM_RX_MPDU_REORDER_BAID_MASK) >> IWM_RX_MPDU_REORDER_BAID_SHIFT; if (baid == IWM_RX_REORDER_DATA_INVALID_BAID || baid >= nitems(sc->sc_rxba_data)) return 0; rxba = &sc->sc_rxba_data[baid]; if (rxba->reorder_buf.buf_size == 0 || tid != rxba->tid || rxba->sta_id != IWM_STATION_ID) return 0; if (rxba->timeout != 0) getmicrouptime(&rxba->last_rx); /* Bypass A-MPDU re-ordering in net80211. */ rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE; nssn = reorder_data & IWM_RX_MPDU_REORDER_NSSN_MASK; sn = (reorder_data & IWM_RX_MPDU_REORDER_SN_MASK) >> IWM_RX_MPDU_REORDER_SN_SHIFT; buffer = &rxba->reorder_buf; entries = &rxba->entries[0]; if (!buffer->valid) { if (reorder_data & IWM_RX_MPDU_REORDER_BA_OLD_SN) return 0; buffer->valid = 1; } ni = ieee80211_find_rxnode(ic, wh); if (type == IEEE80211_FC0_TYPE_CTL && subtype == IEEE80211_FC0_SUBTYPE_BAR) { iwm_release_frames(sc, ni, rxba, buffer, nssn, ml); goto drop; } /* * If there was a significant jump in the nssn - adjust. * If the SN is smaller than the NSSN it might need to first go into * the reorder buffer, in which case we just release up to it and the * rest of the function will take care of storing it and releasing up to * the nssn. */ if (!iwm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size, buffer->buf_size) || !SEQ_LT(sn, buffer->head_sn + buffer->buf_size)) { uint16_t min_sn = SEQ_LT(sn, nssn) ? sn : nssn; ic->ic_stats.is_ht_rx_frame_above_ba_winend++; iwm_release_frames(sc, ni, rxba, buffer, min_sn, ml); } if (iwm_oldsn_workaround(sc, ni, tid, buffer, reorder_data, device_timestamp)) { /* BA session will be torn down. */ ic->ic_stats.is_ht_rx_ba_window_jump++; goto drop; } /* drop any outdated packets */ if (SEQ_LT(sn, buffer->head_sn)) { ic->ic_stats.is_ht_rx_frame_below_ba_winstart++; goto drop; } /* release immediately if allowed by nssn and no stored frames */ if (!buffer->num_stored && SEQ_LT(sn, nssn)) { if (iwm_is_sn_less(buffer->head_sn, nssn, buffer->buf_size) && (!is_amsdu || last_subframe)) buffer->head_sn = nssn; ieee80211_release_node(ic, ni); return 0; } /* * release immediately if there are no stored frames, and the sn is * equal to the head. * This can happen due to reorder timer, where NSSN is behind head_sn. * When we released everything, and we got the next frame in the * sequence, according to the NSSN we can't release immediately, * while technically there is no hole and we can move forward. */ if (!buffer->num_stored && sn == buffer->head_sn) { if (!is_amsdu || last_subframe) buffer->head_sn = (buffer->head_sn + 1) & 0xfff; ieee80211_release_node(ic, ni); return 0; } index = sn % buffer->buf_size; /* * Check if we already stored this frame * As AMSDU is either received or not as whole, logic is simple: * If we have frames in that position in the buffer and the last frame * originated from AMSDU had a different SN then it is a retransmission. * If it is the same SN then if the subframe index is incrementing it * is the same AMSDU - otherwise it is a retransmission. */ if (!ml_empty(&entries[index].frames)) { if (!is_amsdu) { ic->ic_stats.is_ht_rx_ba_no_buf++; goto drop; } else if (sn != buffer->last_amsdu || buffer->last_sub_index >= subframe_idx) { ic->ic_stats.is_ht_rx_ba_no_buf++; goto drop; } } else { /* This data is the same for all A-MSDU subframes. */ entries[index].chanidx = chanidx; entries[index].is_shortpre = is_shortpre; entries[index].rate_n_flags = rate_n_flags; entries[index].device_timestamp = device_timestamp; memcpy(&entries[index].rxi, rxi, sizeof(entries[index].rxi)); } /* put in reorder buffer */ ml_enqueue(&entries[index].frames, m); buffer->num_stored++; getmicrouptime(&entries[index].reorder_time); if (is_amsdu) { buffer->last_amsdu = sn; buffer->last_sub_index = subframe_idx; } /* * We cannot trust NSSN for AMSDU sub-frames that are not the last. * The reason is that NSSN advances on the first sub-frame, and may * cause the reorder buffer to advance before all the sub-frames arrive. * Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with * SN 1. NSSN for first sub frame will be 3 with the result of driver * releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is * already ahead and it will be dropped. * If the last sub-frame is not on this queue - we will get frame * release notification with up to date NSSN. */ if (!is_amsdu || last_subframe) iwm_release_frames(sc, ni, rxba, buffer, nssn, ml); ieee80211_release_node(ic, ni); return 1; drop: mbuf_freem(m); ieee80211_release_node(ic, ni); return 1; } void ItlIwm:: iwm_rx_mpdu_mq(struct iwm_softc *sc, mbuf_t m, void *pktdata, size_t maxlen, struct mbuf_list *ml) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_rxinfo rxi; struct ieee80211_rx_status rx_status; struct iwm_rx_mpdu_desc *desc; uint32_t len, hdrlen, rate_n_flags, device_timestamp; int rssi; uint8_t chanidx; uint16_t phy_info; memset(&rxi, 0, sizeof(rxi)); memset(&rx_status, 0, sizeof(struct ieee80211_rx_status)); desc = (struct iwm_rx_mpdu_desc *)pktdata; if (!(desc->status & htole16(IWM_RX_MPDU_RES_STATUS_CRC_OK)) || !(desc->status & htole16(IWM_RX_MPDU_RES_STATUS_OVERRUN_OK))) { mbuf_freem(m); return; /* drop */ } len = le16toh(desc->mpdu_len); if (ic->ic_opmode == IEEE80211_M_MONITOR) { /* Allow control frames in monitor mode. */ if (len < sizeof(struct ieee80211_frame_cts)) { ic->ic_stats.is_rx_tooshort++; IC2IFP(ic)->netStat->inputErrors++; mbuf_freem(m); return; } } else if (len < sizeof(struct ieee80211_frame)) { ic->ic_stats.is_rx_tooshort++; IC2IFP(ic)->netStat->inputErrors++; mbuf_freem(m); return; } if (len > maxlen - sizeof(*desc)) { IC2IFP(ic)->netStat->inputErrors++; mbuf_freem(m); return; } // m->m_data = pktdata + sizeof(*desc); // m->m_pkthdr.len = m->m_len = len; mbuf_setdata(m, (uint8_t*)pktdata + sizeof(*desc), len); mbuf_pkthdr_setlen(m, len); mbuf_setlen(m, len); /* Account for padding following the frame header. */ if (desc->mac_flags2 & IWM_RX_MPDU_MFLG2_PAD) { struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; if (type == IEEE80211_FC0_TYPE_CTL) { switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { case IEEE80211_FC0_SUBTYPE_CTS: hdrlen = sizeof(struct ieee80211_frame_cts); break; case IEEE80211_FC0_SUBTYPE_ACK: hdrlen = sizeof(struct ieee80211_frame_ack); break; default: hdrlen = sizeof(struct ieee80211_frame_min); break; } } else hdrlen = ieee80211_get_hdrlen(wh); if ((le16toh(desc->status) & IWM_RX_MPDU_RES_STATUS_SEC_ENC_MSK) == IWM_RX_MPDU_RES_STATUS_SEC_CCM_ENC) { /* Padding is inserted after the IV. */ hdrlen += IEEE80211_CCMP_HDRLEN; } memmove((uint8_t*)mbuf_data(m) + 2, mbuf_data(m), hdrlen); mbuf_adj(m, 2); } /* * Hardware de-aggregates A-MSDUs and copies the same MAC header * in place for each subframe. But it leaves the 'A-MSDU present' * bit set in the frame header. We need to clear this bit ourselves. * * And we must allow the same CCMP PN for subframes following the * first subframe. Otherwise they would be discarded as replays. */ if (desc->mac_flags2 & IWM_RX_MPDU_MFLG2_AMSDU) { struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); uint8_t subframe_idx = (desc->amsdu_info & IWM_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK); if (subframe_idx > 0) rxi.rxi_flags |= IEEE80211_RXI_HWDEC_SAME_PN; if (ieee80211_has_qos(wh) && ieee80211_has_addr4(wh) && mbuf_len(m) >= sizeof(struct ieee80211_qosframe_addr4)) { struct ieee80211_qosframe_addr4 *qwh4 = mtod(m, struct ieee80211_qosframe_addr4 *); qwh4->i_qos[0] &= htole16(~IEEE80211_QOS_AMSDU); /* HW reverses addr3 and addr4. */ iwm_flip_address(qwh4->i_addr3); iwm_flip_address(qwh4->i_addr4); } else if (ieee80211_has_qos(wh) && mbuf_len(m) >= sizeof(struct ieee80211_qosframe)) { struct ieee80211_qosframe *qwh = mtod(m, struct ieee80211_qosframe *); qwh->i_qos[0] &= htole16(~IEEE80211_QOS_AMSDU); /* HW reverses addr3. */ iwm_flip_address(qwh->i_addr3); } } /* * Verify decryption before duplicate detection. The latter uses * the TID supplied in QoS frame headers and this TID is implicitly * verified as part of the CCMP nonce. */ if (iwm_rx_hwdecrypt(sc, m, le16toh(desc->status), &rxi)) { mbuf_freem(m); return; } if (iwm_detect_duplicate(sc, m, desc, &rxi)) { mbuf_freem(m); return; } phy_info = le16toh(desc->phy_info); rate_n_flags = le32toh(desc->v1.rate_n_flags); chanidx = desc->v1.channel; device_timestamp = desc->v1.gp2_on_air_rise; rssi = iwm_rxmq_get_signal_strength(sc, &rx_status, rate_n_flags, desc); rs_update_last_rssi(sc, &rx_status); rssi = (0 - IWM_MIN_DBM) + rssi; /* normalize */ rssi = MIN(rssi, ic->ic_max_rssi); /* clip to max. 100% */ rxi.rxi_rssi = rssi; rxi.rxi_tstamp = le64toh(desc->v1.tsf_on_air_rise); rxi.rxi_chan = chanidx; if (iwm_rx_reorder(sc, m, chanidx, desc, (phy_info & IWM_RX_MPDU_PHY_SHORT_PREAMBLE), rate_n_flags, device_timestamp, &rxi, ml)) return; iwm_rx_frame(sc, m, chanidx, le16toh(desc->status), (phy_info & IWM_RX_MPDU_PHY_SHORT_PREAMBLE), rate_n_flags, device_timestamp, &rxi, ml); } int ItlIwm:: iwm_rx_pkt_valid(struct iwm_rx_packet *pkt) { int qid, idx, code; qid = pkt->hdr.qid & ~0x80; idx = pkt->hdr.idx; code = IWM_WIDE_ID(pkt->hdr.flags, pkt->hdr.code); return (!(qid == 0 && idx == 0 && code == 0) && pkt->len_n_flags != htole32(IWM_FH_RSCSR_FRAME_INVALID)); } #define SYNC_RESP_STRUCT(_var_, _pkt_, t) \ do { \ bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*(_pkt_)), \ sizeof(*(_var_)), BUS_DMASYNC_POSTREAD); \ _var_ = (t)((_pkt_)+1); \ } while (/*CONSTCOND*/0) void ItlIwm:: iwm_rx_pkt(struct iwm_softc *sc, struct iwm_rx_data *data, struct mbuf_list *ml) { struct _ifnet *ifp = IC2IFP(&sc->sc_ic); struct iwm_rx_packet *pkt, *nextpkt; uint32_t offset = 0, nextoff = 0, nmpdu = 0, len; mbuf_t m0, m = NULL; const size_t minsz = sizeof(pkt->len_n_flags) + sizeof(pkt->hdr); int qid, idx, code, handled = 1; // bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE, // BUS_DMASYNC_POSTREAD); m0 = data->m; while (m0 && offset + minsz < IWM_RBUF_SIZE) { pkt = (struct iwm_rx_packet *)((uint8_t*)mbuf_data(m0) + offset); qid = pkt->hdr.qid; idx = pkt->hdr.idx; code = IWM_WIDE_ID(pkt->hdr.flags, pkt->hdr.code); if (!iwm_rx_pkt_valid(pkt)) break; len = sizeof(pkt->len_n_flags) + iwm_rx_packet_len(pkt); if (len < minsz || len > (IWM_RBUF_SIZE - offset)) break; if (code == IWM_REPLY_RX_MPDU_CMD && ++nmpdu == 1) { /* Take mbuf m0 off the RX ring. */ if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur)) { ifp->netStat->inputErrors++; break; } // KASSERT(data->m != m0, "data->m != m0"); } switch (code) { case IWM_REPLY_RX_PHY_CMD: iwm_rx_rx_phy_cmd(sc, pkt, data); break; case IWM_REPLY_RX_MPDU_CMD: { size_t maxlen = IWM_RBUF_SIZE - offset - minsz; nextoff = offset + roundup(len, IWM_FH_RSCSR_FRAME_ALIGN); nextpkt = (struct iwm_rx_packet *) ((uint8_t*)mbuf_data(m0) + nextoff); if (nextoff + minsz >= IWM_RBUF_SIZE || !iwm_rx_pkt_valid(nextpkt)) { /* No need to copy last frame in buffer. */ if (offset > 0) mbuf_adj(m0, offset); if (sc->sc_mqrx_supported) iwm_rx_mpdu_mq(sc, m0, pkt->data, maxlen, ml); else iwm_rx_mpdu(sc, m0, pkt->data, maxlen, ml); m0 = NULL; /* stack owns m0 now; abort loop */ } else { /* * Create an mbuf which points to the current * packet. Always copy from offset zero to * preserve m_pkthdr. */ mbuf_copym(m0, 0, MBUF_COPYALL, MBUF_DONTWAIT, &m); // m = m_copym(m0, 0, M_COPYALL, M_DONTWAIT); if (m == NULL) { ifp->netStat->inputErrors++; mbuf_freem(m0); m0 = NULL; break; } mbuf_adj(m, offset); if (sc->sc_mqrx_supported) iwm_rx_mpdu_mq(sc, m, pkt->data, maxlen, ml); else iwm_rx_mpdu(sc, m, pkt->data, maxlen, ml); } break; } case IWM_TX_CMD: iwm_rx_tx_cmd(sc, pkt, data); break; case IWM_BA_NOTIF: iwm_rx_tx_ba_notif(sc, pkt, data); break; case IWM_MISSED_BEACONS_NOTIFICATION: iwm_rx_bmiss(sc, pkt, data); break; case IWM_MFUART_LOAD_NOTIFICATION: break; case IWM_ALIVE: { struct iwm_alive_resp_v1 *resp1; struct iwm_alive_resp_v2 *resp2; struct iwm_alive_resp_v3 *resp3; // XYLog("%s: firmware alive, size=%d\n", __FUNCTION__, iwm_rx_packet_payload_len(pkt)); if (iwm_rx_packet_payload_len(pkt) == sizeof(*resp1)) { SYNC_RESP_STRUCT(resp1, pkt, struct iwm_alive_resp_v1 *); sc->sc_uc.uc_error_event_table = le32toh(resp1->error_event_table_ptr); sc->sc_uc.uc_log_event_table = le32toh(resp1->log_event_table_ptr); sc->sched_base = le32toh(resp1->scd_base_ptr); if (resp1->status == IWM_ALIVE_STATUS_OK) sc->sc_uc.uc_ok = 1; else sc->sc_uc.uc_ok = 0; } if (iwm_rx_packet_payload_len(pkt) == sizeof(*resp2)) { SYNC_RESP_STRUCT(resp2, pkt, struct iwm_alive_resp_v2 *); sc->sc_uc.uc_error_event_table = le32toh(resp2->error_event_table_ptr); sc->sc_uc.uc_log_event_table = le32toh(resp2->log_event_table_ptr); sc->sched_base = le32toh(resp2->scd_base_ptr); sc->sc_uc.uc_umac_error_event_table = le32toh(resp2->error_info_addr); if (resp2->status == IWM_ALIVE_STATUS_OK) sc->sc_uc.uc_ok = 1; else sc->sc_uc.uc_ok = 0; } if (iwm_rx_packet_payload_len(pkt) == sizeof(*resp3)) { SYNC_RESP_STRUCT(resp3, pkt, struct iwm_alive_resp_v3 *); sc->sc_uc.uc_error_event_table = le32toh(resp3->error_event_table_ptr); sc->sc_uc.uc_log_event_table = le32toh(resp3->log_event_table_ptr); sc->sched_base = le32toh(resp3->scd_base_ptr); sc->sc_uc.uc_umac_error_event_table = le32toh(resp3->error_info_addr); if (resp3->status == IWM_ALIVE_STATUS_OK) sc->sc_uc.uc_ok = 1; else sc->sc_uc.uc_ok = 0; } sc->sc_uc.uc_intr = 1; wakeupOn(&sc->sc_uc); break; } case IWM_CALIB_RES_NOTIF_PHY_DB: { struct iwm_calib_res_notif_phy_db *phy_db_notif; SYNC_RESP_STRUCT(phy_db_notif, pkt, struct iwm_calib_res_notif_phy_db *); iwm_phy_db_set_section(sc, phy_db_notif); sc->sc_init_complete |= IWM_CALIB_COMPLETE; // wakeupOn(&sc->sc_init_complete); break; } case IWM_STATISTICS_NOTIFICATION: { struct iwm_notif_statistics *stats; SYNC_RESP_STRUCT(stats, pkt, struct iwm_notif_statistics *); memcpy(&sc->sc_stats, stats, sizeof(sc->sc_stats)); sc->sc_noise = iwm_get_noise(&stats->rx.general); break; } case IWM_MCC_CHUB_UPDATE_CMD: { struct iwm_mcc_chub_notif *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwm_mcc_chub_notif *); iwm_mcc_update(sc, notif); break; } case IWM_DTS_MEASUREMENT_NOTIFICATION: case IWM_WIDE_ID(IWM_PHY_OPS_GROUP, IWM_DTS_MEASUREMENT_NOTIF_WIDE): case IWM_WIDE_ID(IWM_PHY_OPS_GROUP, IWM_TEMP_REPORTING_THRESHOLDS_CMD): break; case IWM_WIDE_ID(IWM_PHY_OPS_GROUP, IWM_CT_KILL_NOTIFICATION): { struct iwm_ct_kill_notif *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwm_ct_kill_notif *); XYLog("%s: device at critical temperature (%u degC), " "stopping device\n", DEVNAME(sc), le16toh(notif->temperature)); sc->sc_flags |= IWM_FLAG_HW_ERR; task_add(systq, &sc->init_task); break; } case IWM_ADD_STA_KEY: case IWM_PHY_CONFIGURATION_CMD: case IWM_TX_ANT_CONFIGURATION_CMD: case IWM_ADD_STA: case IWM_MAC_CONTEXT_CMD: case IWM_REPLY_SF_CFG_CMD: case IWM_POWER_TABLE_CMD: case IWM_LTR_CONFIG: case IWM_PHY_CONTEXT_CMD: case IWM_BINDING_CONTEXT_CMD: case IWM_WIDE_ID(IWM_LONG_GROUP, IWM_SCAN_CFG_CMD): case IWM_WIDE_ID(IWM_LONG_GROUP, IWM_SCAN_REQ_UMAC): case IWM_WIDE_ID(IWM_LONG_GROUP, IWM_SCAN_ABORT_UMAC): case IWM_SCAN_OFFLOAD_REQUEST_CMD: case IWM_SCAN_OFFLOAD_ABORT_CMD: case IWM_REPLY_BEACON_FILTERING_CMD: case IWM_MAC_PM_POWER_TABLE: case IWM_TIME_QUOTA_CMD: case IWM_REMOVE_STA: case IWM_TXPATH_FLUSH: case IWM_LQ_CMD: case IWM_WIDE_ID(IWM_LONG_GROUP, IWM_FW_PAGING_BLOCK_CMD): case IWM_BT_CONFIG: case IWM_REPLY_THERMAL_MNG_BACKOFF: case IWM_NVM_ACCESS_CMD: case IWM_MCC_UPDATE_CMD: case IWM_TIME_EVENT_CMD: { size_t pkt_len; if (sc->sc_cmd_resp_pkt[idx] == NULL) break; // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // sizeof(*pkt), BUS_DMASYNC_POSTREAD); pkt_len = sizeof(pkt->len_n_flags) + iwm_rx_packet_len(pkt); if ((pkt->hdr.flags & IWM_CMD_FAILED_MSK) || pkt_len < sizeof(*pkt) || pkt_len > sc->sc_cmd_resp_len[idx]) { ::free(sc->sc_cmd_resp_pkt[idx]); sc->sc_cmd_resp_pkt[idx] = NULL; break; } // bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*pkt), // pkt_len - sizeof(*pkt), BUS_DMASYNC_POSTREAD); memcpy(sc->sc_cmd_resp_pkt[idx], pkt, pkt_len); break; } /* ignore */ case IWM_PHY_DB_CMD: break; case IWM_INIT_COMPLETE_NOTIF: sc->sc_init_complete |= IWM_INIT_COMPLETE; wakeupOn(&sc->sc_init_complete); break; case IWM_SCAN_OFFLOAD_COMPLETE: { struct iwm_periodic_scan_complete *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwm_periodic_scan_complete *); break; } case IWM_SCAN_ITERATION_COMPLETE: { struct iwm_lmac_scan_complete_notif *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwm_lmac_scan_complete_notif *); iwm_endscan(sc); break; } case IWM_SCAN_COMPLETE_UMAC: { struct iwm_umac_scan_complete *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwm_umac_scan_complete *); iwm_endscan(sc); break; } case IWM_SCAN_ITERATION_COMPLETE_UMAC: { struct iwm_umac_scan_iter_complete_notif *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwm_umac_scan_iter_complete_notif *); iwm_endscan(sc); break; } case IWM_REPLY_ERROR: { struct iwm_error_resp *resp; SYNC_RESP_STRUCT(resp, pkt, struct iwm_error_resp *); XYLog("%s: firmware error 0x%x, cmd 0x%x\n", DEVNAME(sc), le32toh(resp->error_type), resp->cmd_id); break; } case IWM_TIME_EVENT_NOTIFICATION: { struct iwm_time_event_notif *notif; uint32_t action; SYNC_RESP_STRUCT(notif, pkt, struct iwm_time_event_notif *); if (sc->sc_time_event_uid != le32toh(notif->unique_id)) break; action = le32toh(notif->action); if (action & IWM_TE_V2_NOTIF_HOST_EVENT_END) sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE; break; } case IWM_WIDE_ID(IWM_SYSTEM_GROUP, IWM_FSEQ_VER_MISMATCH_NOTIFICATION): break; /* * Firmware versions 21 and 22 generate some DEBUG_LOG_MSG * messages. Just ignore them for now. */ case IWM_DEBUG_LOG_MSG: break; case IWM_MCAST_FILTER_CMD: break; case IWM_SCD_QUEUE_CFG: { struct iwm_scd_txq_cfg_rsp *rsp; SYNC_RESP_STRUCT(rsp, pkt, struct iwm_scd_txq_cfg_rsp *); break; } case IWM_WIDE_ID(IWM_DATA_PATH_GROUP, IWM_DQA_ENABLE_CMD): break; case IWM_WIDE_ID(IWM_SYSTEM_GROUP, IWM_SOC_CONFIGURATION_CMD): break; default: handled = 0; XYLog("%s: unhandled firmware response 0x%x/0x%x " "rx ring %d[%d]\n", DEVNAME(sc), code, pkt->len_n_flags, (qid & ~0x80), idx); break; } /* * uCode sets bit 0x80 when it originates the notification, * i.e. when the notification is not a direct response to a * command sent by the driver. * For example, uCode issues IWM_REPLY_RX when it sends a * received frame to the driver. */ if (handled && !(qid & (1 << 7))) { iwm_cmd_done(sc, qid, idx, code); } offset += roundup(len, IWM_FH_RSCSR_FRAME_ALIGN); } if (m0 && m0 != data->m && mbuf_type(m0) != MBUF_TYPE_FREE) { mbuf_freem(m0); } } ================================================ FILE: itlwm/hal_iwm/scan.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" #include "rs.h" uint16_t ItlIwm:: iwm_scan_rx_chain(struct iwm_softc *sc) { uint16_t rx_chain; uint8_t rx_ant; rx_ant = iwm_fw_valid_rx_ant(sc); rx_chain = rx_ant << IWM_PHY_RX_CHAIN_VALID_POS; rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_SEL_POS; rx_chain |= 0x1 << IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS; return htole16(rx_chain); } uint32_t ItlIwm:: iwm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck) { uint32_t tx_ant; int i, ind; for (i = 0, ind = sc->sc_scan_last_antenna; i < IWM_RATE_MCS_ANT_NUM; i++) { ind = (ind + 1) % IWM_RATE_MCS_ANT_NUM; if (iwm_fw_valid_tx_ant(sc) & (1 << ind)) { sc->sc_scan_last_antenna = ind; break; } } tx_ant = (1 << sc->sc_scan_last_antenna) << IWM_RATE_MCS_ANT_POS; if ((flags & IEEE80211_CHAN_2GHZ) && !no_cck) return htole32(IWL_RATE_1M_PLCP | RATE_MCS_CCK_MSK | tx_ant); else return htole32(IWL_RATE_6M_PLCP | tx_ant); } uint8_t ItlIwm:: iwm_lmac_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_channel_cfg_lmac *chan, int n_ssids, int bgscan) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_channel *c; uint8_t nchan; for (nchan = 0, c = &ic->ic_channels[1]; c <= &ic->ic_channels[IEEE80211_CHAN_MAX] && nchan < sc->sc_capa_n_scan_channels; c++) { if (c->ic_flags == 0) continue; chan->channel_num = htole16(ieee80211_mhz2ieee(c->ic_freq, 0)); chan->iter_count = htole16(1); chan->iter_interval = 0; chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL); if (n_ssids != 0 && !bgscan) chan->flags |= htole32(1 << 1); /* select SSID 0 */ chan++; nchan++; } return nchan; } uint8_t ItlIwm:: iwm_umac_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_channel_cfg_umac *chan, int n_ssids, int bgscan) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_channel *c; uint8_t nchan; for (nchan = 0, c = &ic->ic_channels[1]; c <= &ic->ic_channels[IEEE80211_CHAN_MAX] && nchan < sc->sc_capa_n_scan_channels; c++) { if (c->ic_flags == 0) continue; chan->channel_num = ieee80211_mhz2ieee(c->ic_freq, 0); chan->iter_count = 1; chan->iter_interval = htole16(0); if (n_ssids != 0 && !bgscan) chan->flags = htole32(1 << 0); /* select SSID 0 */ chan++; nchan++; } return nchan; } int ItlIwm:: iwm_fill_probe_req_v1(struct iwm_softc *sc, struct iwm_scan_probe_req_v1 *preq1) { struct iwm_scan_probe_req preq2; int err, i; err = iwm_fill_probe_req(sc, &preq2); if (err) return err; preq1->mac_header = preq2.mac_header; for (i = 0; i < nitems(preq1->band_data); i++) preq1->band_data[i] = preq2.band_data[i]; preq1->common_data = preq2.common_data; memcpy(preq1->buf, preq2.buf, sizeof(preq1->buf)); return 0; } int ItlIwm:: iwm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req *preq) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf; struct ieee80211_rateset *rs; size_t remain = sizeof(preq->buf); uint8_t *frm, *pos; memset(preq, 0, sizeof(*preq)); if (remain < sizeof(*wh) + 2) return ENOBUFS; /* * Build a probe request frame. Most of the following code is a * copy & paste of what is done in net80211. */ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; // IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl)); IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr); *(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */ *(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */ frm = (uint8_t *)(wh + 1); *frm++ = IEEE80211_ELEMID_SSID; *frm++ = 0; /* hardware inserts SSID */ /* Tell firmware where the MAC header and SSID IE are. */ preq->mac_header.offset = 0; preq->mac_header.len = htole16(frm - (uint8_t *)wh); remain -= frm - (uint8_t *)wh; /* Fill in 2GHz IEs and tell firmware where they are. */ rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; if (rs->rs_nrates > IEEE80211_RATE_SIZE) { if (remain < 4 + rs->rs_nrates) return ENOBUFS; } else if (remain < 2 + rs->rs_nrates) return ENOBUFS; preq->band_data[0].offset = htole16(frm - (uint8_t *)wh); pos = frm; frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); remain -= frm - pos; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)) { if (remain < 3) return ENOBUFS; *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = 0; remain -= 3; } preq->band_data[0].len = htole16(frm - pos); if (sc->sc_nvm.sku_cap_band_52GHz_enable) { /* Fill in 5GHz IEs. */ rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; if (rs->rs_nrates > IEEE80211_RATE_SIZE) { if (remain < 4 + rs->rs_nrates) return ENOBUFS; } else if (remain < 2 + rs->rs_nrates) return ENOBUFS; preq->band_data[1].offset = htole16(frm - (uint8_t *)wh); pos = frm; frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); preq->band_data[1].len = htole16(frm - pos); remain -= frm - pos; if (ic->ic_flags & IEEE80211_F_VHTON) { if (remain < sizeof(struct ieee80211_ie_vhtcap)) return ENOBUFS; frm = ieee80211_add_vhtcaps(frm, ic); remain -= frm - pos; } } /* Send 11n IEs on both 2GHz and 5GHz bands. */ preq->common_data.offset = htole16(frm - (uint8_t *)wh); pos = frm; if (ic->ic_flags & IEEE80211_F_HTON) { if (remain < sizeof(struct ieee80211_ie_htcap)) return ENOBUFS; frm = ieee80211_add_htcaps(frm, ic); /* XXX add WME info? */ } preq->common_data.len = htole16(frm - pos); return 0; } int ItlIwm:: iwm_lmac_scan(struct iwm_softc *sc, int bgscan) { struct ieee80211com *ic = &sc->sc_ic; struct iwm_host_cmd hcmd = { .id = IWM_SCAN_OFFLOAD_REQUEST_CMD, .len = { 0, }, .data = { NULL, }, .flags = 0, }; struct iwm_scan_req_lmac *req; struct iwm_scan_probe_req_v1 *preq; size_t req_len; int err, async = bgscan; req_len = sizeof(struct iwm_scan_req_lmac) + (sizeof(struct iwm_scan_channel_cfg_lmac) * sc->sc_capa_n_scan_channels) + sizeof(struct iwm_scan_probe_req_v1); if (req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ENOMEM; req = (struct iwm_scan_req_lmac*)malloc(req_len, M_DEVBUF, M_NOWAIT); if (req == NULL) return ENOMEM; bzero(req, req_len); hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; hcmd.flags |= async ? IWM_CMD_ASYNC : 0; /* These timings correspond to iwlwifi's UNASSOC scan. */ req->active_dwell = 10; req->passive_dwell = 110; req->fragmented_dwell = 44; req->extended_dwell = 90; if (bgscan) { req->max_out_time = htole32(120); req->suspend_time = htole32(120); } else { req->max_out_time = htole32(0); req->suspend_time = htole32(0); } req->scan_prio = htole32(IWM_SCAN_PRIORITY_HIGH); req->rx_chain_select = iwm_scan_rx_chain(sc); req->iter_num = htole32(1); req->delay = 0; req->scan_flags = htole32(IWM_LMAC_SCAN_FLAG_PASS_ALL | IWM_LMAC_SCAN_FLAG_ITER_COMPLETE | IWM_LMAC_SCAN_FLAG_EXTENDED_DWELL); if (ic->ic_des_esslen == 0) req->scan_flags |= htole32(IWM_LMAC_SCAN_FLAG_PASSIVE); else req->scan_flags |= htole32(IWM_LMAC_SCAN_FLAG_PRE_CONNECTION); if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT) && isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)) req->scan_flags |= htole32(IWM_LMAC_SCAN_FLAGS_RRM_ENABLED); req->flags = htole32(IWM_PHY_BAND_24); if (sc->sc_nvm.sku_cap_band_52GHz_enable) req->flags |= htole32(IWM_PHY_BAND_5); req->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP | IWM_MAC_FILTER_IN_BEACON); /* Tx flags 2 GHz. */ req->tx_cmd[0].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL | IWM_TX_CMD_FLG_BT_DIS); req->tx_cmd[0].rate_n_flags = iwm_scan_rate_n_flags(sc, IEEE80211_CHAN_2GHZ, 1/*XXX*/); req->tx_cmd[0].sta_id = IWM_AUX_STA_ID; /* Tx flags 5 GHz. */ req->tx_cmd[1].tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL | IWM_TX_CMD_FLG_BT_DIS); req->tx_cmd[1].rate_n_flags = iwm_scan_rate_n_flags(sc, IEEE80211_CHAN_5GHZ, 1/*XXX*/); req->tx_cmd[1].sta_id = IWM_AUX_STA_ID; /* Check if we're doing an active directed scan. */ if (ic->ic_des_esslen != 0) { req->direct_scan[0].id = IEEE80211_ELEMID_SSID; req->direct_scan[0].len = ic->ic_des_esslen; memcpy(req->direct_scan[0].ssid, ic->ic_des_essid, ic->ic_des_esslen); } req->n_channels = iwm_lmac_scan_fill_channels(sc, (struct iwm_scan_channel_cfg_lmac *)req->data, ic->ic_des_esslen != 0, bgscan); preq = (struct iwm_scan_probe_req_v1 *)(req->data + (sizeof(struct iwm_scan_channel_cfg_lmac) * sc->sc_capa_n_scan_channels)); err = iwm_fill_probe_req_v1(sc, preq); if (err) { ::free(req); return err; } /* Specify the scan plan: We'll do one iteration. */ req->schedule[0].iterations = 1; req->schedule[0].full_scan_mul = 1; /* Disable EBS. */ req->channel_opt[0].non_ebs_ratio = 1; req->channel_opt[1].non_ebs_ratio = 1; err = iwm_send_cmd(sc, &hcmd); ::free(req); return err; } int ItlIwm:: iwm_config_umac_scan(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwm_scan_config *scan_config; int err, nchan; size_t cmd_size; struct ieee80211_channel *c; struct iwm_host_cmd hcmd = { .id = iwm_cmd_id(IWM_SCAN_CFG_CMD, IWM_LONG_GROUP, 0), .flags = 0, }; static const uint32_t rates = (IWM_SCAN_CONFIG_RATE_1M | IWM_SCAN_CONFIG_RATE_2M | IWM_SCAN_CONFIG_RATE_5M | IWM_SCAN_CONFIG_RATE_11M | IWM_SCAN_CONFIG_RATE_6M | IWM_SCAN_CONFIG_RATE_9M | IWM_SCAN_CONFIG_RATE_12M | IWM_SCAN_CONFIG_RATE_18M | IWM_SCAN_CONFIG_RATE_24M | IWM_SCAN_CONFIG_RATE_36M | IWM_SCAN_CONFIG_RATE_48M | IWM_SCAN_CONFIG_RATE_54M); cmd_size = sizeof(*scan_config) + sc->sc_capa_n_scan_channels; scan_config = (struct iwm_scan_config*)malloc(cmd_size, M_DEVBUF, M_WAIT); if (scan_config == NULL) return ENOMEM; bzero(scan_config, cmd_size); scan_config->tx_chains = htole32(iwm_fw_valid_tx_ant(sc)); scan_config->rx_chains = htole32(iwm_fw_valid_rx_ant(sc)); scan_config->legacy_rates = htole32(rates | IWM_SCAN_CONFIG_SUPPORTED_RATE(rates)); /* These timings correspond to iwlwifi's UNASSOC scan. */ scan_config->dwell_active = 10; scan_config->dwell_passive = 110; scan_config->dwell_fragmented = 44; scan_config->dwell_extended = 90; scan_config->out_of_channel_time = htole32(0); scan_config->suspend_time = htole32(0); IEEE80211_ADDR_COPY(scan_config->mac_addr, sc->sc_ic.ic_myaddr); scan_config->bcast_sta_id = IWM_AUX_STA_ID; scan_config->channel_flags = 0; for (c = &ic->ic_channels[1], nchan = 0; c <= &ic->ic_channels[IEEE80211_CHAN_MAX] && nchan < sc->sc_capa_n_scan_channels; c++) { if (c->ic_flags == 0) continue; scan_config->channel_array[nchan++] = ieee80211_mhz2ieee(c->ic_freq, 0); } scan_config->flags = htole32(IWM_SCAN_CONFIG_FLAG_ACTIVATE | IWM_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | IWM_SCAN_CONFIG_FLAG_SET_TX_CHAINS | IWM_SCAN_CONFIG_FLAG_SET_RX_CHAINS | IWM_SCAN_CONFIG_FLAG_SET_AUX_STA_ID | IWM_SCAN_CONFIG_FLAG_SET_ALL_TIMES | IWM_SCAN_CONFIG_FLAG_SET_LEGACY_RATES | IWM_SCAN_CONFIG_FLAG_SET_MAC_ADDR | IWM_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| IWM_SCAN_CONFIG_N_CHANNELS(nchan) | IWM_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED); hcmd.data[0] = scan_config; hcmd.len[0] = cmd_size; err = iwm_send_cmd(sc, &hcmd); ::free(scan_config); return err; } int ItlIwm:: iwm_umac_scan_size(struct iwm_softc *sc) { int base_size = IWM_SCAN_REQ_UMAC_SIZE_V1; int tail_size; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) base_size = IWM_SCAN_REQ_UMAC_SIZE_V8; else if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) base_size = IWM_SCAN_REQ_UMAC_SIZE_V7; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_SCAN_EXT_CHAN_VER)) tail_size = sizeof(struct iwm_scan_req_umac_tail_v2); else tail_size = sizeof(struct iwm_scan_req_umac_tail_v1); return base_size + sizeof(struct iwm_scan_channel_cfg_umac) * sc->sc_capa_n_scan_channels + tail_size; } struct iwm_scan_umac_chan_param *ItlIwm:: iwm_get_scan_req_umac_chan_param(struct iwm_softc *sc, struct iwm_scan_req_umac *req) { if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) return &req->v8.channel; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) return &req->v7.channel; return &req->v1.channel; } void *ItlIwm:: iwm_get_scan_req_umac_data(struct iwm_softc *sc, struct iwm_scan_req_umac *req) { if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) return (void *)&req->v8.data; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) return (void *)&req->v7.data; return (void *)&req->v1.data; } /* adaptive dwell max budget time [TU] for full scan */ #define IWM_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300 /* adaptive dwell max budget time [TU] for directed scan */ #define IWM_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN 100 /* adaptive dwell default high band APs number */ #define IWM_SCAN_ADWELL_DEFAULT_HB_N_APS 8 /* adaptive dwell default low band APs number */ #define IWM_SCAN_ADWELL_DEFAULT_LB_N_APS 2 /* adaptive dwell default APs number in social channels (1, 6, 11) */ #define IWM_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 10 int ItlIwm:: iwm_umac_scan(struct iwm_softc *sc, int bgscan) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwm_host_cmd hcmd = { .id = iwm_cmd_id(IWM_SCAN_REQ_UMAC, IWM_LONG_GROUP, 0), .len = { 0, }, .data = { NULL, }, .flags = 0, }; struct iwm_scan_req_umac *req; void *cmd_data, *tail_data; struct iwm_scan_req_umac_tail_v2 *tail; struct iwm_scan_req_umac_tail_v1 *tailv1; struct iwm_scan_umac_chan_param *chanparam; size_t req_len; int err, async = bgscan; req_len = iwm_umac_scan_size(sc); if ((req_len < IWM_SCAN_REQ_UMAC_SIZE_V1 + sizeof(struct iwm_scan_req_umac_tail_v1)) || req_len > IWM_MAX_CMD_PAYLOAD_SIZE) return ERANGE; req = (struct iwm_scan_req_umac*)malloc(req_len, M_DEVBUF, M_NOWAIT); if (req == NULL) return ENOMEM; bzero(req, req_len); hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; hcmd.flags |= async ? IWM_CMD_ASYNC : 0; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) { req->v7.adwell_default_n_aps_social = IWM_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; req->v7.adwell_default_n_aps = IWM_SCAN_ADWELL_DEFAULT_LB_N_APS; if (ic->ic_des_esslen != 0) req->v7.adwell_max_budget = htole16(IWM_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); else req->v7.adwell_max_budget = htole16(IWM_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); req->v7.scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH); req->v7.max_out_time[IWM_SCAN_LB_LMAC_IDX] = 0; req->v7.suspend_time[IWM_SCAN_LB_LMAC_IDX] = 0; if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) { req->v8.active_dwell[IWM_SCAN_LB_LMAC_IDX] = 10; req->v8.passive_dwell[IWM_SCAN_LB_LMAC_IDX] = 110; } else { req->v7.active_dwell = 10; req->v7.passive_dwell = 110; req->v7.fragmented_dwell = 44; } } else { /* These timings correspond to iwlwifi's UNASSOC scan. */ req->v1.active_dwell = 10; req->v1.passive_dwell = 110; req->v1.fragmented_dwell = 44; req->v1.extended_dwell = 90; req->v1.scan_priority = htole32(IWM_SCAN_PRIORITY_HIGH); } if (bgscan) { const uint32_t timeout = htole32(120); if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) { req->v8.max_out_time[IWM_SCAN_LB_LMAC_IDX] = timeout; req->v8.suspend_time[IWM_SCAN_LB_LMAC_IDX] = timeout; } else if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) { req->v7.max_out_time[IWM_SCAN_LB_LMAC_IDX] = timeout; req->v7.suspend_time[IWM_SCAN_LB_LMAC_IDX] = timeout; } else { req->v1.max_out_time = timeout; req->v1.suspend_time = timeout; } } req->ooc_priority = htole32(IWM_SCAN_PRIORITY_HIGH); cmd_data = iwm_get_scan_req_umac_data(sc, req); chanparam = iwm_get_scan_req_umac_chan_param(sc, req); chanparam->count = iwm_umac_scan_fill_channels(sc, (struct iwm_scan_channel_cfg_umac *)cmd_data, ic->ic_des_esslen != 0, bgscan); chanparam->flags = 0; tail_data = (uint8_t*)cmd_data + sizeof(struct iwm_scan_channel_cfg_umac) * sc->sc_capa_n_scan_channels; tail = (struct iwm_scan_req_umac_tail_v2*)((uint8_t*)tail_data); /* tail v1 layout differs in preq and direct_scan member fields. */ tailv1 = (struct iwm_scan_req_umac_tail_v1*)((uint8_t*)tail_data); req->general_flags = htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASS_ALL | IWM_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE); if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) { req->v8.general_flags2 = IWM_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER; } /* Check if we're doing an active directed scan. */ if (ic->ic_des_esslen != 0) { if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_SCAN_EXT_CHAN_VER)) { tail->direct_scan[0].id = IEEE80211_ELEMID_SSID; tail->direct_scan[0].len = ic->ic_des_esslen; memcpy(tail->direct_scan[0].ssid, ic->ic_des_essid, ic->ic_des_esslen); } else { tailv1->direct_scan[0].id = IEEE80211_ELEMID_SSID; tailv1->direct_scan[0].len = ic->ic_des_esslen; memcpy(tailv1->direct_scan[0].ssid, ic->ic_des_essid, ic->ic_des_esslen); } req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT); } else req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_PASSIVE); if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT) && isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)) req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED); if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_ADAPTIVE_DWELL)) { req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL); } else { req->general_flags |= htole32(IWM_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL); } if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_SCAN_EXT_CHAN_VER)) err = iwm_fill_probe_req(sc, &tail->preq); else err = iwm_fill_probe_req_v1(sc, &tailv1->preq); if (err) { ::free(req); return err; } /* Specify the scan plan: We'll do one iteration. */ tail->schedule[0].interval = 0; tail->schedule[0].iter_count = 1; err = iwm_send_cmd(sc, &hcmd); ::free(req); return err; } void ItlIwm:: iwm_mcc_update(struct iwm_softc *sc, struct iwm_mcc_chub_notif *notif) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); snprintf(sc->sc_fw_mcc, sizeof(sc->sc_fw_mcc), "%c%c", (le16toh(notif->mcc) & 0xff00) >> 8, le16toh(notif->mcc) & 0xff); if (sc->sc_fw_mcc_int != notif->mcc && sc->sc_ic.ic_event_handler) { (*sc->sc_ic.ic_event_handler)(&sc->sc_ic, IEEE80211_EVT_COUNTRY_CODE_UPDATE, NULL); } sc->sc_fw_mcc_int = notif->mcc; if (ifp->if_flags & IFF_DEBUG) { DPRINTFN(3, ("%s: firmware has detected regulatory domain '%s' " "(0x%x)\n", DEVNAME(sc), sc->sc_fw_mcc, le16toh(notif->mcc))); } /* TODO: Schedule a task to send MCC_UPDATE_CMD? */ } uint8_t ItlIwm:: iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx) { int i; uint8_t rval; for (i = 0; i < rs->rs_nrates; i++) { rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL); if (rval == ieee80211_std_rateset_11g.rs_rates[ridx]) return rs->rs_rates[i]; } return 0; } void ItlIwm:: iwm_ack_rates(struct iwm_softc *sc, struct iwm_node *in, int *cck_rates, int *ofdm_rates) { struct ieee80211_node *ni = &in->in_ni; struct ieee80211_rateset *rs = &ni->ni_rates; int lowest_present_ofdm = -1; int lowest_present_cck = -1; uint8_t cck = 0; uint8_t ofdm = 0; int i; if (ni->ni_chan == IEEE80211_CHAN_ANYC || IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { for (i = IWL_FIRST_CCK_RATE; i < IWL_FIRST_OFDM_RATE; i++) { if ((iwm_ridx2rate(rs, i) & IEEE80211_RATE_BASIC) == 0) continue; cck |= (1 << i); if (lowest_present_cck == -1 || lowest_present_cck > i) lowest_present_cck = i; } } for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_NON_HT_RATE; i++) { if ((iwm_ridx2rate(rs, i) & IEEE80211_RATE_BASIC) == 0) continue; ofdm |= (1 << (i - IWL_FIRST_OFDM_RATE)); if (lowest_present_ofdm == -1 || lowest_present_ofdm > i) lowest_present_ofdm = i; } /* * Now we've got the basic rates as bitmaps in the ofdm and cck * variables. This isn't sufficient though, as there might not * be all the right rates in the bitmap. E.g. if the only basic * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps * and 6 Mbps because the 802.11-2007 standard says in 9.6: * * [...] a STA responding to a received frame shall transmit * its Control Response frame [...] at the highest rate in the * BSSBasicRateSet parameter that is less than or equal to the * rate of the immediately previous frame in the frame exchange * sequence ([...]) and that is of the same modulation class * ([...]) as the received frame. If no rate contained in the * BSSBasicRateSet parameter meets these conditions, then the * control frame sent in response to a received frame shall be * transmitted at the highest mandatory rate of the PHY that is * less than or equal to the rate of the received frame, and * that is of the same modulation class as the received frame. * * As a consequence, we need to add all mandatory rates that are * lower than all of the basic rates to these bitmaps. */ if (IWL_RATE_24M_INDEX < lowest_present_ofdm) ofdm |= IWL_RATE_BIT_MSK(24) >> IWL_FIRST_OFDM_RATE; if (IWL_RATE_12M_INDEX < lowest_present_ofdm) ofdm |= IWL_RATE_BIT_MSK(12) >> IWL_FIRST_OFDM_RATE; /* 6M already there or needed so always add */ ofdm |= IWL_RATE_BIT_MSK(6) >> IWL_FIRST_OFDM_RATE; /* * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP. * Note, however: * - if no CCK rates are basic, it must be ERP since there must * be some basic rates at all, so they're OFDM => ERP PHY * (or we're in 5 GHz, and the cck bitmap will never be used) * - if 11M is a basic rate, it must be ERP as well, so add 5.5M * - if 5.5M is basic, 1M and 2M are mandatory * - if 2M is basic, 1M is mandatory * - if 1M is basic, that's the only valid ACK rate. * As a consequence, it's not as complicated as it sounds, just add * any lower rates to the ACK rate bitmap. */ if (IWL_RATE_11M_INDEX < lowest_present_cck) cck |= IWL_RATE_BIT_MSK(11) >> IWL_FIRST_CCK_RATE; if (IWL_RATE_5M_INDEX < lowest_present_cck) cck |= IWL_RATE_BIT_MSK(5) >> IWL_FIRST_CCK_RATE; if (IWL_RATE_2M_INDEX < lowest_present_cck) cck |= IWL_RATE_BIT_MSK(2) >> IWL_FIRST_CCK_RATE; /* 1M already there or needed so always add */ cck |= IWL_RATE_BIT_MSK(1) >> IWL_FIRST_CCK_RATE; *cck_rates = cck; *ofdm_rates = ofdm; } int ItlIwm:: iwm_scan(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); int err; if (sc->sc_flags & IWM_FLAG_BGSCAN) { err = iwm_scan_abort(sc); if (err) { XYLog("%s: could not abort background scan\n", DEVNAME(sc)); return err; } } if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) err = iwm_umac_scan(sc, 0); else err = iwm_lmac_scan(sc, 0); if (err && err != 1) { XYLog("%s: %d could not initiate scan, err=%d\n", DEVNAME(sc), __LINE__, err); return err; } /* * The current mode might have been fixed during association. * Ensure all channels get scanned. */ if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); sc->sc_flags |= IWM_FLAG_SCANNING; if (ifp->if_flags & IFF_DEBUG) XYLog("%s: %s -> %s\n", ifp->if_xname, ieee80211_state_name[ic->ic_state], ieee80211_state_name[IEEE80211_S_SCAN]); if ((sc->sc_flags & IWM_FLAG_BGSCAN) == 0) { ieee80211_set_link_state(ic, LINK_STATE_DOWN); ieee80211_node_cleanup(ic, ic->ic_bss); } ic->ic_state = IEEE80211_S_SCAN; iwm_led_blink_start(sc); wakeupOn(&ic->ic_state); /* wake iwm_init() */ return 0; } int ItlIwm:: iwm_bgscan(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwm_softc *sc = (struct iwm_softc *)IC2IFP(ic)->if_softc; ItlIwm *that = container_of(sc, ItlIwm, com); int err; if (sc->sc_flags & IWM_FLAG_SCANNING) return 0; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) err = that->iwm_umac_scan(sc, 1); else err = that->iwm_lmac_scan(sc, 1); if (err && err != 1) { XYLog("%s: could not initiate scan\n", DEVNAME(sc)); return err; } sc->sc_flags |= IWM_FLAG_BGSCAN; return 0; } int ItlIwm:: iwm_umac_scan_abort(struct iwm_softc *sc) { struct iwm_umac_scan_abort cmd = { 0 }; return iwm_send_cmd_pdu(sc, IWM_WIDE_ID(IWM_LONG_GROUP, IWM_SCAN_ABORT_UMAC), 0, sizeof(cmd), &cmd); } int ItlIwm:: iwm_lmac_scan_abort(struct iwm_softc *sc) { struct iwm_host_cmd cmd = { .id = IWM_SCAN_OFFLOAD_ABORT_CMD, }; int err; uint32_t status; err = iwm_send_cmd_status(sc, &cmd, &status); if (err) return err; if (status != IWM_CAN_ABORT_STATUS) { /* * The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before the * microcode has notified us that a scan is completed. */ return EBUSY; } return 0; } int ItlIwm:: iwm_scan_abort(struct iwm_softc *sc) { int err; if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) err = iwm_umac_scan_abort(sc); else err = iwm_lmac_scan_abort(sc); if (err == 0) sc->sc_flags &= ~(IWM_FLAG_SCANNING | IWM_FLAG_BGSCAN); return err; } ================================================ FILE: itlwm/hal_iwm/tx.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" void ItlIwm:: iwm_free_tx_ring(iwm_softc *sc, struct iwm_tx_ring *ring) { int i; iwm_dma_contig_free(&ring->desc_dma); iwm_dma_contig_free(&ring->cmd_dma); for (i = 0; i < IWM_TX_RING_COUNT; i++) { struct iwm_tx_data *data = &ring->data[i]; if (data->m != NULL) { mbuf_freem(data->m); data->m = NULL; } if (data->map != NULL) { bus_dmamap_destroy(sc->sc_dmat, data->map); data->map = NULL; } } } void ItlIwm:: iwm_reset_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring) { int i; for (i = 0; i < IWM_TX_RING_COUNT; i++) { struct iwm_tx_data *data = &ring->data[i]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } } /* Clear TX descriptors. */ memset(ring->desc, 0, ring->desc_dma.size); // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, // ring->desc_dma.size, BUS_DMASYNC_PREWRITE); sc->qfullmsk &= ~(1 << ring->qid); /* 7000 family NICs are locked while commands are in progress. */ if (ring->qid == sc->cmdqid && ring->queued > 0) { if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) iwm_nic_unlock(sc); } ring->queued = 0; ring->cur = 0; ring->tail = 0; } int ItlIwm:: iwm_alloc_tx_ring(iwm_softc *sc, struct iwm_tx_ring *ring, int qid) { bus_addr_t paddr; bus_size_t size; int i, err; int nsegments; ring->qid = qid; ring->queued = 0; ring->cur = 0; ring->tail = 0; /* We are using 10:17 for DQA tx agg */ if (qid > IWM_LAST_AGG_TX_QUEUE) return 0; /* Allocate TX descriptors (256-byte aligned). */ size = IWM_TX_RING_COUNT * sizeof (struct iwm_tfd); err = iwm_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, size, 256); if (err) { XYLog("%s: could not allocate TX ring DMA memory\n", DEVNAME(sc)); goto fail; } ring->desc = (struct iwm_tfd *)ring->desc_dma.vaddr; size = IWM_TX_RING_COUNT * sizeof(struct iwm_device_cmd); err = iwm_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, size, 4); if (err) { XYLog("%s: could not allocate cmd DMA memory\n", DEVNAME(sc)); goto fail; } ring->cmd = (struct iwm_device_cmd*)ring->cmd_dma.vaddr; paddr = ring->cmd_dma.paddr; for (i = 0; i < IWM_TX_RING_COUNT; i++) { struct iwm_tx_data *data = &ring->data[i]; size_t mapsize; data->cmd_paddr = paddr; data->scratch_paddr = paddr + sizeof(struct iwm_cmd_header) + offsetof(struct iwm_tx_cmd, scratch); paddr += sizeof(struct iwm_device_cmd); /* FW commands may require more mapped space than packets. */ if (qid == IWM_CMD_QUEUE || qid == IWM_DQA_CMD_QUEUE) { mapsize = (sizeof(struct iwm_cmd_header) + IWM_MAX_CMD_PAYLOAD_SIZE); nsegments = 1; } else { mapsize = MCLBYTES; nsegments = IWM_NUM_OF_TBS - 2; } err = bus_dmamap_create(sc->sc_dmat, mapsize, nsegments, mapsize, 0, BUS_DMA_NOWAIT, &data->map); if (err) { XYLog("%s: could not create TX buf DMA map\n", DEVNAME(sc)); goto fail; } } KASSERT(paddr == ring->cmd_dma.paddr + size, ""); return 0; fail: iwm_free_tx_ring(sc, ring); return err; } int ItlIwm:: iwm_enable_ac_txq(struct iwm_softc *sc, int qid, int fifo) { XYLog("%s\n", __FUNCTION__); iwm_nic_assert_locked(sc); IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0); iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid), (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) | (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid)); iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0); iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0); /* Set scheduler window size and frame limit. */ iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) + sizeof(uint32_t), ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid), (1 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) | (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) | (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) | IWM_SCD_QUEUE_STTS_REG_MSK); if (qid == sc->cmdqid) iwm_write_prph(sc, IWM_SCD_EN_CTRL, iwm_read_prph(sc, IWM_SCD_EN_CTRL) | (1 << qid)); return 0; } int ItlIwm:: iwm_enable_txq(struct iwm_softc *sc, int sta_id, int qid, int fifo, int ssn, int tid, int agg) { XYLog("%s qid=%d tid=%d agg=%d\n", __FUNCTION__, qid, tid, agg); struct iwm_scd_txq_cfg_cmd cmd; int err = 0; uint16_t idx; struct iwm_tx_ring *ring = &sc->txq[qid]; bool scd_bug = false; if (agg && (sc->agg_queue_mask & (1 << qid))) return 0; iwm_nic_assert_locked(sc); /* * If we need to move the SCD write pointer by steps of * 0x40, 0x80 or 0xc0, it gets stuck. Avoids this and let * the op_mode know by returning true later. * Do this only in case cfg is NULL since this trick can * be done only if we have DQA enabled which is true for mvm * only. And mvm never sets a cfg pointer. * This is really ugly, but this is the easiest way out for * this sad hardware issue. * This bug has been fixed on devices 9000 and up. */ scd_bug = !sc->sc_mqrx_supported && !((ssn - ring->cur) & 0x3f) && (ssn != ring->cur); if (scd_bug) ssn = (ssn + 1) & 0xfff; idx = IWM_AGG_SSN_TO_TXQ_IDX(ssn); ring->cur = ring->read = idx; ring->tail = idx; IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, (qid << 8) | idx); memset(&cmd, 0, sizeof(cmd)); cmd.scd_queue = qid; cmd.enable = IWM_SCD_CFG_ENABLE_QUEUE; cmd.window = IWM_FRAME_LIMIT; cmd.sta_id = sta_id; cmd.ssn = htole16(ssn); cmd.tx_fifo = fifo; cmd.aggregate = agg; cmd.tid = tid; iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), ssn); iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0); /* Set scheduler window size and frame limit. */ iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) + sizeof(uint32_t), ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid), (1 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) | (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) | (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) | IWM_SCD_QUEUE_STTS_REG_MSK); if (qid == sc->cmdqid) iwm_write_prph(sc, IWM_SCD_EN_CTRL, iwm_read_prph(sc, IWM_SCD_EN_CTRL) | (1 << qid)); err = iwm_send_cmd_pdu(sc, IWM_SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd); if (err) XYLog("%s failed error=%d\n", __FUNCTION__, err); return err; } int ItlIwm:: iwm_disable_txq(struct iwm_softc *sc, uint8_t qid, uint8_t tid, uint8_t flags) { int err; struct iwm_scd_txq_cfg_cmd cmd = { .scd_queue = qid, .enable = IWM_SCD_CFG_DISABLE_QUEUE, .sta_id = IWM_STATION_ID, .tid = tid, }; err = iwm_send_cmd_pdu(sc, IWM_SCD_QUEUE_CFG, flags, sizeof(struct iwm_scd_txq_cfg_cmd), &cmd); return err; } int ItlIwm:: iwm_send_soc_conf(struct iwm_softc *sc) { struct iwm_soc_configuration_cmd cmd; int err; uint32_t cmd_id, flags = 0; memset(&cmd, 0, sizeof(cmd)); /* * In VER_1 of this command, the discrete value is considered * an integer; In VER_2, it's a bitmask. Since we have only 2 * values in VER_1, this is backwards-compatible with VER_2, * as long as we don't set any other flag bits. */ if (!sc->sc_integrated) { /* VER_1 */ flags = IWM_SOC_CONFIG_CMD_FLAGS_DISCRETE; } else { /* VER_2 */ uint8_t scan_cmd_ver; if (sc->sc_ltr_delay != IWM_SOC_FLAGS_LTR_APPLY_DELAY_NONE) flags |= (sc->sc_ltr_delay & IWM_SOC_FLAGS_LTR_APPLY_DELAY_MASK); scan_cmd_ver = iwm_lookup_cmd_ver(sc, IWM_LONG_GROUP, IWM_SCAN_REQ_UMAC); if (scan_cmd_ver != IWM_FW_CMD_VER_UNKNOWN && scan_cmd_ver >= 2 && sc->sc_low_latency_xtal) flags |= IWM_SOC_CONFIG_CMD_FLAGS_LOW_LATENCY; } cmd.flags = htole32(flags); cmd.latency = htole32(sc->sc_xtal_latency); cmd_id = iwm_cmd_id(IWM_SOC_CONFIGURATION_CMD, IWM_SYSTEM_GROUP, 0); err = iwm_send_cmd_pdu(sc, cmd_id, 0, sizeof(cmd), &cmd); if (err) printf("%s: failed to set soc latency: %d\n", DEVNAME(sc), err); return err; } int ItlIwm:: iwm_send_update_mcc_cmd(struct iwm_softc *sc, const char *alpha2) { XYLog("%s\n", __FUNCTION__); struct iwm_mcc_update_cmd mcc_cmd; struct iwm_host_cmd hcmd = { .id = IWM_MCC_UPDATE_CMD, .flags = IWM_CMD_WANT_RESP, .resp_pkt_len = IWM_CMD_RESP_MAX, .data = { &mcc_cmd }, }; struct iwm_rx_packet *pkt; size_t resp_len; int err; int resp_v3 = isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_SUPPORT_V3); if (sc->sc_device_family == IWM_DEVICE_FAMILY_8000 && !sc->sc_nvm.lar_enabled) { return 0; } memset(&mcc_cmd, 0, sizeof(mcc_cmd)); mcc_cmd.mcc = htole16(alpha2[0] << 8 | alpha2[1]); if (isset(sc->sc_ucode_api, IWM_UCODE_TLV_API_WIFI_MCC_UPDATE) || isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_LAR_MULTI_MCC)) mcc_cmd.source_id = IWM_MCC_SOURCE_GET_CURRENT; else mcc_cmd.source_id = IWM_MCC_SOURCE_OLD_FW; if (resp_v3) { /* same size as resp_v2 */ hcmd.len[0] = sizeof(struct iwm_mcc_update_cmd); } else { hcmd.len[0] = sizeof(struct iwm_mcc_update_cmd_v1); } err = iwm_send_cmd(sc, &hcmd); if (err) return err; pkt = hcmd.resp_pkt; if (!pkt || (pkt->hdr.flags & IWM_CMD_FAILED_MSK)) { err = EIO; goto out; } if (resp_v3) { struct iwm_mcc_update_resp_v3 *resp; resp_len = iwm_rx_packet_payload_len(pkt); if (resp_len < sizeof(*resp)) { err = EIO; goto out; } resp = (struct iwm_mcc_update_resp_v3 *)pkt->data; if (resp_len != sizeof(*resp) + resp->n_channels * sizeof(resp->channels[0])) { err = EIO; goto out; } } else { struct iwm_mcc_update_resp_v1 *resp_v1; resp_len = iwm_rx_packet_payload_len(pkt); if (resp_len < sizeof(*resp_v1)) { err = EIO; goto out; } resp_v1 = (struct iwm_mcc_update_resp_v1 *)pkt->data; if (resp_len != sizeof(*resp_v1) + resp_v1->n_channels * sizeof(resp_v1->channels[0])) { err = EIO; goto out; } } out: iwm_free_resp(sc, &hcmd); return err; } int ItlIwm:: iwm_send_temp_report_ths_cmd(struct iwm_softc *sc) { struct iwm_temp_report_ths_cmd cmd; int err; /* * In order to give responsibility for critical-temperature-kill * and TX backoff to FW we need to send an empty temperature * reporting command at init time. */ memset(&cmd, 0, sizeof(cmd)); err = iwm_send_cmd_pdu(sc, IWM_WIDE_ID(IWM_PHY_OPS_GROUP, IWM_TEMP_REPORTING_THRESHOLDS_CMD), 0, sizeof(cmd), &cmd); if (err) printf("%s: TEMP_REPORT_THS_CMD command failed (error %d)\n", DEVNAME(sc), err); return err; } void ItlIwm:: iwm_tt_tx_backoff(struct iwm_softc *sc, uint32_t backoff) { XYLog("%s\n", __FUNCTION__); struct iwm_host_cmd cmd = { .id = IWM_REPLY_THERMAL_MNG_BACKOFF, .len = { sizeof(uint32_t), }, .data = { &backoff, }, }; iwm_send_cmd(sc, &cmd); } void ItlIwm:: iwm_free_fw_paging(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); int i; if (sc->fw_paging_db[0].fw_paging_block.vaddr == NULL) return; for (i = 0; i < IWM_NUM_OF_FW_PAGING_BLOCKS; i++) { iwm_dma_contig_free(&sc->fw_paging_db[i].fw_paging_block); } memset(sc->fw_paging_db, 0, sizeof(sc->fw_paging_db)); } int ItlIwm:: iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image) { int sec_idx, idx; uint32_t offset = 0; /* * find where is the paging image start point: * if CPU2 exist and it's in paging format, then the image looks like: * CPU1 sections (2 or more) * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between CPU1 to CPU2 * CPU2 sections (not paged) * PAGING_SEPARATOR_SECTION delimiter - separate between CPU2 * non paged to CPU2 paging sec * CPU2 paging CSS * CPU2 paging image (including instruction and data) */ for (sec_idx = 0; sec_idx < IWM_UCODE_SECT_MAX; sec_idx++) { if (image->fw_sect[sec_idx].fws_devoff == IWM_PAGING_SEPARATOR_SECTION) { sec_idx++; break; } } /* * If paging is enabled there should be at least 2 more sections left * (one for CSS and one for Paging data) */ if (sec_idx >= nitems(image->fw_sect) - 1) { XYLog("%s: Paging: Missing CSS and/or paging sections\n", DEVNAME(sc)); iwm_free_fw_paging(sc); return EINVAL; } /* copy the CSS block to the dram */ XYLog("%s: Paging: load paging CSS to FW, sec = %d\n", DEVNAME(sc), sec_idx); memcpy(sc->fw_paging_db[0].fw_paging_block.vaddr, image->fw_sect[sec_idx].fws_data, sc->fw_paging_db[0].fw_paging_size); XYLog("%s: Paging: copied %d CSS bytes to first block\n", DEVNAME(sc), sc->fw_paging_db[0].fw_paging_size); sec_idx++; /* * copy the paging blocks to the dram * loop index start from 1 since that CSS block already copied to dram * and CSS index is 0. * loop stop at num_of_paging_blk since that last block is not full. */ for (idx = 1; idx < sc->num_of_paging_blk; idx++) { memcpy(sc->fw_paging_db[idx].fw_paging_block.vaddr, (const char *)image->fw_sect[sec_idx].fws_data + offset, sc->fw_paging_db[idx].fw_paging_size); XYLog("%s: Paging: copied %d paging bytes to block %d\n", DEVNAME(sc), sc->fw_paging_db[idx].fw_paging_size, idx); offset += sc->fw_paging_db[idx].fw_paging_size; } /* copy the last paging block */ if (sc->num_of_pages_in_last_blk > 0) { memcpy(sc->fw_paging_db[idx].fw_paging_block.vaddr, (const char *)image->fw_sect[sec_idx].fws_data + offset, IWM_FW_PAGING_SIZE * sc->num_of_pages_in_last_blk); XYLog("%s: Paging: copied %d pages in the last block %d\n", DEVNAME(sc), sc->num_of_pages_in_last_blk, idx); } return 0; } int ItlIwm:: iwm_alloc_fw_paging_mem(struct iwm_softc *sc, const struct iwm_fw_sects *image) { int blk_idx = 0; int error, num_of_pages; if (sc->fw_paging_db[0].fw_paging_block.vaddr != NULL) { // int i; // /* Device got reset, and we setup firmware paging again */ // bus_dmamap_sync(sc->sc_dmat, // sc->fw_paging_db[0].fw_paging_block.map, // 0, IWM_FW_PAGING_SIZE, // BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); // for (i = 1; i < sc->num_of_paging_blk + 1; i++) { // bus_dmamap_sync(sc->sc_dmat, // sc->fw_paging_db[i].fw_paging_block.map, // 0, IWM_PAGING_BLOCK_SIZE, // BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); // } return 0; } /* ensure IWM_BLOCK_2_EXP_SIZE is power of 2 of IWM_PAGING_BLOCK_SIZE */ #if (1 << IWM_BLOCK_2_EXP_SIZE) != IWM_PAGING_BLOCK_SIZE #error IWM_BLOCK_2_EXP_SIZE must be power of 2 of IWM_PAGING_BLOCK_SIZE #endif num_of_pages = image->paging_mem_size / IWM_FW_PAGING_SIZE; sc->num_of_paging_blk = ((num_of_pages - 1) / IWM_NUM_OF_PAGE_PER_GROUP) + 1; sc->num_of_pages_in_last_blk = num_of_pages - IWM_NUM_OF_PAGE_PER_GROUP * (sc->num_of_paging_blk - 1); XYLog("%s: Paging: allocating mem for %d paging blocks, each block" " holds 8 pages, last block holds %d pages\n", DEVNAME(sc), sc->num_of_paging_blk, sc->num_of_pages_in_last_blk); /* allocate block of 4Kbytes for paging CSS */ error = iwm_dma_contig_alloc(sc->sc_dmat, &sc->fw_paging_db[blk_idx].fw_paging_block, IWM_FW_PAGING_SIZE, 4096); if (error) { /* free all the previous pages since we failed */ iwm_free_fw_paging(sc); return ENOMEM; } sc->fw_paging_db[blk_idx].fw_paging_size = IWM_FW_PAGING_SIZE; XYLog("%s: Paging: allocated 4K(CSS) bytes for firmware paging.\n", DEVNAME(sc)); /* * allocate blocks in dram. * since that CSS allocated in fw_paging_db[0] loop start from index 1 */ for (blk_idx = 1; blk_idx < sc->num_of_paging_blk + 1; blk_idx++) { /* allocate block of IWM_PAGING_BLOCK_SIZE (32K) */ /* XXX Use iwm_dma_contig_alloc for allocating */ error = iwm_dma_contig_alloc(sc->sc_dmat, &sc->fw_paging_db[blk_idx].fw_paging_block, IWM_PAGING_BLOCK_SIZE, 4096); if (error) { /* free all the previous pages since we failed */ iwm_free_fw_paging(sc); return ENOMEM; } sc->fw_paging_db[blk_idx].fw_paging_size = IWM_PAGING_BLOCK_SIZE; XYLog( "%s: Paging: allocated 32K bytes for firmware paging.\n", DEVNAME(sc)); } return 0; } int ItlIwm:: iwm_save_fw_paging(struct iwm_softc *sc, const struct iwm_fw_sects *fw) { XYLog("%s\n", __FUNCTION__); int ret; ret = iwm_alloc_fw_paging_mem(sc, fw); if (ret) return ret; return iwm_fill_paging_mem(sc, fw); } /* send paging cmd to FW in case CPU2 has paging image */ int ItlIwm:: iwm_send_paging_cmd(struct iwm_softc *sc, const struct iwm_fw_sects *fw) { XYLog("%s\n", __FUNCTION__); int blk_idx; uint32_t dev_phy_addr; struct iwm_fw_paging_cmd fw_paging_cmd = { .flags = htole32(IWM_PAGING_CMD_IS_SECURED | IWM_PAGING_CMD_IS_ENABLED | (sc->num_of_pages_in_last_blk << IWM_PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), .block_size = htole32(IWM_BLOCK_2_EXP_SIZE), .block_num = htole32(sc->num_of_paging_blk), }; /* loop for for all paging blocks + CSS block */ for (blk_idx = 0; blk_idx < sc->num_of_paging_blk + 1; blk_idx++) { dev_phy_addr = htole32( sc->fw_paging_db[blk_idx].fw_paging_block.paddr >> IWM_PAGE_2_EXP_SIZE); fw_paging_cmd.device_phy_addr[blk_idx] = dev_phy_addr; // bus_dmamap_sync(sc->sc_dmat, // sc->fw_paging_db[blk_idx].fw_paging_block.map, 0, // blk_idx == 0 ? IWM_FW_PAGING_SIZE : IWM_PAGING_BLOCK_SIZE, // BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); } return iwm_send_cmd_pdu(sc, iwm_cmd_id(IWM_FW_PAGING_BLOCK_CMD, IWM_LONG_GROUP, 0), 0, sizeof(fw_paging_cmd), &fw_paging_cmd); } ================================================ FILE: itlwm/hal_iwm/utils.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwm.c,v 1.316 2020/12/07 20:09:24 tobhe Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * *********************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, * USA * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * * BSD LICENSE * * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwm.hpp" #include int ItlIwm:: iwm_send_bt_init_conf(struct iwm_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwm_bt_coex_cmd bt_cmd; bt_cmd.mode = htole32(IWM_BT_COEX_NW); bt_cmd.enabled_modules = htole32(IWM_BT_COEX_HIGH_BAND_RET | IWM_BT_COEX_SYNC2SCO_ENABLED); if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT)) bt_cmd.enabled_modules |= IWM_BT_COEX_MPLUT_ENABLED; return iwm_send_cmd_pdu(sc, IWM_BT_CONFIG, 0, sizeof(bt_cmd), &bt_cmd); } ================================================ FILE: itlwm/hal_iwn/ItlIwn.cpp ================================================ /* * Copyright (C) 2020 pigworlds * * 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. */ /* $OpenBSD: if_iwn.c,v 1.243 2020/11/12 15:16:18 krw Exp $ */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Driver for Intel WiFi Link 4965 and 1000/5000/6000 Series 802.11 network * adapters. */ #include "ItlIwn.hpp" #include #include #include #include #include #include #include #include #include #include #define super ItlHalService OSDefineMetaClassAndStructors(ItlIwn, ItlHalService) #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) #define IC2IFP(_ic_) (&(_ic_)->ic_if) #define IWN_DEBUG #ifdef IWN_DEBUG #define DPRINTF(x) do { if (iwn_debug > 0) XYLog x; } while (0) #define DPRINTFN(n, x) do { if (iwn_debug >= (n)) XYLog x; } while (0) int iwn_debug = 1; #else #define DPRINTF(x) do { ; } while (0) #define DPRINTFN(n, x) do { ; } while (0) #endif #define M_DEVBUF 2 #ifdef DELAY #undef DELAY #define DELAY IODelay #endif bool ItlIwn::attach(IOPCIDevice *device) { pci.pa_tag = device; pci.workloop = getMainWorkLoop(); if (!iwn_attach(&com, &pci)) { detach(device); releaseAll(); return false; } return true; } void ItlIwn:: detach(IOPCIDevice *device) { struct _ifnet *ifp = &com.sc_ic.ic_ac.ac_if; struct iwn_softc *sc = &com; for (int txq_i = 0; txq_i < nitems(sc->txq); txq_i++) iwn_free_tx_ring(sc, &sc->txq[txq_i]); iwn_free_rx_ring(sc, &sc->rxq); iwn_free_sched(sc); iwn_free_ict(sc); iwn_free_kw(sc); iwn_free_fwmem(sc); ieee80211_ifdetach(ifp); taskq_destroy(systq); releaseAll(); } void ItlIwn:: releaseAll() { pci_intr_handle *intrHandler = com.ih; if (com.calib_to) { timeout_del(&com.calib_to); timeout_free(&com.calib_to); } if (intrHandler) { if (intrHandler->intr && intrHandler->workloop) { // intrHandler->intr->disable(); intrHandler->workloop->removeEventSource(intrHandler->intr); intrHandler->intr->release(); } intrHandler->intr = NULL; intrHandler->workloop = NULL; intrHandler->arg = NULL; intrHandler->dev = NULL; intrHandler->func = NULL; intrHandler->release(); com.ih = NULL; } pci.pa_tag = NULL; pci.workloop = NULL; } void ItlIwn::free() { XYLog("%s\n", __FUNCTION__); super::free(); } ItlDriverInfo *ItlIwn:: getDriverInfo() { return this; } ItlDriverController *ItlIwn:: getDriverController() { return this; } IOReturn ItlIwn::enable(IONetworkInterface *netif) { XYLog("%s\n", __PRETTY_FUNCTION__); struct _ifnet *ifp = &com.sc_ic.ic_ac.ac_if; if (ifp->if_flags & IFF_UP) { XYLog("%s already in activating state\n", __FUNCTION__); return kIOReturnSuccess; } ifp->if_flags |= IFF_UP; iwn_activate(&com, DVACT_RESUME); iwn_activate(&com, DVACT_WAKEUP); return kIOReturnSuccess; } IOReturn ItlIwn::disable(IONetworkInterface *netif) { XYLog("%s\n", __FUNCTION__); struct _ifnet *ifp = &com.sc_ic.ic_ac.ac_if; if (!(ifp->if_flags & IFF_UP)) { XYLog("%s already in diactivating state\n", __FUNCTION__); return kIOReturnSuccess; } ifp->if_flags &= ~IFF_UP; iwn_activate(&com, DVACT_QUIESCE); return kIOReturnSuccess; } void ItlIwn:: clearScanningFlags() { com.sc_flags &= ~(IWN_FLAG_SCANNING | IWN_FLAG_BGSCAN); } IOReturn ItlIwn:: setMulticastList(IOEthernetAddress *addr, int count) { return kIOReturnSuccess; } const char *ItlIwn:: getFirmwareVersion() { return com.fwname; } const char *ItlIwn:: getFirmwareName() { return com.fwname; } UInt32 ItlIwn:: supportedFeatures() { return kIONetworkFeatureMultiPages; } const char *ItlIwn:: getFirmwareCountryCode() { return "ZZ"; } uint32_t ItlIwn:: getTxQueueSize() { return IWN_TX_RING_COUNT; } int16_t ItlIwn:: getBSSNoise() { return com.noise; } bool ItlIwn:: is5GBandSupport() { return com.sc_flags & IWN_FLAG_HAS_5GHZ; } int ItlIwn:: getTxNSS() { return com.ntxchains; } struct ieee80211com *ItlIwn:: get80211Controller() { return &com.sc_ic; } #define PCI_VENDOR_INTEL 0x8086 /* Intel */ #define PCI_PRODUCT_INTEL_WL_4965_1 0x4229 /* Wireless WiFi Link 4965 */ #define PCI_PRODUCT_INTEL_WL_6300_1 0x422b /* Centrino Ultimate-N 6300 */ #define PCI_PRODUCT_INTEL_WL_6200_1 0x422c /* Centrino Advanced-N 6200 */ #define PCI_PRODUCT_INTEL_WL_4965_2 0x4230 /* Wireless WiFi Link 4965 */ #define PCI_PRODUCT_INTEL_WL_5100_1 0x4232 /* WiFi Link 5100 */ #define PCI_PRODUCT_INTEL_WL_5300_1 0x4235 /* WiFi Link 5300 */ #define PCI_PRODUCT_INTEL_WL_5300_2 0x4236 /* WiFi Link 5300 */ #define PCI_PRODUCT_INTEL_WL_5100_2 0x4237 /* WiFi Link 5100 */ #define PCI_PRODUCT_INTEL_WL_6300_2 0x4238 /* Centrino Ultimate-N 6300 */ #define PCI_PRODUCT_INTEL_WL_6200_2 0x4239 /* Centrino Advanced-N 6200 */ #define PCI_PRODUCT_INTEL_WL_5350_1 0x423a /* WiFi Link 5350 */ #define PCI_PRODUCT_INTEL_WL_5350_2 0x423b /* WiFi Link 5350 */ #define PCI_PRODUCT_INTEL_WL_5150_1 0x423c /* WiFi Link 5150 */ #define PCI_PRODUCT_INTEL_WL_5150_2 0x423d /* WiFi Link 5150 */ #define PCI_PRODUCT_INTEL_WL_6005_1 0x0082 /* Centrino Advanced-N 6205 */ #define PCI_PRODUCT_INTEL_WL_1000_1 0x0083 /* WiFi Link 1000 */ #define PCI_PRODUCT_INTEL_WL_1000_2 0x0084 /* WiFi Link 1000 */ #define PCI_PRODUCT_INTEL_WL_6005_2 0x0085 /* Centrino Advanced-N 6205 */ #define PCI_PRODUCT_INTEL_WL_6050_1 0x0087 /* Centrino Advanced-N 6250 */ #define PCI_PRODUCT_INTEL_WL_6050_2 0x0089 /* Centrino Advanced-N 6250 */ #define PCI_PRODUCT_INTEL_WL_1030_1 0x008a /* WiFi Link 1030 */ #define PCI_PRODUCT_INTEL_WL_1030_2 0x008b /* WiFi Link 1030 */ #define PCI_PRODUCT_INTEL_WL_6030_1 0x0090 /* Centrino Advanced-N 6030 */ #define PCI_PRODUCT_INTEL_WL_6030_2 0x0091 /* Centrino Advanced-N 6030 */ #define PCI_PRODUCT_INTEL_WL_135_1 0x0892 /* Centrino Wireless-N 135 */ #define PCI_PRODUCT_INTEL_WL_135_2 0x0893 /* Centrino Wireless-N 135 */ #define PCI_PRODUCT_INTEL_WL_105_1 0x0894 /* Centrino Wireless-N 105 */ #define PCI_PRODUCT_INTEL_WL_105_2 0x0895 /* Centrino Wireless-N 105 */ #define PCI_PRODUCT_INTEL_WL_130_1 0x0896 /* Centrino Wireless-N 130 */ #define PCI_PRODUCT_INTEL_WL_130_2 0x0897 /* Centrino Wireless-N 130 */ #define PCI_PRODUCT_INTEL_WL_100_1 0x08ae /* Centrino Wireless-N 100 */ #define PCI_PRODUCT_INTEL_WL_100_2 0x08af /* Centrino Wireless-N 100 */ #define PCI_PRODUCT_INTEL_WL_6235_1 0x088e /* Centrino Advanced-N 6235 */ #define PCI_PRODUCT_INTEL_WL_6235_2 0x088f /* Centrino Advanced-N 6235 */ #define PCI_PRODUCT_INTEL_WL_2200_1 0x0890 /* Centrino Wireless-N 2200 */ #define PCI_PRODUCT_INTEL_WL_2200_2 0x0891 /* Centrino Wireless-N 2200 */ #define PCI_PRODUCT_INTEL_WL_6150_1 0x0885 /* Centrino Wireless-N 6150 */ #define PCI_PRODUCT_INTEL_WL_6150_2 0x0886 /* Centrino Wireless-N 6150 */ #define PCI_PRODUCT_INTEL_WL_2230_1 0x0887 /* Centrino Wireless-N 2230 */ #define PCI_PRODUCT_INTEL_WL_2230_2 0x0888 /* Centrino Wireless-N 2230 */ static const struct pci_matchid iwn_devices[] = { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_4965_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_4965_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5100_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5100_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5150_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5150_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5300_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5300_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5350_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5350_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_1000_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_1000_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6300_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6300_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6200_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6200_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6050_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6050_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6005_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6005_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6030_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6030_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_1030_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_1030_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_100_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_100_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_130_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_130_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6235_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6235_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2230_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2230_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2200_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2200_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_135_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_135_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_105_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_105_2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6150_1 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6150_2 }, }; int ItlIwn:: iwn_match(struct IOPCIDevice *device) { int devId = device->configRead16(kIOPCIConfigDeviceID); return pci_matchbyid(PCI_VENDOR_INTEL, devId, iwn_devices, nitems(iwn_devices)); } bool ItlIwn:: intrFilter(OSObject *object, IOFilterInterruptEventSource *src) { ItlIwn *that = (ItlIwn*)object; IWN_WRITE(&that->com, IWN_INT_MASK, 0); return true; } bool ItlIwn:: iwn_attach(struct iwn_softc *sc, struct pci_attach_args *pa) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; pcireg_t memtype, reg; int i, error; sc->sc_pct = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; sc->sc_dmat = pa->pa_dmat; /* * Get the offset of the PCI Express Capability Structure in PCI * Configuration Space. */ error = pci_get_capability(sc->sc_pct, sc->sc_pcitag, PCI_CAP_PCIEXPRESS, &sc->sc_cap_off, NULL); if (error == 0) { XYLog(": PCIe capability structure not found!\n"); return false; } /* Clear device-specific "PCI retry timeout" register (41h). */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40); if (reg & 0xff00) pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00); /* Hardware bug workaround. */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); if (reg & PCI_COMMAND_INTERRUPT_DISABLE) { DPRINTF(("PCIe INTx Disable set\n")); reg &= ~PCI_COMMAND_INTERRUPT_DISABLE; pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); } memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, IWN_PCI_BAR0); error = pci_mapreg_map(pa, IWN_PCI_BAR0, memtype, 0, &sc->sc_st, &sc->sc_sh, NULL, &sc->sc_sz, 0); if (error != 0) { XYLog(": can't map mem space\n"); return false; } /* Install interrupt handler. */ if (pci_intr_map_msi(pa, &sc->ih) != 0) { XYLog(": can't map interrupt\n"); return false; } int msiIntrIndex = -1; for (int index = 0; ; index++) { int interruptType; int ret = pa->pa_tag->getInterruptType(index, &interruptType); if (ret != kIOReturnSuccess) break; if (interruptType & kIOInterruptTypePCIMessaged) { msiIntrIndex = index; break; } } if (msiIntrIndex == -1) { XYLog("%s: can't find MSI interrupt controller\n", DEVNAME(sc)); return false; } sc->sc_ih = IOFilterInterruptEventSource::filterInterruptEventSource(this, (IOInterruptEventSource::Action)&ItlIwn::iwn_intr, &ItlIwn::intrFilter ,pa->pa_tag, msiIntrIndex); if (sc->sc_ih == NULL || pa->workloop->addEventSource(sc->sc_ih) != kIOReturnSuccess) { XYLog("%s: can't establish interrupt\n", DEVNAME(sc)); return false; } sc->sc_ih->enable(); /* Read hardware revision and attach. */ sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> 4) & 0x1f; int pa_id = pa->pa_tag->configRead16(kIOPCIConfigDeviceID); if (sc->hw_type == IWN_HW_REV_TYPE_4965) error = iwn4965_attach(sc, pa_id); else error = iwn5000_attach(sc, pa_id); if (error != 0) { XYLog(": could not attach device\n"); return false; } if ((error = iwn_hw_prepare(sc)) != 0) { XYLog(": hardware not ready\n"); return false; } /* Read MAC address, channels, etc from EEPROM. */ if ((error = iwn_read_eeprom(sc)) != 0) { XYLog(": could not read EEPROM\n"); return false; } /* Allocate DMA memory for firmware transfers. */ if ((error = iwn_alloc_fwmem(sc)) != 0) { XYLog(": could not allocate memory for firmware\n"); return false; } /* Allocate "Keep Warm" page. */ if ((error = iwn_alloc_kw(sc)) != 0) { XYLog(": could not allocate keep warm page\n"); goto fail1; } /* Allocate ICT table for 5000 Series. */ if (sc->hw_type != IWN_HW_REV_TYPE_4965 && (error = iwn_alloc_ict(sc)) != 0) { XYLog(": could not allocate ICT table\n"); goto fail2; } /* Allocate TX scheduler "rings". */ if ((error = iwn_alloc_sched(sc)) != 0) { XYLog(": could not allocate TX scheduler rings\n"); goto fail3; } /* Allocate TX rings (16 on 4965AGN, 20 on >=5000). */ for (i = 0; i < sc->ntxqs; i++) { if ((error = iwn_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { XYLog(": could not allocate TX ring %d\n", i); goto fail4; } } /* Allocate RX ring. */ if ((error = iwn_alloc_rx_ring(sc, &sc->rxq)) != 0) { XYLog(": could not allocate RX ring\n"); goto fail4; } /* Clear pending interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); /* Count the number of available chains. */ sc->ntxchains = ((sc->txchainmask >> 2) & 1) + ((sc->txchainmask >> 1) & 1) + ((sc->txchainmask >> 0) & 1); sc->nrxchains = ((sc->rxchainmask >> 2) & 1) + ((sc->rxchainmask >> 1) & 1) + ((sc->rxchainmask >> 0) & 1); XYLog(", MIMO %dT%dR, %.4s, address %s\n", sc->ntxchains, sc->nrxchains, sc->eeprom_domain, ether_sprintf(ic->ic_myaddr)); taskq_init(); ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ ic->ic_state = IEEE80211_S_INIT; /* Set device capabilities. */ ic->ic_caps = IEEE80211_C_WEP | /* WEP */ IEEE80211_C_RSN | /* WPA/RSN */ IEEE80211_C_SCANALL | /* device scans all channels at once */ IEEE80211_C_SCANALLBAND | /* driver scans all bands at once */ IEEE80211_C_MONITOR | /* monitor mode supported */ IEEE80211_C_SHSLOT | /* short slot time supported */ IEEE80211_C_SHPREAMBLE | /* short preamble supported */ IEEE80211_C_PMGT; /* power saving supported */ /* No optional HT features supported for now, */ ic->ic_htcaps = 0; ic->ic_htxcaps = 0; ic->ic_txbfcaps = 0; ic->ic_aselcaps = 0; ic->ic_ampdu_params = (IEEE80211_AMPDU_PARAM_SS_4 | 0x3 /* 64k */); if (sc->sc_flags & IWN_FLAG_HAS_11N) { ic->ic_caps |= (IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU | IEEE80211_C_AMSDU_IN_AMPDU); /* Set HT capabilities. */ ic->ic_htcaps = IEEE80211_HTCAP_SGI20; /* 6200 devices have issues with SGI40 for some reason. */ if ((sc->sc_flags & IWN_FLAG_INTERNAL_PA) == 0) ic->ic_htcaps |= IEEE80211_HTCAP_SGI40; ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40; #if IWN_RBUF_SIZE == 8192 ic->ic_htcaps |= IEEE80211_HTCAP_AMSDU7935; #endif #ifdef notyet if (sc->hw_type != IWN_HW_REV_TYPE_4965) ic->ic_htcaps |= IEEE80211_HTCAP_GF; #endif if (sc->hw_type == IWN_HW_REV_TYPE_6050) ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_DYN << IEEE80211_HTCAP_SMPS_SHIFT; else ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_DIS << IEEE80211_HTCAP_SMPS_SHIFT; } /* Set supported legacy rates. */ ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; if (sc->sc_flags & IWN_FLAG_HAS_5GHZ) { ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; } if (sc->sc_flags & IWN_FLAG_HAS_11N) { /* Set supported HT rates. */ if (ic->ic_userflags & IEEE80211_F_NOMIMO) sc->ntxchains = sc->nrxchains = 1; int ntxstreams = sc->ntxchains; int nrxstreams = sc->nrxchains; ic->ic_sup_mcs[0] = 0xff; /* MCS 0-7 */ if (nrxstreams > 1) ic->ic_sup_mcs[1] = 0xff; /* MCS 8-15 */ if (nrxstreams > 2) ic->ic_sup_mcs[2] = 0xff; /* MCS 16-23 */ ic->ic_tx_mcs_set = IEEE80211_TX_MCS_SET_DEFINED; if (ntxstreams != nrxstreams) { ic->ic_tx_mcs_set |= IEEE80211_TX_RX_MCS_NOT_EQUAL; ic->ic_tx_mcs_set |= (ntxstreams - 1) << 2; } } /* IBSS channel undefined for now. */ ic->ic_ibss_chan = &ic->ic_channels[0]; ic->ic_max_rssi = IWN_MAX_DBM - IWN_MIN_DBM; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_DEBUG; ifp->if_ioctl = iwn_ioctl; ifp->if_start = iwn_start; ifp->if_watchdog = iwn_watchdog; memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); if_attach(ifp); ieee80211_ifattach(ifp, getController()); ic->ic_node_alloc = iwn_node_alloc; ic->ic_bgscan_start = iwn_bgscan; ic->ic_newassoc = iwn_newassoc; ic->ic_updateedca = iwn_updateedca; ic->ic_set_key = iwn_set_key; ic->ic_delete_key = iwn_delete_key; ic->ic_updateprot = iwn_updateprot; ic->ic_updateslot = iwn_updateslot; ic->ic_ampdu_rx_start = iwn_ampdu_rx_start; ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop; ic->ic_ampdu_tx_start = iwn_ampdu_tx_start; ic->ic_ampdu_tx_stop = iwn_ampdu_tx_stop; ic->ic_update_chw = iwn_update_chw; /* Override 802.11 state transition machine. */ sc->sc_newstate = ic->ic_newstate; ic->ic_newstate = iwn_newstate; ieee80211_media_init(ifp); sc->amrr.amrr_min_success_threshold = 1; sc->amrr.amrr_max_success_threshold = 15; #if NBPFILTER > 0 iwn_radiotap_attach(sc); #endif timeout_set(&sc->calib_to, iwn_calib_timeout, sc); // rw_init(&sc->sc_rwlock, "iwnlock"); task_set(&sc->init_task, iwn_init_task, sc, "iwn_init_task"); return true; /* Free allocated memory if something failed during attachment. */ fail4: while (--i >= 0) iwn_free_tx_ring(sc, &sc->txq[i]); iwn_free_sched(sc); fail3: if (sc->ict != NULL) iwn_free_ict(sc); fail2: iwn_free_kw(sc); fail1: iwn_free_fwmem(sc); return false; } int ItlIwn:: iwn4965_attach(struct iwn_softc *sc, pci_product_id_t pid) { struct iwn_ops *ops = &sc->ops; ops->load_firmware = iwn4965_load_firmware; ops->read_eeprom = iwn4965_read_eeprom; ops->post_alive = iwn4965_post_alive; ops->nic_config = iwn4965_nic_config; ops->reset_sched = iwn4965_reset_sched; ops->update_sched = iwn4965_update_sched; ops->update_rxon = iwn4965_update_rxon; ops->get_temperature = iwn4965_get_temperature; ops->get_rssi = iwn4965_get_rssi; ops->set_txpower = iwn4965_set_txpower; ops->init_gains = iwn4965_init_gains; ops->set_gains = iwn4965_set_gains; ops->add_node = iwn4965_add_node; ops->tx_done = iwn4965_tx_done; ops->ampdu_tx_start = iwn4965_ampdu_tx_start; ops->ampdu_tx_stop = iwn4965_ampdu_tx_stop; sc->ntxqs = IWN4965_NTXQUEUES; sc->first_agg_txq = IWN4965_FIRST_AGG_TXQUEUE; sc->ndmachnls = IWN4965_NDMACHNLS; sc->broadcast_id = IWN4965_ID_BROADCAST; sc->rxonsz = IWN4965_RXONSZ; sc->schedsz = IWN4965_SCHEDSZ; sc->fw_text_maxsz = IWN4965_FW_TEXT_MAXSZ; sc->fw_data_maxsz = IWN4965_FW_DATA_MAXSZ; sc->fwsz = IWN4965_FWSZ; sc->sched_txfact_addr = IWN4965_SCHED_TXFACT; sc->limits = &iwn4965_sensitivity_limits; sc->fwname = "iwn-4965"; /* Override chains masks, ROM is known to be broken. */ sc->txchainmask = IWN_ANT_AB; sc->rxchainmask = IWN_ANT_ABC; return 0; } int ItlIwn:: iwn5000_attach(struct iwn_softc *sc, pci_product_id_t pid) { struct iwn_ops *ops = &sc->ops; ops->load_firmware = iwn5000_load_firmware; ops->read_eeprom = iwn5000_read_eeprom; ops->post_alive = iwn5000_post_alive; ops->nic_config = iwn5000_nic_config; ops->reset_sched = iwn5000_reset_sched; ops->update_sched = iwn5000_update_sched; ops->update_rxon = iwn5000_update_rxon; ops->get_temperature = iwn5000_get_temperature; ops->get_rssi = iwn5000_get_rssi; ops->set_txpower = iwn5000_set_txpower; ops->init_gains = iwn5000_init_gains; ops->set_gains = iwn5000_set_gains; ops->add_node = iwn5000_add_node; ops->tx_done = iwn5000_tx_done; ops->ampdu_tx_start = iwn5000_ampdu_tx_start; ops->ampdu_tx_stop = iwn5000_ampdu_tx_stop; sc->ntxqs = IWN5000_NTXQUEUES; sc->first_agg_txq = IWN5000_FIRST_AGG_TXQUEUE; sc->ndmachnls = IWN5000_NDMACHNLS; sc->broadcast_id = IWN5000_ID_BROADCAST; sc->rxonsz = IWN5000_RXONSZ; sc->schedsz = IWN5000_SCHEDSZ; sc->fw_text_maxsz = IWN5000_FW_TEXT_MAXSZ; sc->fw_data_maxsz = IWN5000_FW_DATA_MAXSZ; sc->fwsz = IWN5000_FWSZ; sc->sched_txfact_addr = IWN5000_SCHED_TXFACT; switch (sc->hw_type) { case IWN_HW_REV_TYPE_5100: sc->limits = &iwn5000_sensitivity_limits; sc->fwname = "iwn-5000"; /* Override chains masks, ROM is known to be broken. */ sc->txchainmask = IWN_ANT_B; sc->rxchainmask = IWN_ANT_AB; break; case IWN_HW_REV_TYPE_5150: sc->limits = &iwn5150_sensitivity_limits; sc->fwname = "iwn-5150"; break; case IWN_HW_REV_TYPE_5300: case IWN_HW_REV_TYPE_5350: sc->limits = &iwn5000_sensitivity_limits; sc->fwname = "iwn-5000"; break; case IWN_HW_REV_TYPE_1000: sc->limits = &iwn1000_sensitivity_limits; sc->fwname = "iwn-1000"; break; case IWN_HW_REV_TYPE_6000: sc->limits = &iwn6000_sensitivity_limits; sc->fwname = "iwn-6000"; if (pid == PCI_PRODUCT_INTEL_WL_6200_1 || pid == PCI_PRODUCT_INTEL_WL_6200_2) { sc->sc_flags |= IWN_FLAG_INTERNAL_PA; /* Override chains masks, ROM is known to be broken. */ sc->txchainmask = IWN_ANT_BC; sc->rxchainmask = IWN_ANT_BC; } break; case IWN_HW_REV_TYPE_6050: sc->limits = &iwn6000_sensitivity_limits; sc->fwname = "iwn-6050"; break; case IWN_HW_REV_TYPE_6005: sc->limits = &iwn6000_sensitivity_limits; if (pid != PCI_PRODUCT_INTEL_WL_6005_1 && pid != PCI_PRODUCT_INTEL_WL_6005_2) { sc->fwname = "iwn-6030"; sc->sc_flags |= IWN_FLAG_ADV_BT_COEX; } else sc->fwname = "iwn-6005"; break; case IWN_HW_REV_TYPE_2030: sc->limits = &iwn2000_sensitivity_limits; sc->fwname = "iwn-2030"; sc->sc_flags |= IWN_FLAG_ADV_BT_COEX; break; case IWN_HW_REV_TYPE_2000: sc->limits = &iwn2000_sensitivity_limits; sc->fwname = "iwn-2000"; break; case IWN_HW_REV_TYPE_135: sc->limits = &iwn2000_sensitivity_limits; sc->fwname = "iwn-135"; sc->sc_flags |= IWN_FLAG_ADV_BT_COEX; break; case IWN_HW_REV_TYPE_105: sc->limits = &iwn2000_sensitivity_limits; sc->fwname = "iwn-105"; break; default: XYLog(": adapter type %d not supported\n", sc->hw_type); return ENOTSUP; } return 0; } #if NBPFILTER > 0 /* * Attach the interface to 802.11 radiotap. */ void ItlIwn:: iwn_radiotap_attach(struct iwn_softc *sc) { bpfattach(&sc->sc_drvbpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO, sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN); sc->sc_rxtap_len = sizeof sc->sc_rxtapu; sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); sc->sc_rxtap.wr_ihdr.it_present = htole32(IWN_RX_RADIOTAP_PRESENT); sc->sc_txtap_len = sizeof sc->sc_txtapu; sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); sc->sc_txtap.wt_ihdr.it_present = htole32(IWN_TX_RADIOTAP_PRESENT); } #endif int ItlIwn:: iwn_activate(struct iwn_softc *sc, int act) { XYLog("%s\n", __FUNCTION__); struct _ifnet *ifp = &sc->sc_ic.ic_if; switch (act) { case DVACT_QUIESCE: if (ifp->if_flags & IFF_RUNNING) iwn_stop(ifp); break; case DVACT_WAKEUP: iwn_wakeup(sc); break; } return 0; } void ItlIwn:: iwn_wakeup(struct iwn_softc *sc) { pcireg_t reg; /* Clear device-specific "PCI retry timeout" register (41h). */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40); if (reg & 0xff00) pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00); task_add(systq, &sc->init_task); } void ItlIwn:: iwn_init_task(void *arg1) { XYLog("%s\n", __FUNCTION__); struct iwn_softc *sc = (struct iwn_softc *)arg1; struct _ifnet *ifp = &sc->sc_ic.ic_if; ItlIwn *that = container_of(sc, ItlIwn, com); int s; // rw_enter_write(&sc->sc_rwlock); s = splnet(); if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP) that->iwn_init(ifp); splx(s); // rw_exit_write(&sc->sc_rwlock); } int iwn_nic_lock(struct iwn_softc *sc) { int ntries; /* Request exclusive access to NIC. */ IWN_SETBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_MAC_ACCESS_REQ); /* Spin until we actually get the lock. */ for (ntries = 0; ntries < 1000; ntries++) { if ((IWN_READ(sc, IWN_GP_CNTRL) & (IWN_GP_CNTRL_MAC_ACCESS_ENA | IWN_GP_CNTRL_SLEEP)) == IWN_GP_CNTRL_MAC_ACCESS_ENA) return 0; DELAY(10); } XYLog("%s acquiring device failed.", __FUNCTION__); return ETIMEDOUT; } void iwn_nic_unlock(struct iwn_softc *sc) { IWN_CLRBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_MAC_ACCESS_REQ); } uint32_t iwn_prph_read(struct iwn_softc *sc, uint32_t addr) { IWN_WRITE(sc, IWN_PRPH_RADDR, IWN_PRPH_DWORD | addr); IWN_BARRIER_READ_WRITE(sc); return IWN_READ(sc, IWN_PRPH_RDATA); } void iwn_prph_write(struct iwn_softc *sc, uint32_t addr, uint32_t data) { IWN_WRITE(sc, IWN_PRPH_WADDR, IWN_PRPH_DWORD | addr); IWN_BARRIER_WRITE(sc); IWN_WRITE(sc, IWN_PRPH_WDATA, data); } void iwn_prph_setbits(struct iwn_softc *sc, uint32_t addr, uint32_t mask) { iwn_prph_write(sc, addr, iwn_prph_read(sc, addr) | mask); } void iwn_prph_clrbits(struct iwn_softc *sc, uint32_t addr, uint32_t mask) { iwn_prph_write(sc, addr, iwn_prph_read(sc, addr) & ~mask); } void iwn_prph_write_region_4(struct iwn_softc *sc, uint32_t addr, const uint32_t *data, int count) { for (; count > 0; count--, data++, addr += 4) iwn_prph_write(sc, addr, *data); } uint32_t iwn_mem_read(struct iwn_softc *sc, uint32_t addr) { IWN_WRITE(sc, IWN_MEM_RADDR, addr); IWN_BARRIER_READ_WRITE(sc); return IWN_READ(sc, IWN_MEM_RDATA); } void iwn_mem_write(struct iwn_softc *sc, uint32_t addr, uint32_t data) { IWN_WRITE(sc, IWN_MEM_WADDR, addr); IWN_BARRIER_WRITE(sc); IWN_WRITE(sc, IWN_MEM_WDATA, data); } void iwn_mem_write_2(struct iwn_softc *sc, uint32_t addr, uint16_t data) { uint32_t tmp; tmp = iwn_mem_read(sc, addr & ~3); if (addr & 3) tmp = (tmp & 0x0000ffff) | data << 16; else tmp = (tmp & 0xffff0000) | data; iwn_mem_write(sc, addr & ~3, tmp); } #ifdef IWN_DEBUG void iwn_mem_read_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t *data, int count) { for (; count > 0; count--, addr += 4) *data++ = iwn_mem_read(sc, addr); } #endif void iwn_mem_set_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t val, int count) { for (; count > 0; count--, addr += 4) iwn_mem_write(sc, addr, val); } int ItlIwn:: iwn_eeprom_lock(struct iwn_softc *sc) { int i, ntries; for (i = 0; i < 100; i++) { /* Request exclusive access to EEPROM. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_EEPROM_LOCKED); /* Spin until we actually get the lock. */ for (ntries = 0; ntries < 100; ntries++) { if (IWN_READ(sc, IWN_HW_IF_CONFIG) & IWN_HW_IF_CONFIG_EEPROM_LOCKED) return 0; DELAY(10); } } return ETIMEDOUT; } void iwn_eeprom_unlock(struct iwn_softc *sc) { IWN_CLRBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_EEPROM_LOCKED); } /* * Initialize access by host to One Time Programmable ROM. * NB: This kind of ROM can be found on 1000 or 6000 Series only. */ int ItlIwn:: iwn_init_otprom(struct iwn_softc *sc) { uint16_t prev, base, next; int count, error; /* Wait for clock stabilization before accessing prph. */ if ((error = iwn_clock_wait(sc)) != 0) return error; if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_RESET_REQ); DELAY(5); iwn_prph_clrbits(sc, IWN_APMG_PS, IWN_APMG_PS_RESET_REQ); iwn_nic_unlock(sc); /* Set auto clock gate disable bit for HW with OTP shadow RAM. */ if (sc->hw_type != IWN_HW_REV_TYPE_1000) { IWN_SETBITS(sc, IWN_DBG_LINK_PWR_MGMT, IWN_RESET_LINK_PWR_MGMT_DIS); } IWN_CLRBITS(sc, IWN_EEPROM_GP, IWN_EEPROM_GP_IF_OWNER); /* Clear ECC status. */ IWN_SETBITS(sc, IWN_OTP_GP, IWN_OTP_GP_ECC_CORR_STTS | IWN_OTP_GP_ECC_UNCORR_STTS); /* * Find the block before last block (contains the EEPROM image) * for HW without OTP shadow RAM. */ if (sc->hw_type == IWN_HW_REV_TYPE_1000) { /* Switch to absolute addressing mode. */ IWN_CLRBITS(sc, IWN_OTP_GP, IWN_OTP_GP_RELATIVE_ACCESS); base = 0; for (count = 0; count < IWN1000_OTP_NBLOCKS; count++) { error = iwn_read_prom_data(sc, base, &next, 2); if (error != 0) return error; if (next == 0) /* End of linked-list. */ break; prev = base; base = letoh16(next); } if (count == 0 || count == IWN1000_OTP_NBLOCKS) return EIO; /* Skip "next" word. */ sc->prom_base = prev + 1; } return 0; } int ItlIwn:: iwn_read_prom_data(struct iwn_softc *sc, uint32_t addr, void *data, int count) { uint8_t *out = (uint8_t *)data; uint32_t val, tmp; int ntries; addr += sc->prom_base; for (; count > 0; count -= 2, addr++) { IWN_WRITE(sc, IWN_EEPROM, addr << 2); for (ntries = 0; ntries < 10; ntries++) { val = IWN_READ(sc, IWN_EEPROM); if (val & IWN_EEPROM_READ_VALID) break; DELAY(5); } if (ntries == 10) { XYLog("%s: timeout reading ROM at 0x%x\n", sc->sc_dev.dv_xname, addr); return ETIMEDOUT; } if (sc->sc_flags & IWN_FLAG_HAS_OTPROM) { /* OTPROM, check for ECC errors. */ tmp = IWN_READ(sc, IWN_OTP_GP); if (tmp & IWN_OTP_GP_ECC_UNCORR_STTS) { XYLog("%s: OTPROM ECC error at 0x%x\n", sc->sc_dev.dv_xname, addr); return EIO; } if (tmp & IWN_OTP_GP_ECC_CORR_STTS) { /* Correctable ECC error, clear bit. */ IWN_SETBITS(sc, IWN_OTP_GP, IWN_OTP_GP_ECC_CORR_STTS); } } *out++ = val >> 16; if (count > 1) *out++ = val >> 24; } return 0; } bool allocDmaMemory2(struct iwn_dma_info *dma, size_t size, int alignment) { IOBufferMemoryDescriptor *bmd; IODMACommand::Segment64 seg; UInt64 ofs = 0; UInt32 numSegs = 1; bmd = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, kIODirectionInOut | kIOMemoryPhysicallyContiguous | kIOMapInhibitCache, size, DMA_BIT_MASK(64)); if (bmd == NULL) { XYLog("%s alloc DMA memory failed.\n", __FUNCTION__); return false; } bmd->prepare(); IODMACommand *cmd = IODMACommand::withSpecification(kIODMACommandOutputHost64, 64, 0, IODMACommand::kMapped, 0, alignment); if (cmd == NULL) { XYLog("%s alloc IODMACommand memory failed.\n", __FUNCTION__); bmd->complete(); bmd->release(); return false; } cmd->setMemoryDescriptor(bmd); if (cmd->gen64IOVMSegments(&ofs, &seg, &numSegs) != kIOReturnSuccess) { cmd->release(); cmd = NULL; bmd->complete(); bmd->release(); bmd = NULL; return false; } dma->paddr = seg.fIOVMAddr; dma->vaddr = bmd->getBytesNoCopy(); dma->size = size; dma->buffer = bmd; dma->cmd = cmd; memset(dma->vaddr, 0, dma->size); return true; } int ItlIwn:: iwn_dma_contig_alloc(bus_dma_tag_t tag, struct iwn_dma_info *dma, void** kvap, bus_size_t size, bus_size_t alignment) { if (!allocDmaMemory2(dma, size, alignment)) { return 1; } if (kvap != NULL) *kvap = dma->vaddr; return 0; } void ItlIwn:: iwn_dma_contig_free(struct iwn_dma_info *dma) { if (dma == NULL || dma->cmd == NULL) return; if (dma->vaddr == NULL) return; dma->cmd->clearMemoryDescriptor(); dma->cmd->release(); dma->cmd = NULL; dma->buffer->complete(); dma->buffer->release(); dma->buffer = NULL; dma->vaddr = NULL; } int ItlIwn:: iwn_alloc_sched(struct iwn_softc *sc) { /* TX scheduler rings must be aligned on a 1KB boundary. */ return iwn_dma_contig_alloc(sc->sc_dmat, &sc->sched_dma, (void **)&sc->sched, sc->schedsz, 1024); } void ItlIwn:: iwn_free_sched(struct iwn_softc *sc) { iwn_dma_contig_free(&sc->sched_dma); } int ItlIwn:: iwn_alloc_kw(struct iwn_softc *sc) { /* "Keep Warm" page must be aligned on a 4KB boundary. */ return iwn_dma_contig_alloc(sc->sc_dmat, &sc->kw_dma, NULL, 4096, 4096); } void ItlIwn:: iwn_free_kw(struct iwn_softc *sc) { iwn_dma_contig_free(&sc->kw_dma); } int ItlIwn:: iwn_alloc_ict(struct iwn_softc *sc) { /* ICT table must be aligned on a 4KB boundary. */ return iwn_dma_contig_alloc(sc->sc_dmat, &sc->ict_dma, (void **)&sc->ict, IWN_ICT_SIZE, 4096); } void ItlIwn:: iwn_free_ict(struct iwn_softc *sc) { iwn_dma_contig_free(&sc->ict_dma); } int ItlIwn:: iwn_alloc_fwmem(struct iwn_softc *sc) { /* Must be aligned on a 16-byte boundary. */ return iwn_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma, NULL, sc->fwsz, 16); } void ItlIwn:: iwn_free_fwmem(struct iwn_softc *sc) { iwn_dma_contig_free(&sc->fw_dma); } int ItlIwn:: iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) { bus_size_t size; int i, error; mbuf_t m; ring->cur = 0; /* Allocate RX descriptors (256-byte aligned). */ size = IWN_RX_RING_COUNT * sizeof (uint32_t); error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, (void **)&ring->desc, size, 256); if (error != 0) { XYLog("%s: could not allocate RX ring DMA memory\n", sc->sc_dev.dv_xname); goto fail; } /* Allocate RX status area (16-byte aligned). */ error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->stat_dma, (void **)&ring->stat, sizeof (struct iwn_rx_status), 16); if (error != 0) { XYLog("%s: could not allocate RX status DMA memory\n", sc->sc_dev.dv_xname); goto fail; } /* * Allocate and map RX buffers. */ for (i = 0; i < IWN_RX_RING_COUNT; i++) { struct iwn_rx_data *data = &ring->data[i]; error = bus_dmamap_create(sc->sc_dmat, IWN_RBUF_SIZE, 1, IWN_RBUF_SIZE, 0, BUS_DMA_NOWAIT, &data->map); if (error != 0) { XYLog("%s: could not create RX buf DMA map\n", sc->sc_dev.dv_xname); goto fail; } m = getController()->allocatePacket(IWN_RBUF_SIZE); if (m == NULL) { XYLog("could not allocate RX mbuf\n"); error = ENOBUFS; goto fail; } data->map->dm_nsegs = data->map->cursor->getPhysicalSegments(m, &data->map->dm_segs[0], 1); if (data->map->dm_nsegs == 0) { mbuf_freem(m); error = ENOMEM; goto fail; } data->m = m; // data->m = MCLGETI(NULL, M_DONTWAIT, NULL, IWN_RBUF_SIZE); // if (data->m == NULL) { // XYLog("%s: could not allocate RX mbuf\n", // sc->sc_dev.dv_xname); // error = ENOBUFS; // goto fail; // } // // error = bus_dmamap_load(sc->sc_dmat, data->map, // mtod(data->m, void *), IWN_RBUF_SIZE, NULL, // BUS_DMA_NOWAIT | BUS_DMA_READ); // if (error != 0) { // XYLog("%s: can't map mbuf (error %d)\n", // sc->sc_dev.dv_xname, error); // goto fail; // } /* Set physical address of RX buffer (256-byte aligned). */ ring->desc[i] = htole32(data->map->dm_segs[0].location >> 8); } // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, size, // BUS_DMASYNC_PREWRITE); return 0; fail: iwn_free_rx_ring(sc, ring); return error; } void ItlIwn:: iwn_reset_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) { int ntries; if (iwn_nic_lock(sc) == 0) { IWN_WRITE(sc, IWN_FH_RX_CONFIG, 0); for (ntries = 0; ntries < 1000; ntries++) { if (IWN_READ(sc, IWN_FH_RX_STATUS) & IWN_FH_RX_STATUS_IDLE) break; DELAY(10); } iwn_nic_unlock(sc); } ring->cur = 0; sc->last_rx_valid = 0; } void ItlIwn:: iwn_free_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) { int i; iwn_dma_contig_free(&ring->desc_dma); iwn_dma_contig_free(&ring->stat_dma); for (i = 0; i < IWN_RX_RING_COUNT; i++) { struct iwn_rx_data *data = &ring->data[i]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } if (data->map != NULL) { bus_dmamap_destroy(sc->sc_dmat, data->map); data->map = NULL; } } } int ItlIwn:: iwn_alloc_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring, int qid) { bus_addr_t paddr; bus_size_t size; int i, error; ring->qid = qid; ring->queued = 0; ring->cur = 0; /* Allocate TX descriptors (256-byte aligned). */ size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_desc); error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, (void **)&ring->desc, size, 256); if (error != 0) { XYLog("%s: could not allocate TX ring DMA memory\n", sc->sc_dev.dv_xname); goto fail; } size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_cmd); error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, (void **)&ring->cmd, size, 4); if (error != 0) { XYLog("%s: could not allocate TX cmd DMA memory\n", sc->sc_dev.dv_xname); goto fail; } paddr = ring->cmd_dma.paddr; for (i = 0; i < IWN_TX_RING_COUNT; i++) { struct iwn_tx_data *data = &ring->data[i]; data->cmd_paddr = paddr; data->scratch_paddr = paddr + 12; paddr += sizeof (struct iwn_tx_cmd); error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, IWN_MAX_SCATTER - 1, MCLBYTES, 0, BUS_DMA_NOWAIT, &data->map); if (error != 0) { XYLog("%s: could not create TX buf DMA map\n", sc->sc_dev.dv_xname); goto fail; } } return 0; fail: iwn_free_tx_ring(sc, ring); return error; } void ItlIwn:: iwn_reset_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring) { int i; for (i = 0; i < IWN_TX_RING_COUNT; i++) { struct iwn_tx_data *data = &ring->data[i]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } } /* Clear TX descriptors. */ memset(ring->desc, 0, ring->desc_dma.size); // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, // ring->desc_dma.size, BUS_DMASYNC_PREWRITE); sc->qfullmsk &= ~(1 << ring->qid); ring->queued = 0; ring->cur = 0; } void ItlIwn:: iwn_free_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring) { int i; iwn_dma_contig_free(&ring->desc_dma); iwn_dma_contig_free(&ring->cmd_dma); for (i = 0; i < IWN_TX_RING_COUNT; i++) { struct iwn_tx_data *data = &ring->data[i]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } if (data->map != NULL) { bus_dmamap_destroy(sc->sc_dmat, data->map); data->map = NULL; } } } void ItlIwn:: iwn5000_ict_reset(struct iwn_softc *sc) { /* Disable interrupts. */ IWN_WRITE(sc, IWN_INT_MASK, 0); /* Reset ICT table. */ memset(sc->ict, 0, IWN_ICT_SIZE); sc->ict_cur = 0; /* Set physical address of ICT table (4KB aligned). */ DPRINTF(("enabling ICT\n")); IWN_WRITE(sc, IWN_DRAM_INT_TBL, IWN_DRAM_INT_TBL_ENABLE | IWN_DRAM_INT_TBL_WRAP_CHECK | sc->ict_dma.paddr >> 12); /* Enable periodic RX interrupt. */ sc->int_mask |= IWN_INT_RX_PERIODIC; /* Switch to ICT interrupt mode in driver. */ sc->sc_flags |= IWN_FLAG_USE_ICT; /* Re-enable interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); } int ItlIwn:: iwn_read_eeprom(struct iwn_softc *sc) { struct iwn_ops *ops = &sc->ops; struct ieee80211com *ic = &sc->sc_ic; uint16_t val; int error; /* Check whether adapter has an EEPROM or an OTPROM. */ if (sc->hw_type >= IWN_HW_REV_TYPE_1000 && (IWN_READ(sc, IWN_OTP_GP) & IWN_OTP_GP_DEV_SEL_OTP)) sc->sc_flags |= IWN_FLAG_HAS_OTPROM; DPRINTF(("%s found\n", (sc->sc_flags & IWN_FLAG_HAS_OTPROM) ? "OTPROM" : "EEPROM")); /* Adapter has to be powered on for EEPROM access to work. */ if ((error = iwn_apm_init(sc)) != 0) { XYLog("%s: could not power ON adapter\n", sc->sc_dev.dv_xname); return error; } if ((IWN_READ(sc, IWN_EEPROM_GP) & 0x7) == 0) { XYLog("%s: bad ROM signature\n", sc->sc_dev.dv_xname); return EIO; } if ((error = iwn_eeprom_lock(sc)) != 0) { XYLog("%s: could not lock ROM (error=%d)\n", sc->sc_dev.dv_xname, error); return error; } if (sc->sc_flags & IWN_FLAG_HAS_OTPROM) { if ((error = iwn_init_otprom(sc)) != 0) { XYLog("%s: could not initialize OTPROM\n", sc->sc_dev.dv_xname); return error; } } iwn_read_prom_data(sc, IWN_EEPROM_SKU_CAP, &val, 2); DPRINTF(("SKU capabilities=0x%04x\n", letoh16(val))); /* Check if HT support is bonded out. */ if (val & htole16(IWN_EEPROM_SKU_CAP_11N)) sc->sc_flags |= IWN_FLAG_HAS_11N; iwn_read_prom_data(sc, IWN_EEPROM_RFCFG, &val, 2); sc->rfcfg = letoh16(val); DPRINTF(("radio config=0x%04x\n", sc->rfcfg)); /* Read Tx/Rx chains from ROM unless it's known to be broken. */ if (sc->txchainmask == 0) sc->txchainmask = IWN_RFCFG_TXANTMSK(sc->rfcfg); if (sc->rxchainmask == 0) sc->rxchainmask = IWN_RFCFG_RXANTMSK(sc->rfcfg); /* Read MAC address. */ iwn_read_prom_data(sc, IWN_EEPROM_MAC, ic->ic_myaddr, 6); /* Read adapter-specific information from EEPROM. */ ops->read_eeprom(sc); iwn_apm_stop(sc); /* Power OFF adapter. */ iwn_eeprom_unlock(sc); return 0; } void ItlIwn:: iwn4965_read_eeprom(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); uint32_t addr; uint16_t val; int i; /* Read regulatory domain (4 ASCII characters). */ that->iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4); /* Read the list of authorized channels. */ for (i = 0; i < 7; i++) { addr = iwn4965_regulatory_bands[i]; that->iwn_read_eeprom_channels(sc, i, addr); } /* Read maximum allowed TX power for 2GHz and 5GHz bands. */ that->iwn_read_prom_data(sc, IWN4965_EEPROM_MAXPOW, &val, 2); sc->maxpwr2GHz = val & 0xff; sc->maxpwr5GHz = val >> 8; /* Check that EEPROM values are within valid range. */ if (sc->maxpwr5GHz < 20 || sc->maxpwr5GHz > 50) sc->maxpwr5GHz = 38; if (sc->maxpwr2GHz < 20 || sc->maxpwr2GHz > 50) sc->maxpwr2GHz = 38; DPRINTF(("maxpwr 2GHz=%d 5GHz=%d\n", sc->maxpwr2GHz, sc->maxpwr5GHz)); /* Read samples for each TX power group. */ that->iwn_read_prom_data(sc, IWN4965_EEPROM_BANDS, sc->bands, sizeof sc->bands); /* Read voltage at which samples were taken. */ that->iwn_read_prom_data(sc, IWN4965_EEPROM_VOLTAGE, &val, 2); sc->eeprom_voltage = (int16_t)letoh16(val); DPRINTF(("voltage=%d (in 0.3V)\n", sc->eeprom_voltage)); #ifdef IWN_DEBUG /* Print samples. */ if (iwn_debug > 0) { for (i = 0; i < IWN_NBANDS; i++) that->iwn4965_print_power_group(sc, i); } #endif } #ifdef IWN_DEBUG void ItlIwn:: iwn4965_print_power_group(struct iwn_softc *sc, int i) { struct iwn4965_eeprom_band *band = &sc->bands[i]; struct iwn4965_eeprom_chan_samples *chans = band->chans; int j, c; XYLog("===band %d===\n", i); XYLog("chan lo=%d, chan hi=%d\n", band->lo, band->hi); XYLog("chan1 num=%d\n", chans[0].num); for (c = 0; c < 2; c++) { for (j = 0; j < IWN_NSAMPLES; j++) { XYLog("chain %d, sample %d: temp=%d gain=%d " "power=%d pa_det=%d\n", c, j, chans[0].samples[c][j].temp, chans[0].samples[c][j].gain, chans[0].samples[c][j].power, chans[0].samples[c][j].pa_det); } } XYLog("chan2 num=%d\n", chans[1].num); for (c = 0; c < 2; c++) { for (j = 0; j < IWN_NSAMPLES; j++) { XYLog("chain %d, sample %d: temp=%d gain=%d " "power=%d pa_det=%d\n", c, j, chans[1].samples[c][j].temp, chans[1].samples[c][j].gain, chans[1].samples[c][j].power, chans[1].samples[c][j].pa_det); } } } #endif void ItlIwn:: iwn5000_read_eeprom(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn5000_eeprom_calib_hdr hdr; int32_t volt; uint32_t base, addr; uint16_t val; int i; /* Read regulatory domain (4 ASCII characters). */ that->iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2); base = letoh16(val); that->iwn_read_prom_data(sc, base + IWN5000_EEPROM_DOMAIN, sc->eeprom_domain, 4); /* Read the list of authorized channels. */ for (i = 0; i < 7; i++) { addr = base + iwn5000_regulatory_bands[i]; that->iwn_read_eeprom_channels(sc, i, addr); } /* Read enhanced TX power information for 6000 Series. */ if (sc->hw_type >= IWN_HW_REV_TYPE_6000) that->iwn_read_eeprom_enhinfo(sc); that->iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2); base = letoh16(val); that->iwn_read_prom_data(sc, base, &hdr, sizeof hdr); DPRINTF(("calib version=%u pa type=%u voltage=%u\n", hdr.version, hdr.pa_type, letoh16(hdr.volt))); sc->calib_ver = hdr.version; if (sc->hw_type == IWN_HW_REV_TYPE_2030 || sc->hw_type == IWN_HW_REV_TYPE_2000 || sc->hw_type == IWN_HW_REV_TYPE_135 || sc->hw_type == IWN_HW_REV_TYPE_105) { sc->eeprom_voltage = letoh16(hdr.volt); that->iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); sc->eeprom_temp = letoh16(val); that->iwn_read_prom_data(sc, base + IWN2000_EEPROM_RAWTEMP, &val, 2); sc->eeprom_rawtemp = letoh16(val); } if (sc->hw_type == IWN_HW_REV_TYPE_5150) { /* Compute temperature offset. */ that->iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); sc->eeprom_temp = letoh16(val); that->iwn_read_prom_data(sc, base + IWN5000_EEPROM_VOLT, &val, 2); volt = letoh16(val); sc->temp_off = sc->eeprom_temp - (volt / -5); DPRINTF(("temp=%d volt=%d offset=%dK\n", sc->eeprom_temp, volt, sc->temp_off)); } else { /* Read crystal calibration. */ that->iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL, &sc->eeprom_crystal, sizeof (uint32_t)); DPRINTF(("crystal calibration 0x%08x\n", letoh32(sc->eeprom_crystal))); } } void ItlIwn:: iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) { struct ieee80211com *ic = &sc->sc_ic; const struct iwn_chan_band *band = &iwn_bands[n]; struct iwn_eeprom_chan channels[IWN_MAX_CHAN_PER_BAND]; uint8_t chan; int i; iwn_read_prom_data(sc, addr, channels, band->nchan * sizeof (struct iwn_eeprom_chan)); for (i = 0; i < band->nchan; i++) { if (!(channels[i].flags & IWN_EEPROM_CHAN_VALID)) continue; chan = band->chan[i]; if (n == 0) { /* 2GHz band */ ic->ic_channels[chan].ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; } else if (n < 5) { /* 5GHz band */ /* * Some adapters support channels 7, 8, 11 and 12 * both in the 2GHz and 4.9GHz bands. * Because of limitations in our net80211 layer, * we don't support them in the 4.9GHz band. */ if (chan <= 14) continue; ic->ic_channels[chan].ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A; /* We have at least one valid 5GHz channel. */ sc->sc_flags |= IWN_FLAG_HAS_5GHZ; } else { /* 40 MHz */ sc->maxpwr40[chan] = channels[i].maxpwr; ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_HT40; } /* Is active scan allowed on this channel? */ if (n < 5) { /* Is active scan allowed on this channel? */ if (!(channels[i].flags & IWN_EEPROM_CHAN_ACTIVE)) { ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_PASSIVE; } /* Save maximum allowed TX power for this channel. */ sc->maxpwr[chan] = channels[i].maxpwr; if (sc->sc_flags & IWN_FLAG_HAS_11N) ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_HT; } DPRINTF(("adding chan %d flags=0x%x maxpwr=%d maxpwr40=%d\n", chan, channels[i].flags, sc->maxpwr[chan], sc->maxpwr40[chan])); } } void ItlIwn:: iwn_read_eeprom_enhinfo(struct iwn_softc *sc) { struct iwn_eeprom_enhinfo enhinfo[35]; uint16_t val, base; int8_t maxpwr; int i; iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2); base = letoh16(val); iwn_read_prom_data(sc, base + IWN6000_EEPROM_ENHINFO, enhinfo, sizeof enhinfo); memset(sc->enh_maxpwr, 0, sizeof sc->enh_maxpwr); for (i = 0; i < nitems(enhinfo); i++) { if ((enhinfo[i].flags & IWN_TXP_VALID) == 0) continue; /* Skip invalid entries. */ maxpwr = 0; if (sc->txchainmask & IWN_ANT_A) maxpwr = MAX(maxpwr, enhinfo[i].chain[0]); if (sc->txchainmask & IWN_ANT_B) maxpwr = MAX(maxpwr, enhinfo[i].chain[1]); if (sc->txchainmask & IWN_ANT_C) maxpwr = MAX(maxpwr, enhinfo[i].chain[2]); if (sc->ntxchains == 2) maxpwr = MAX(maxpwr, enhinfo[i].mimo2); else if (sc->ntxchains == 3) maxpwr = MAX(maxpwr, enhinfo[i].mimo3); maxpwr /= 2; /* Convert half-dBm to dBm. */ DPRINTF(("enhinfo %d, maxpwr=%d\n", i, maxpwr)); sc->enh_maxpwr[i] = maxpwr; } } struct ieee80211_node * ItlIwn:: iwn_node_alloc(struct ieee80211com *ic) { return (ieee80211_node *)malloc(sizeof (struct iwn_node), M_DEVBUF, M_NOWAIT | M_ZERO); } void ItlIwn:: iwn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew) { struct iwn_softc *sc = (struct iwn_softc *)ic->ic_if.if_softc; struct iwn_node *wn = (struct iwn_node *)ni; uint8_t rate; int ridx, i; if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) ieee80211_amrr_node_init(&sc->amrr, &wn->amn); /* Start at lowest available bit-rate, AMRR/MiRA will raise. */ ni->ni_txrate = 0; ni->ni_txmcs = 0; for (i = 0; i < ni->ni_rates.rs_nrates; i++) { rate = ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL; /* Map 802.11 rate to HW rate index. */ for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) { if (iwn_rates[ridx].plcp != IWN_RATE_INVM_PLCP && iwn_rates[ridx].rate == rate) break; } wn->ridx[i] = ridx; } } int ItlIwn:: iwn_media_change(struct _ifnet *ifp) { struct iwn_softc *sc = (struct iwn_softc *)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; uint8_t rate, ridx; int error; error = ieee80211_media_change(ifp); if (error != ENETRESET) return error; if (ic->ic_fixed_mcs != -1) sc->fixed_ridx = iwn_mcs2ridx[ic->ic_fixed_mcs]; if (ic->ic_fixed_rate != -1) { rate = ic->ic_sup_rates[ic->ic_curmode]. rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; /* Map 802.11 rate to HW rate index. */ for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) if (iwn_rates[ridx].plcp != IWN_RATE_INVM_PLCP && iwn_rates[ridx].rate == rate) break; sc->fixed_ridx = ridx; } if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) { iwn_stop(ifp); error = iwn_init(ifp); } return error; } int ItlIwn:: iwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { XYLog("%s nstate=%d\n", __FUNCTION__, nstate); struct _ifnet *ifp = &ic->ic_if; struct iwn_softc *sc = (struct iwn_softc *)ifp->if_softc; struct ieee80211_node *ni = ic->ic_bss; ItlIwn *that = container_of(sc, ItlIwn, com); int error; if (ic->ic_state == IEEE80211_S_RUN) { if (nstate == IEEE80211_S_SCAN) { /* * During RUN->SCAN we don't call sc_newstate() so * we must stop A-MPDU Tx ourselves in this case. */ ieee80211_stop_ampdu_tx(ic, ni, -1); ieee80211_ba_del(ni); } timeout_del(&sc->calib_to); sc->calib.state = IWN_CALIB_STATE_INIT; if (sc->sc_flags & IWN_FLAG_BGSCAN) that->iwn_scan_abort(sc); } if (ic->ic_state == IEEE80211_S_SCAN) { if (nstate == IEEE80211_S_SCAN) { if (sc->sc_flags & IWN_FLAG_SCANNING) return 0; } else sc->sc_flags &= ~IWN_FLAG_SCANNING; /* Turn LED off when leaving scan state. */ that->iwn_set_led(sc, IWN_LED_LINK, 1, 0); } if (ic->ic_state >= IEEE80211_S_ASSOC && nstate <= IEEE80211_S_ASSOC) { /* Reset state to handle re- and disassociations. */ sc->rxon.associd = 0; sc->rxon.filter &= ~htole32(IWN_FILTER_BSS); sc->rxon.flags &= ~htole32(IWN_RXON_HT_CHANMODE_MIXED2040 | IWN_RXON_HT_CHANMODE_PURE40 | IWN_RXON_HT_HT40MINUS); sc->calib.state = IWN_CALIB_STATE_INIT; sc->agg_queue_mask = 0; error = that->iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); if (error != 0) XYLog("%s: RXON command failed\n", sc->sc_dev.dv_xname); } switch (nstate) { case IEEE80211_S_SCAN: /* Make the link LED blink while we're scanning. */ that->iwn_set_led(sc, IWN_LED_LINK, 10, 10); if ((sc->sc_flags & IWN_FLAG_BGSCAN) == 0) { ieee80211_set_link_state(ic, LINK_STATE_DOWN); ieee80211_node_cleanup(ic, ic->ic_bss); } if (ifp->if_flags & IFF_DEBUG) XYLog("%s: %s -> %s\n", ifp->if_xname, ieee80211_state_name[ic->ic_state], ieee80211_state_name[nstate]); ic->ic_state = nstate; if ((error = that->iwn_scan(sc, IEEE80211_CHAN_2GHZ, 0)) != 0) { printf("%s: could not initiate scan\n", sc->sc_dev.dv_xname); } return error; case IEEE80211_S_ASSOC: if (ic->ic_state != IEEE80211_S_RUN) break; /* FALLTHROUGH */ case IEEE80211_S_AUTH: if ((error = that->iwn_auth(sc, arg)) != 0) { XYLog("%s: could not move to auth state\n", sc->sc_dev.dv_xname); return error; } break; case IEEE80211_S_RUN: if ((error = that->iwn_run(sc)) != 0) { XYLog("%s: could not move to run state\n", sc->sc_dev.dv_xname); return error; } break; case IEEE80211_S_INIT: sc->calib.state = IWN_CALIB_STATE_INIT; break; } return sc->sc_newstate(ic, nstate, arg); } void ItlIwn:: iwn_iter_func(void *arg, struct ieee80211_node *ni) { struct iwn_softc *sc = (struct iwn_softc*)arg; struct iwn_node *wn = (struct iwn_node*)ni; ItlIwn *that = container_of(sc, ItlIwn, com); if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) { int old_txrate = ni->ni_txrate; ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn); if (old_txrate != ni->ni_txrate) that->iwn_set_link_quality(sc, ni); } } void ItlIwn:: iwn_calib_timeout(void *arg) { struct iwn_softc *sc = (struct iwn_softc *)arg; struct ieee80211com *ic = &sc->sc_ic; ItlIwn *that = container_of(sc, ItlIwn, com); int s; s = splnet(); if (ic->ic_fixed_rate == -1) { if (ic->ic_opmode == IEEE80211_M_STA) that->iwn_iter_func(sc, ic->ic_bss); else ieee80211_iterate_nodes(ic, iwn_iter_func, sc); } /* Force automatic TX power calibration every 60 secs. */ if (++sc->calib_cnt >= 120) { uint32_t flags = 0; DPRINTFN(2, ("sending request for statistics\n")); (void)that->iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, sizeof flags, 1); sc->calib_cnt = 0; } splx(s); /* Automatic rate control triggered every 500ms. */ timeout_add_msec(&sc->calib_to, 500); } int ItlIwn:: iwn_ccmp_decap(struct iwn_softc *sc, mbuf_t m, struct ieee80211_node *ni) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_key *k = &ni->ni_pairwise_key; struct ieee80211_frame *wh; uint64_t pn, *prsc; uint8_t *ivp; uint8_t tid; int hdrlen, hasqos; wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); ivp = (uint8_t *)wh + hdrlen; /* Check that ExtIV bit is set. */ if (!(ivp[3] & IEEE80211_WEP_EXTIV)) { DPRINTF(("CCMP decap ExtIV not set\n")); return 1; } hasqos = ieee80211_has_qos(wh); tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; prsc = &k->k_rsc[tid]; /* Extract the 48-bit PN from the CCMP header. */ pn = (uint64_t)ivp[0] | (uint64_t)ivp[1] << 8 | (uint64_t)ivp[4] << 16 | (uint64_t)ivp[5] << 24 | (uint64_t)ivp[6] << 32 | (uint64_t)ivp[7] << 40; if (pn <= *prsc) { ic->ic_stats.is_ccmp_replays++; return 1; } /* Last seen packet number is updated in ieee80211_inputm(). */ /* Strip MIC. IV will be stripped by ieee80211_inputm(). */ mbuf_adj(m, -IEEE80211_CCMP_MICLEN); return 0; } /* * Process an RX_PHY firmware notification. This is usually immediately * followed by an MPDU_RX_DONE notification. */ void ItlIwn:: iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_rx_stat *stat = (struct iwn_rx_stat *)(desc + 1); DPRINTFN(2, ("received PHY stats\n")); bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*stat), BUS_DMASYNC_POSTREAD); /* Save RX statistics, they will be used on MPDU_RX_DONE. */ memcpy(&sc->last_rx_stat, stat, sizeof (*stat)); sc->last_rx_valid = IWN_LAST_RX_VALID; /* * The firmware does not send separate RX_PHY * notifications for A-MPDU subframes. */ if (stat->flags & htole16(IWN_STAT_FLAG_AGG)) sc->last_rx_valid |= IWN_LAST_RX_AMPDU; } /* * Process an RX_DONE (4965AGN only) or MPDU_RX_DONE firmware notification. * Each MPDU_RX_DONE notification must be preceded by an RX_PHY one. */ void ItlIwn:: iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data, struct mbuf_list *ml) { struct iwn_ops *ops = &sc->ops; struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; struct iwn_rx_ring *ring = &sc->rxq; struct ieee80211_frame *wh; struct ieee80211_rxinfo rxi; struct ieee80211_node *ni; mbuf_t m, m1; struct iwn_rx_stat *stat; caddr_t head; uint32_t flags; int error, len, rssi; uint16_t chan; if (desc->type == IWN_MPDU_RX_DONE) { /* Check for prior RX_PHY notification. */ if (!sc->last_rx_valid) { DPRINTF(("missing RX_PHY\n")); return; } sc->last_rx_valid &= ~IWN_LAST_RX_VALID; stat = &sc->last_rx_stat; if ((sc->last_rx_valid & IWN_LAST_RX_AMPDU) && (stat->flags & htole16(IWN_STAT_FLAG_AGG)) == 0) { DPRINTF(("missing RX_PHY (expecting A-MPDU)\n")); return; } if ((sc->last_rx_valid & IWN_LAST_RX_AMPDU) == 0 && (stat->flags & htole16(IWN_STAT_FLAG_AGG))) { DPRINTF(("missing RX_PHY (unexpected A-MPDU)\n")); return; } } else stat = (struct iwn_rx_stat *)(desc + 1); bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWN_RBUF_SIZE, BUS_DMASYNC_POSTREAD); if (stat->cfg_phy_len > IWN_STAT_MAXLEN) { XYLog("%s: invalid RX statistic header\n", sc->sc_dev.dv_xname); return; } if (desc->type == IWN_MPDU_RX_DONE) { struct iwn_rx_mpdu *mpdu = (struct iwn_rx_mpdu *)(desc + 1); head = (caddr_t)(mpdu + 1); len = letoh16(mpdu->len); } else { head = (caddr_t)(stat + 1) + stat->cfg_phy_len; len = letoh16(stat->len); } flags = letoh32(*(uint32_t *)(head + len)); /* Discard frames with a bad FCS early. */ if ((flags & IWN_RX_NOERROR) != IWN_RX_NOERROR) { DPRINTFN(2, ("RX flags error %x\n", flags)); ifp->netStat->inputErrors++; return; } /* Discard frames that are too short. */ if (ic->ic_opmode == IEEE80211_M_MONITOR) { /* Allow control frames in monitor mode. */ if (len < sizeof (struct ieee80211_frame_cts)) { ic->ic_stats.is_rx_tooshort++; ifp->netStat->inputErrors++; return; } } else if (len < sizeof (*wh)) { ic->ic_stats.is_rx_tooshort++; ifp->netStat->inputErrors++; return; } m1 = getController()->allocatePacket(IWN_RBUF_SIZE); if (m1 == NULL) { XYLog("could not allocate RX mbuf\n"); ic->ic_stats.is_rx_nombuf++; ifp->netStat->inputErrors++; return; } data->map->dm_nsegs = data->map->cursor->getPhysicalSegments(m1, &data->map->dm_segs[0], 1); if (data->map->dm_nsegs == 0) { XYLog("could not map RX mbuf\n"); mbuf_freem(m1); ifp->netStat->inputErrors++; return; } // m1 = MCLGETI(NULL, M_DONTWAIT, NULL, IWN_RBUF_SIZE); // if (m1 == NULL) { // ic->ic_stats.is_rx_nombuf++; // ifp->netStat->inputErrors++; // return; // } // bus_dmamap_unload(sc->sc_dmat, data->map); // // error = bus_dmamap_load(sc->sc_dmat, data->map, mtod(m1, void *), // IWN_RBUF_SIZE, NULL, BUS_DMA_NOWAIT | BUS_DMA_READ); // if (error != 0) { // mbuf_freem(m1); // // /* Try to reload the old mbuf. */ // error = bus_dmamap_load(sc->sc_dmat, data->map, // mtod(data->m, void *), IWN_RBUF_SIZE, NULL, // BUS_DMA_NOWAIT | BUS_DMA_READ); // if (error != 0) { // panic("%s: could not load old RX mbuf", // sc->sc_dev.dv_xname); // } // /* Physical address may have changed. */ // ring->desc[ring->cur] = // htole32(data->map->dm_segs[0].ds_addr >> 8); // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, // ring->cur * sizeof (uint32_t), sizeof (uint32_t), // BUS_DMASYNC_PREWRITE); // ifp->netStat->inputErrors++; // return; // } m = data->m; data->m = m1; /* Update RX descriptor. */ ring->desc[ring->cur] = htole32(data->map->dm_segs[0].location >> 8); // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, // ring->cur * sizeof (uint32_t), sizeof (uint32_t), // BUS_DMASYNC_PREWRITE); /* Finalize mbuf. */ // m->m_data = pktdata + sizeof(*desc); // m->m_pkthdr.len = m->m_len = len; mbuf_setdata(m, head, len); mbuf_pkthdr_setlen(m, len); mbuf_setlen(m, len); /* * Grab a reference to the source node. Note that control frames are * shorter than struct ieee80211_frame but ieee80211_find_rxnode() * is being careful about control frames. */ wh = mtod(m, struct ieee80211_frame *); if (len < sizeof (*wh) && (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) { ic->ic_stats.is_rx_tooshort++; ifp->netStat->inputErrors++; mbuf_freem(m); return; } ni = ieee80211_find_rxnode(ic, wh); memset(&rxi, 0, sizeof(rxi)); if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && !IEEE80211_IS_MULTICAST(wh->i_addr1) && (ni->ni_flags & IEEE80211_NODE_RXPROT) && ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) { if ((flags & IWN_RX_CIPHER_MASK) != IWN_RX_CIPHER_CCMP) { ic->ic_stats.is_ccmp_dec_errs++; ifp->netStat->inputErrors++; mbuf_freem(m); ieee80211_release_node(ic, ni); return; } /* Check whether decryption was successful or not. */ if ((desc->type == IWN_MPDU_RX_DONE && (flags & (IWN_RX_MPDU_DEC | IWN_RX_MPDU_MIC_OK)) != (IWN_RX_MPDU_DEC | IWN_RX_MPDU_MIC_OK)) || (desc->type != IWN_MPDU_RX_DONE && (flags & IWN_RX_DECRYPT_MASK) != IWN_RX_DECRYPT_OK)) { DPRINTF(("CCMP decryption failed 0x%x\n", flags)); ic->ic_stats.is_ccmp_dec_errs++; ifp->netStat->inputErrors++; mbuf_freem(m); ieee80211_release_node(ic, ni); return; } if (iwn_ccmp_decap(sc, m, ni) != 0) { ifp->netStat->inputErrors++; mbuf_freem(m); ieee80211_release_node(ic, ni); return; } rxi.rxi_flags |= IEEE80211_RXI_HWDEC; } rssi = ops->get_rssi(stat); rssi = (0 - IWN_MIN_DBM) + rssi; /* normalize */ rssi = MIN(rssi, ic->ic_max_rssi); /* clip to max. 100% */ chan = stat->chan; if (chan > IEEE80211_CHAN_MAX) chan = IEEE80211_CHAN_MAX; #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap; uint16_t chan_flags; tap->wr_flags = 0; if (stat->flags & htole16(IWN_STAT_FLAG_SHPREAMBLE)) tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; tap->wr_chan_freq = htole16(ic->ic_channels[chan].ic_freq); chan_flags = ic->ic_channels[chan].ic_flags; if (ic->ic_curmode != IEEE80211_MODE_11N) chan_flags &= ~IEEE80211_CHAN_HT; tap->wr_chan_flags = htole16(chan_flags); tap->wr_dbm_antsignal = (int8_t)rssi; tap->wr_dbm_antnoise = (int8_t)sc->noise; tap->wr_tsft = stat->tstamp; if (stat->rflags & IWN_RFLAG_MCS) { tap->wr_rate = (0x80 | stat->rate); /* HT MCS index */ } else { switch (stat->rate) { /* CCK rates. */ case 10: tap->wr_rate = 2; break; case 20: tap->wr_rate = 4; break; case 55: tap->wr_rate = 11; break; case 110: tap->wr_rate = 22; break; /* OFDM rates. */ case 0xd: tap->wr_rate = 12; break; case 0xf: tap->wr_rate = 18; break; case 0x5: tap->wr_rate = 24; break; case 0x7: tap->wr_rate = 36; break; case 0x9: tap->wr_rate = 48; break; case 0xb: tap->wr_rate = 72; break; case 0x1: tap->wr_rate = 96; break; case 0x3: tap->wr_rate = 108; break; /* Unknown rate: should not happen. */ default: tap->wr_rate = 0; } } bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m, BPF_DIRECTION_IN); } #endif /* Send the frame to the 802.11 layer. */ rxi.rxi_rssi = rssi; rxi.rxi_chan = chan; ieee80211_inputm(ifp, m, ni, &rxi, ml); /* Node is no longer needed. */ ieee80211_release_node(ic, ni); } void ItlIwn:: iwn_ra_choose(struct iwn_softc *sc, struct ieee80211_node *ni) { struct ieee80211com *ic = &sc->sc_ic; struct iwn_node *wn = (struct iwn_node *)ni; int old_txmcs = ni->ni_txmcs; ieee80211_ra_choose(&wn->rn, ic, ni); /* Update firmware's LQ retry table if RA has chosen a new MCS. */ if (ni->ni_txmcs != old_txmcs) iwn_set_link_quality(sc, ni); } void ItlIwn:: iwn_ampdu_rate_control(struct iwn_softc *sc, struct ieee80211_node *ni, struct iwn_tx_ring *txq, uint16_t seq, uint16_t ssn) { struct ieee80211com *ic = &sc->sc_ic; struct iwn_node *wn = (struct iwn_node *)ni; int idx, end_idx; /* * Update Tx rate statistics for A-MPDUs before firmware's BA window. */ idx = IWN_AGG_SSN_TO_TXQ_IDX(seq); end_idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn); while (idx != end_idx) { struct iwn_tx_data *txdata = &txq->data[idx]; if (txdata->m != NULL && txdata->ampdu_nframes > 1) { /* * We can assume that this subframe has been ACKed * because ACK failures come as single frames and * before failing an A-MPDU subframe the firmware * sends it as a single frame at least once. */ ieee80211_ra_add_stats_ht(&wn->rn, ic, ni, txdata->ampdu_txmcs, 1, 0); /* Report this frame only once. */ txdata->ampdu_nframes = 0; } idx = (idx + 1) % IWN_TX_RING_COUNT; } iwn_ra_choose(sc, ni); } void ItlIwn:: iwn_ht_single_rate_control(struct iwn_softc *sc, struct ieee80211_node *ni, uint8_t rate, uint8_t rflags, uint8_t ackfailcnt, int txfail) { struct ieee80211com *ic = &sc->sc_ic; struct iwn_node *wn = (struct iwn_node *)ni; int mcs = rate; const struct ieee80211_ra_rate *rs; unsigned int retries = 0, i; /* * Ignore Tx reports which don't match our last LQ command. */ if (rate != ni->ni_txmcs) { if (++wn->lq_rate_mismatch > 15) { /* Try to sync firmware with driver. */ iwn_set_link_quality(sc, ni); wn->lq_rate_mismatch = 0; } return; } wn->lq_rate_mismatch = 0; rs = ieee80211_ra_get_rateset(&wn->rn, ic, ni, rate); /* * Firmware has attempted rates in this rate set in sequence. * Retries at a basic rate are counted against the minimum MCS. */ for (i = 0; i < ackfailcnt; i++) { if (mcs > rs->min_mcs) { ieee80211_ra_add_stats_ht(&wn->rn, ic, ni, mcs, 1, 1); mcs--; } else retries++; } if (txfail && ackfailcnt == 0) ieee80211_ra_add_stats_ht(&wn->rn, ic, ni, mcs, 1, 1); else ieee80211_ra_add_stats_ht(&wn->rn, ic, ni, mcs, retries + 1, retries); iwn_ra_choose(sc, ni); } /* * Process an incoming Compressed BlockAck. * Note that these block ack notifications are generated by firmware and do * not necessarily correspond to contents of block ack frames seen on the air. */ void ItlIwn:: iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_compressed_ba *cba = (struct iwn_compressed_ba *)(desc + 1); struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; struct ieee80211_tx_ba *ba; struct iwn_tx_ring *txq; uint16_t seq, ssn; int qid; if (ic->ic_state != IEEE80211_S_RUN) return; bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*cba), BUS_DMASYNC_POSTREAD); if (!IEEE80211_ADDR_EQ(ic->ic_bss->ni_macaddr, cba->macaddr)) return; ni = ic->ic_bss; qid = le16toh(cba->qid); if (qid < sc->first_agg_txq || qid >= sc->ntxqs) return; txq = &sc->txq[qid]; /* Protect against a firmware bug where the queue/TID are off. */ if (qid != sc->first_agg_txq + cba->tid) return; ba = &ni->ni_tx_ba[cba->tid]; if (ba->ba_state != IEEE80211_BA_AGREED) return; /* * The first bit in cba->bitmap corresponds to the sequence number * stored in the sequence control field cba->seq. * Multiple BA notifications in a row may be using this number, with * additional bits being set in cba->bitmap. It is unclear how the * firmware decides to shift this window forward. * We rely on ba->ba_winstart instead. */ seq = le16toh(cba->seq) >> IEEE80211_SEQ_SEQ_SHIFT; /* * The firmware's new BA window starting sequence number * corresponds to the first hole in cba->bitmap, implying * that all frames between 'seq' and 'ssn' (non-inclusive) * have been acked. */ ssn = le16toh(cba->ssn); if (SEQ_LT(ssn, ba->ba_winstart)) return; /* Skip rate control if our Tx rate is fixed. */ if (ic->ic_fixed_mcs == -1) iwn_ampdu_rate_control(sc, ni, txq, ba->ba_winstart, ssn); /* * SSN corresponds to the first (perhaps not yet transmitted) frame * in firmware's BA window. Firmware is not going to retransmit any * frames before its BA window so mark them all as done. */ ieee80211_output_ba_move_window(ic, ni, cba->tid, ssn); iwn_ampdu_txq_advance(sc, txq, qid, IWN_AGG_SSN_TO_TXQ_IDX(ssn)); iwn_clear_oactive(sc, txq); } /* * Process a CALIBRATION_RESULT notification sent by the initialization * firmware on response to a CMD_CALIB_CONFIG command (5000 only). */ void ItlIwn:: iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1); int len, idx = -1; /* Runtime firmware should not send such a notification. */ if (sc->sc_flags & IWN_FLAG_CALIB_DONE) return; len = (letoh32(desc->len) & IWN_RX_DESC_LEN_MASK) - 4; bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), len, BUS_DMASYNC_POSTREAD); switch (calib->code) { case IWN5000_PHY_CALIB_DC: if (sc->hw_type == IWN_HW_REV_TYPE_5150 || sc->hw_type == IWN_HW_REV_TYPE_2030 || sc->hw_type == IWN_HW_REV_TYPE_2000 || sc->hw_type == IWN_HW_REV_TYPE_135 || sc->hw_type == IWN_HW_REV_TYPE_105) idx = 0; break; case IWN5000_PHY_CALIB_LO: idx = 1; break; case IWN5000_PHY_CALIB_TX_IQ: idx = 2; break; case IWN5000_PHY_CALIB_TX_IQ_PERIODIC: if (sc->hw_type < IWN_HW_REV_TYPE_6000 && sc->hw_type != IWN_HW_REV_TYPE_5150) idx = 3; break; case IWN5000_PHY_CALIB_BASE_BAND: idx = 4; break; } if (idx == -1) /* Ignore other results. */ return; /* Save calibration result. */ if (sc->calibcmd[idx].buf != NULL) ::free(sc->calibcmd[idx].buf); sc->calibcmd[idx].buf = (uint8_t *)malloc(len, M_DEVBUF, M_NOWAIT); if (sc->calibcmd[idx].buf == NULL) { DPRINTF(("not enough memory for calibration result %d\n", calib->code)); return; } DPRINTF(("saving calibration result code=%d len=%d\n", calib->code, len)); sc->calibcmd[idx].len = len; memcpy(sc->calibcmd[idx].buf, calib, len); } /* * Process an RX_STATISTICS or BEACON_STATISTICS firmware notification. * The latter is sent by the firmware after each received beacon. */ void ItlIwn:: iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_ops *ops = &sc->ops; struct ieee80211com *ic = &sc->sc_ic; struct iwn_calib_state *calib = &sc->calib; struct iwn_stats *stats = (struct iwn_stats *)(desc + 1); int temp; /* Ignore statistics received during a scan. */ if (ic->ic_state != IEEE80211_S_RUN) return; bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*stats), BUS_DMASYNC_POSTREAD); DPRINTFN(3, ("received statistics (cmd=%d)\n", desc->type)); sc->calib_cnt = 0; /* Reset TX power calibration timeout. */ sc->rx_stats_flags = htole32(stats->flags); /* Test if temperature has changed. */ if (stats->general.temp != sc->rawtemp) { /* Convert "raw" temperature to degC. */ sc->rawtemp = stats->general.temp; temp = ops->get_temperature(sc); DPRINTFN(2, ("temperature=%dC\n", temp)); /* Update TX power if need be (4965AGN only). */ if (sc->hw_type == IWN_HW_REV_TYPE_4965) iwn4965_power_calibration(sc, temp); } if (desc->type != IWN_BEACON_STATISTICS) return; /* Reply to a statistics request. */ sc->noise = iwn_get_noise(&stats->rx.general); /* Test that RSSI and noise are present in stats report. */ if (sc->noise == -127) return; if (letoh32(stats->rx.general.flags) != 1) { DPRINTF(("received statistics without RSSI\n")); return; } /* * XXX Differential gain calibration makes the 6005 firmware * crap out, so skip it for now. This effectively disables * sensitivity tuning as well. */ if (sc->hw_type == IWN_HW_REV_TYPE_6005) return; if (calib->state == IWN_CALIB_STATE_ASSOC) iwn_collect_noise(sc, &stats->rx.general); else if (calib->state == IWN_CALIB_STATE_RUN) iwn_tune_sensitivity(sc, &stats->rx); } void ItlIwn:: iwn_ampdu_txq_advance(struct iwn_softc *sc, struct iwn_tx_ring *txq, int qid, int idx) { struct iwn_ops *ops = &sc->ops; DPRINTFN(3, ("%s: txq->cur=%d txq->read=%d txq->queued=%d qid=%d " "idx=%d\n", __func__, txq->cur, txq->read, txq->queued, qid, idx)); while (txq->read != idx) { struct iwn_tx_data *txdata = &txq->data[txq->read]; if (txdata->m != NULL) { ops->reset_sched(sc, qid, txq->read); iwn_tx_done_free_txdata(sc, txdata); txq->queued--; } txq->read = (txq->read + 1) % IWN_TX_RING_COUNT; } } /* * Handle A-MPDU Tx queue status report. * Tx failures come as single frames (perhaps out of order), and before failing * an A-MPDU subframe the firmware transmits it as a single frame at least once. * Frames successfully transmitted in an A-MPDU are completed when a compressed * block ack notification is received. */ void ItlIwn:: iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_ring *txq, struct iwn_rx_desc *desc, uint16_t status, uint8_t ackfailcnt, uint8_t rate, uint8_t rflags, int nframes, uint32_t ssn, struct iwn_txagg_status *agg_status) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; int tid = desc->qid - sc->first_agg_txq; struct iwn_tx_data *txdata = &txq->data[desc->idx]; struct ieee80211_node *ni = txdata->ni; int txfail = (status != IWN_TX_STATUS_SUCCESS && status != IWN_TX_STATUS_DIRECT_DONE); struct ieee80211_tx_ba *ba; uint16_t seq; sc->sc_tx_timer = 0; if (ic->ic_state != IEEE80211_S_RUN) return; if (nframes > 1) { int i; /* * Collect information about this A-MPDU. */ for (i = 0; i < nframes; i++) { uint8_t qid = agg_status[i].qid; uint8_t idx = agg_status[i].idx; uint16_t txstatus = (le16toh(agg_status[i].status) & IWN_AGG_TX_STATUS_MASK); if (txstatus != IWN_AGG_TX_STATE_TRANSMITTED) continue; if (qid != desc->qid) continue; txdata = &txq->data[idx]; if (txdata->ni == NULL) continue; /* The Tx rate was the same for all subframes. */ txdata->ampdu_txmcs = rate; txdata->ampdu_nframes = nframes; } return; } if (ni == NULL) return; ba = &ni->ni_tx_ba[tid]; if (ba->ba_state != IEEE80211_BA_AGREED) return; if (SEQ_LT(ssn, ba->ba_winstart)) return; /* This was a final single-frame Tx attempt for frame SSN-1. */ seq = (ssn - 1) & 0xfff; /* * Skip rate control if our Tx rate is fixed. */ if (ic->ic_fixed_mcs == -1) { if (txdata->ampdu_nframes > 1) { struct iwn_node *wn = (struct iwn_node *)ni; /* * This frame was once part of an A-MPDU. * Report one failed A-MPDU Tx attempt. * The firmware might have made several such * attempts but we don't keep track of this. */ ieee80211_ra_add_stats_ht(&wn->rn, ic, ni, txdata->ampdu_txmcs, 1, 1); } /* Report the final single-frame Tx attempt. */ if (rflags & IWN_RFLAG_MCS) iwn_ht_single_rate_control(sc, ni, rate, rflags, ackfailcnt, txfail); } if (txfail) ieee80211_tx_compressed_bar(ic, ni, tid, ssn); /* * SSN corresponds to the first (perhaps not yet transmitted) frame * in firmware's BA window. Firmware is not going to retransmit any * frames before its BA window so mark them all as done. */ ieee80211_output_ba_move_window(ic, ni, tid, ssn); iwn_ampdu_txq_advance(sc, txq, desc->qid, IWN_AGG_SSN_TO_TXQ_IDX(ssn)); iwn_clear_oactive(sc, txq); } /* * Process a TX_DONE firmware notification. Unfortunately, the 4965AGN * and 5000 adapters have different incompatible TX status formats. */ void ItlIwn:: iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn4965_tx_stat *stat = (struct iwn4965_tx_stat *)(desc + 1); struct iwn_tx_ring *ring; size_t len = (letoh32(desc->len) & IWN_RX_DESC_LEN_MASK); uint16_t status = letoh32(stat->stat.status) & 0xff; uint32_t ssn; if (desc->qid > IWN4965_NTXQUEUES) return; ring = &sc->txq[desc->qid]; bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), len, BUS_DMASYNC_POSTREAD); /* Sanity checks. */ if (sizeof(*stat) > len) return; if (stat->nframes < 1 || stat->nframes > IWN_AMPDU_MAX) return; if (desc->qid < sc->first_agg_txq && stat->nframes > 1) return; if (desc->qid >= sc->first_agg_txq && sizeof(*stat) + sizeof(ssn) + stat->nframes * sizeof(stat->stat) > len) return; if (desc->qid < sc->first_agg_txq) { /* XXX 4965 does not report byte count */ struct iwn_tx_data *txdata = &ring->data[desc->idx]; uint16_t framelen = txdata->totlen + IEEE80211_CRC_LEN; int txfail = (status != IWN_TX_STATUS_SUCCESS && status != IWN_TX_STATUS_DIRECT_DONE); that->iwn_tx_done(sc, desc, stat->ackfailcnt, stat->rate, stat->rflags, txfail, desc->qid, framelen); } else { memcpy(&ssn, &stat->stat.status + stat->nframes, sizeof(ssn)); ssn = le32toh(ssn) & 0xfff; that->iwn_ampdu_tx_done(sc, ring, desc, status, stat->ackfailcnt, stat->rate, stat->rflags, stat->nframes, ssn, stat->stat.agg_status); } } void ItlIwn:: iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn5000_tx_stat *stat = (struct iwn5000_tx_stat *)(desc + 1); struct iwn_tx_ring *ring; size_t len = (letoh32(desc->len) & IWN_RX_DESC_LEN_MASK); uint16_t status = letoh32(stat->stat.status) & 0xff; uint32_t ssn; if (desc->qid > IWN5000_NTXQUEUES) return; ring = &sc->txq[desc->qid]; bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*stat), BUS_DMASYNC_POSTREAD); /* Sanity checks. */ if (sizeof(*stat) > len) return; if (stat->nframes < 1 || stat->nframes > IWN_AMPDU_MAX) return; if (desc->qid < sc->first_agg_txq && stat->nframes > 1) return; if (desc->qid >= sc->first_agg_txq && sizeof(*stat) + sizeof(ssn) + stat->nframes * sizeof(stat->stat) > len) return; /* If this was not an aggregated frame, complete it now. */ if (desc->qid < sc->first_agg_txq) { int txfail = (status != IWN_TX_STATUS_SUCCESS && status != IWN_TX_STATUS_DIRECT_DONE); /* Reset TX scheduler slot. */ iwn5000_reset_sched(sc, desc->qid, desc->idx); that->iwn_tx_done(sc, desc, stat->ackfailcnt, stat->rate, stat->rflags, txfail, desc->qid, letoh16(stat->len)); } else { memcpy(&ssn, &stat->stat.status + stat->nframes, sizeof(ssn)); ssn = le32toh(ssn) & 0xfff; that->iwn_ampdu_tx_done(sc, ring, desc, status, stat->ackfailcnt, stat->rate, stat->rflags, stat->nframes, ssn, stat->stat.agg_status); } } void ItlIwn:: iwn_tx_done_free_txdata(struct iwn_softc *sc, struct iwn_tx_data *data) { struct ieee80211com *ic = &sc->sc_ic; // bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, // BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; ieee80211_release_node(ic, data->ni); data->ni = NULL; data->totlen = 0; data->ampdu_nframes = 0; data->ampdu_txmcs = 0; } void ItlIwn:: iwn_clear_oactive(struct iwn_softc *sc, struct iwn_tx_ring *ring) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; if (ring->queued < IWN_TX_RING_LOMARK) { sc->qfullmsk &= ~(1 << ring->qid); if (sc->qfullmsk == 0 && ifq_is_oactive(&ifp->if_snd)) { ifq_clr_oactive(&ifp->if_snd); (*ifp->if_start)(ifp); } #ifdef __PRIVATE_SPI__ ifp->iface->signalOutputThread(); #endif } } /* * Adapter-independent backend for TX_DONE firmware notifications. * This handles Tx status for non-aggregation queues. */ void ItlIwn:: iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, uint8_t ackfailcnt, uint8_t rate, uint8_t rflags, int txfail, int qid, uint16_t len) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; struct iwn_tx_ring *ring = &sc->txq[qid]; struct iwn_tx_data *data = &ring->data[desc->idx]; struct iwn_node *wn = (struct iwn_node *)data->ni; if (data->ni == NULL) return; if (data->ni->ni_flags & IEEE80211_NODE_HT) { if (ic->ic_state == IEEE80211_S_RUN && ic->ic_fixed_mcs == -1 && (rflags & IWN_RFLAG_MCS)) { iwn_ht_single_rate_control(sc, data->ni, rate, rflags, ackfailcnt, txfail); } } else { if (rate != data->ni->ni_txrate) { if (++wn->lq_rate_mismatch > 15) { /* Try to sync firmware with driver. */ iwn_set_link_quality(sc, data->ni); wn->lq_rate_mismatch = 0; } } else { wn->lq_rate_mismatch = 0; wn->amn.amn_txcnt++; if (ackfailcnt > 0) wn->amn.amn_retrycnt++; if (txfail) wn->amn.amn_retrycnt++; } } if (txfail) { ifp->netStat->outputErrors++; } iwn_tx_done_free_txdata(sc, data); sc->sc_tx_timer = 0; ring->queued--; iwn_clear_oactive(sc, ring); } /* * Process a "command done" firmware notification. This is where we wakeup * processes waiting for a synchronous command completion. */ void ItlIwn:: iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc) { struct iwn_tx_ring *ring = &sc->txq[4]; struct iwn_tx_data *data; if ((desc->qid & 0xf) != 4) return; /* Not a command ack. */ data = &ring->data[desc->idx]; /* If the command was mapped in an mbuf, free it. */ if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } wakeupOn(&ring->desc[desc->idx]); } /* * Process an INT_FH_RX or INT_SW_RX interrupt. */ void ItlIwn:: iwn_notif_intr(struct iwn_softc *sc) { struct mbuf_list ml = MBUF_LIST_INITIALIZER(); struct iwn_ops *ops = &sc->ops; struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; uint16_t hw; // bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map, // 0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD); hw = letoh16(sc->rxq.stat->closed_count) & 0xfff; while (sc->rxq.cur != hw) { struct iwn_rx_data *data = &sc->rxq.data[sc->rxq.cur]; struct iwn_rx_desc *desc; bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof (*desc), BUS_DMASYNC_POSTREAD); desc = mtod(data->m, struct iwn_rx_desc *); DPRINTFN(4, ("notification qid=%d idx=%d flags=%x type=%d\n", desc->qid & 0xf, desc->idx, desc->flags, desc->type)); if (!(desc->qid & 0x80)) /* Reply to a command. */ iwn_cmd_done(sc, desc); switch (desc->type) { case IWN_RX_PHY: iwn_rx_phy(sc, desc, data); break; case IWN_RX_DONE: /* 4965AGN only. */ case IWN_MPDU_RX_DONE: /* An 802.11 frame has been received. */ iwn_rx_done(sc, desc, data, &ml); break; case IWN_RX_COMPRESSED_BA: /* A Compressed BlockAck has been received. */ iwn_rx_compressed_ba(sc, desc, data); break; case IWN_TX_DONE: /* An 802.11 frame has been transmitted. */ ops->tx_done(sc, desc, data); break; case IWN_RX_STATISTICS: case IWN_BEACON_STATISTICS: iwn_rx_statistics(sc, desc, data); break; case IWN_BEACON_MISSED: { struct iwn_beacon_missed *miss = (struct iwn_beacon_missed *)(desc + 1); uint32_t missed; if ((ic->ic_opmode != IEEE80211_M_STA) || (ic->ic_state != IEEE80211_S_RUN)) break; bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*miss), BUS_DMASYNC_POSTREAD); missed = letoh32(miss->consecutive); /* * If more than 5 consecutive beacons are missed, * reinitialize the sensitivity state machine. */ if (missed > 5) (void)iwn_init_sensitivity(sc); /* * Rather than go directly to scan state, try to send a * directed probe request first. If that fails then the * state machine will drop us into scanning after timing * out waiting for a probe response. */ if (missed > ic->ic_bmissthres && !ic->ic_mgt_timer) { if (ic->ic_if.if_flags & IFF_DEBUG) XYLog("%s: receiving no beacons from " "%s; checking if this AP is still " "responding to probe requests\n", sc->sc_dev.dv_xname, ether_sprintf( ic->ic_bss->ni_macaddr)); IEEE80211_SEND_MGMT(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); } break; } case IWN_UC_READY: { struct iwn_ucode_info *uc = (struct iwn_ucode_info *)(desc + 1); /* The microcontroller is ready. */ bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*uc), BUS_DMASYNC_POSTREAD); DPRINTF(("microcode alive notification version=%d.%d " "subtype=%x alive=%x\n", uc->major, uc->minor, uc->subtype, letoh32(uc->valid))); if (letoh32(uc->valid) != 1) { XYLog("%s: microcontroller initialization " "failed\n", sc->sc_dev.dv_xname); break; } if (uc->subtype == IWN_UCODE_INIT) { /* Save microcontroller report. */ memcpy(&sc->ucode_info, uc, sizeof (*uc)); } /* Save the address of the error log in SRAM. */ sc->errptr = letoh32(uc->errptr); break; } case IWN_STATE_CHANGED: { uint32_t *status = (uint32_t *)(desc + 1); /* Enabled/disabled notification. */ bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*status), BUS_DMASYNC_POSTREAD); DPRINTF(("state changed to %x\n", letoh32(*status))); if (letoh32(*status) & 1) { /* Radio transmitter is off, power down. */ iwn_stop(ifp); return; /* No further processing. */ } break; } case IWN_START_SCAN: { struct iwn_start_scan *scan = (struct iwn_start_scan *)(desc + 1); bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*scan), BUS_DMASYNC_POSTREAD); DPRINTFN(2, ("scan start: chan %d status %x\n", scan->chan, letoh32(scan->status))); if (sc->sc_flags & IWN_FLAG_BGSCAN) break; /* Fix current channel. */ ic->ic_bss->ni_chan = &ic->ic_channels[scan->chan]; break; } case IWN_STOP_SCAN: { struct iwn_stop_scan *scan = (struct iwn_stop_scan *)(desc + 1); bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*scan), BUS_DMASYNC_POSTREAD); DPRINTFN(2, ("scan stop: nchan=%d status=%d chan=%d\n", scan->nchan, scan->status, scan->chan)); if (scan->status == 1 && scan->chan <= 14 && (sc->sc_flags & IWN_FLAG_HAS_5GHZ)) { int error; /* * We just finished scanning 2GHz channels, * start scanning 5GHz ones. */ error = iwn_scan(sc, IEEE80211_CHAN_5GHZ, (sc->sc_flags & IWN_FLAG_BGSCAN) ? 1 : 0); if (error == 0) break; } sc->sc_flags &= ~IWN_FLAG_SCANNING; sc->sc_flags &= ~IWN_FLAG_BGSCAN; ieee80211_end_scan(ifp); break; } case IWN5000_CALIBRATION_RESULT: iwn5000_rx_calib_results(sc, desc, data); break; case IWN5000_CALIBRATION_DONE: sc->sc_flags |= IWN_FLAG_CALIB_DONE; wakeupOn(sc); break; } sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT; } if_input(&sc->sc_ic.ic_if, &ml); /* Tell the firmware what we have processed. */ hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1; IWN_WRITE(sc, IWN_FH_RX_WPTR, hw & ~7); } /* * Process an INT_WAKEUP interrupt raised when the microcontroller wakes up * from power-down sleep mode. */ void ItlIwn:: iwn_wakeup_intr(struct iwn_softc *sc) { int qid; DPRINTF(("ucode wakeup from power-down sleep\n")); /* Wakeup RX and TX rings. */ IWN_WRITE(sc, IWN_FH_RX_WPTR, sc->rxq.cur & ~7); for (qid = 0; qid < sc->ntxqs; qid++) { struct iwn_tx_ring *ring = &sc->txq[qid]; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | ring->cur); } } #ifdef IWN_DEBUG /* * Dump the error log of the firmware when a firmware panic occurs. Although * we can't debug the firmware because it is neither open source nor free, it * can help us to identify certain classes of problems. */ void ItlIwn:: iwn_fatal_intr(struct iwn_softc *sc) { struct iwn_fw_dump dump; int i; /* Check that the error log address is valid. */ if (sc->errptr < IWN_FW_DATA_BASE || sc->errptr + sizeof (dump) > IWN_FW_DATA_BASE + sc->fw_data_maxsz) { XYLog("%s: bad firmware error log address 0x%08x\n", sc->sc_dev.dv_xname, sc->errptr); return; } if (iwn_nic_lock(sc) != 0) { XYLog("%s: could not read firmware error log\n", sc->sc_dev.dv_xname); return; } /* Read firmware error log from SRAM. */ iwn_mem_read_region_4(sc, sc->errptr, (uint32_t *)&dump, sizeof (dump) / sizeof (uint32_t)); iwn_nic_unlock(sc); if (dump.valid == 0) { XYLog("%s: firmware error log is empty\n", sc->sc_dev.dv_xname); return; } XYLog("firmware error log:\n"); XYLog(" error type = \"%s\" (0x%08X)\n", (dump.id < nitems(iwn_fw_errmsg)) ? iwn_fw_errmsg[dump.id] : "UNKNOWN", dump.id); XYLog(" program counter = 0x%08X\n", dump.pc); XYLog(" source line = 0x%08X\n", dump.src_line); XYLog(" error data = 0x%08X%08X\n", dump.error_data[0], dump.error_data[1]); XYLog(" branch link = 0x%08X%08X\n", dump.branch_link[0], dump.branch_link[1]); XYLog(" interrupt link = 0x%08X%08X\n", dump.interrupt_link[0], dump.interrupt_link[1]); XYLog(" time = %u\n", dump.time[0]); /* Dump driver status (TX and RX rings) while we're here. */ XYLog("driver status:\n"); for (i = 0; i < sc->ntxqs; i++) { struct iwn_tx_ring *ring = &sc->txq[i]; XYLog(" tx ring %2d: qid=%-2d cur=%-3d queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); } XYLog(" rx ring: cur=%d\n", sc->rxq.cur); XYLog(" 802.11 state %d\n", sc->sc_ic.ic_state); } #endif int ItlIwn:: iwn_intr(OSObject *object, IOInterruptEventSource* sender, int count) { ItlIwn *that = (ItlIwn*)object; struct iwn_softc *sc = &that->com; struct _ifnet *ifp = &sc->sc_ic.ic_if; uint32_t r1, r2, tmp; // IWN_WRITE(sc, IWN_INT_MASK, 0); /* Read interrupts from ICT (fast) or from registers (slow). */ if (sc->sc_flags & IWN_FLAG_USE_ICT) { tmp = 0; while (sc->ict[sc->ict_cur] != 0) { tmp |= sc->ict[sc->ict_cur]; sc->ict[sc->ict_cur] = 0; /* Acknowledge. */ sc->ict_cur = (sc->ict_cur + 1) % IWN_ICT_COUNT; } tmp = letoh32(tmp); if (tmp == 0xffffffff) /* Shouldn't happen. */ tmp = 0; else if (tmp & 0xc0000) /* Workaround a HW bug. */ tmp |= 0x8000; r1 = (tmp & 0xff00) << 16 | (tmp & 0xff); r2 = 0; /* Unused. */ } else { r1 = IWN_READ(sc, IWN_INT); if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) return 0; /* Hardware gone! */ r2 = IWN_READ(sc, IWN_FH_INT); } if (r1 == 0 && r2 == 0) { if (ifp->if_flags & IFF_UP) IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); return 0; /* Interrupt not for us. */ } /* Acknowledge interrupts. */ IWN_WRITE(sc, IWN_INT, r1); if (!(sc->sc_flags & IWN_FLAG_USE_ICT)) IWN_WRITE(sc, IWN_FH_INT, r2); if (r1 & IWN_INT_RF_TOGGLED) { tmp = IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL; XYLog("%s: RF switch: radio %s\n", sc->sc_dev.dv_xname, tmp ? "enabled" : "disabled"); if (tmp) task_add(systq, &sc->init_task); } if (r1 & IWN_INT_CT_REACHED) { XYLog("%s: critical temperature reached!\n", sc->sc_dev.dv_xname); } if (r1 & (IWN_INT_SW_ERR | IWN_INT_HW_ERR)) { XYLog("%s: fatal firmware error\n", sc->sc_dev.dv_xname); /* Force a complete recalibration on next init. */ sc->sc_flags &= ~IWN_FLAG_CALIB_DONE; /* Dump firmware error log and stop. */ #ifdef IWN_DEBUG that->iwn_fatal_intr(sc); #endif that->iwn_stop(ifp); task_add(systq, &sc->init_task); return 1; } if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) || (r2 & IWN_FH_INT_RX)) { if (sc->sc_flags & IWN_FLAG_USE_ICT) { if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) IWN_WRITE(sc, IWN_FH_INT, IWN_FH_INT_RX); IWN_WRITE_1(sc, IWN_INT_PERIODIC, IWN_INT_PERIODIC_DIS); that->iwn_notif_intr(sc); if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) { IWN_WRITE_1(sc, IWN_INT_PERIODIC, IWN_INT_PERIODIC_ENA); } } else that->iwn_notif_intr(sc); } if ((r1 & IWN_INT_FH_TX) || (r2 & IWN_FH_INT_TX)) { if (sc->sc_flags & IWN_FLAG_USE_ICT) IWN_WRITE(sc, IWN_FH_INT, IWN_FH_INT_TX); that->wakeupOn(sc); /* FH DMA transfer completed. */ } if (r1 & IWN_INT_ALIVE) that->wakeupOn(sc); /* Firmware is alive. */ if (r1 & IWN_INT_WAKEUP) that->iwn_wakeup_intr(sc); /* Re-enable interrupts. */ if (ifp->if_flags & IFF_UP) IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); return 1; } /* * Update TX scheduler ring when transmitting an 802.11 frame (4965AGN and * 5000 adapters use a slightly different format). */ void ItlIwn:: iwn4965_update_sched(struct iwn_softc *sc, int qid, int idx, uint8_t id, uint16_t len) { uint16_t *w = &sc->sched[qid * IWN4965_SCHED_COUNT + idx]; *w = htole16(len + 8); // bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map, // (caddr_t)w - sc->sched_dma.vaddr, sizeof (uint16_t), // BUS_DMASYNC_PREWRITE); if (idx < IWN_SCHED_WINSZ) { *(w + IWN_TX_RING_COUNT) = *w; // bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map, // (caddr_t)(w + IWN_TX_RING_COUNT) - sc->sched_dma.vaddr, // sizeof (uint16_t), BUS_DMASYNC_PREWRITE); } } void ItlIwn:: iwn4965_reset_sched(struct iwn_softc *sc, int qid, int idx) { /* TBD */ } void ItlIwn:: iwn5000_update_sched(struct iwn_softc *sc, int qid, int idx, uint8_t id, uint16_t len) { uint16_t *w = &sc->sched[qid * IWN5000_SCHED_COUNT + idx]; *w = htole16(id << 12 | (len + 8)); // bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map, // (caddr_t)w - sc->sched_dma.vaddr, sizeof (uint16_t), // BUS_DMASYNC_PREWRITE); if (idx < IWN_SCHED_WINSZ) { *(w + IWN_TX_RING_COUNT) = *w; // bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map, // (caddr_t)(w + IWN_TX_RING_COUNT) - sc->sched_dma.vaddr, // sizeof (uint16_t), BUS_DMASYNC_PREWRITE); } } void ItlIwn:: iwn5000_reset_sched(struct iwn_softc *sc, int qid, int idx) { uint16_t *w = &sc->sched[qid * IWN5000_SCHED_COUNT + idx]; *w = (*w & htole16(0xf000)) | htole16(1); // bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map, // (caddr_t)w - sc->sched_dma.vaddr, sizeof (uint16_t), // BUS_DMASYNC_PREWRITE); if (idx < IWN_SCHED_WINSZ) { *(w + IWN_TX_RING_COUNT) = *w; // bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map, // (caddr_t)(w + IWN_TX_RING_COUNT) - sc->sched_dma.vaddr, // sizeof (uint16_t), BUS_DMASYNC_PREWRITE); } } int ItlIwn:: iwn_rval2ridx(int rval) { int ridx; for (ridx = 0; ridx < nitems(iwn_rates); ridx++) { if (rval == iwn_rates[ridx].rate) break; } return ridx; } static int iwn_is_mimo_ht_plcp(uint8_t ht_plcp) { return (ht_plcp != IWN_RATE_HT_SISO_MCS_INV_PLCP && (ht_plcp & IWN_RATE_HT_MCS_NSS_MSK)); } static int iwn_is_mimo_mcs(int mcs) { int ridx = iwn_mcs2ridx[mcs]; return iwn_is_mimo_ht_plcp(iwn_rates[ridx].ht_plcp); } int ItlIwn:: iwn_tx(struct iwn_softc *sc, mbuf_t m, struct ieee80211_node *ni) { struct iwn_ops *ops = &sc->ops; struct ieee80211com *ic = &sc->sc_ic; struct iwn_node *wn = (struct iwn_node *)ni; struct iwn_tx_ring *ring; struct iwn_tx_desc *desc; struct iwn_tx_data *data; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; const struct iwn_rate *rinfo; struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; enum ieee80211_edca_ac ac; int qid; uint32_t flags; uint16_t qos; u_int hdrlen; IOPhysicalSegment *seg; IOPhysicalSegment segs[IWN_MAX_SCATTER - 1]; int nsegs = 0; uint8_t *ivp, tid, ridx, txant, type, subtype; int i, totlen, hasqos, error, pad; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (type == IEEE80211_FC0_TYPE_CTL) hdrlen = sizeof(struct ieee80211_frame_min); else hdrlen = ieee80211_get_hdrlen(wh); if ((hasqos = ieee80211_has_qos(wh))) { /* Select EDCA Access Category and TX ring for this frame. */ struct ieee80211_tx_ba *ba; qos = ieee80211_get_qos(wh); tid = qos & IEEE80211_QOS_TID; ac = ieee80211_up_to_ac(ic, tid); qid = ac; /* If possible, put this frame on an aggregation queue. */ if (sc->sc_tx_ba[tid].wn == wn) { ba = &ni->ni_tx_ba[tid]; if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && ba->ba_state == IEEE80211_BA_AGREED) { qid = sc->first_agg_txq + tid; if (sc->qfullmsk & (1 << qid)) { mbuf_freem(m); return ENOBUFS; } } } } else { qos = 0; tid = IWN_NONQOS_TID; ac = EDCA_AC_BE; qid = ac; } ring = &sc->txq[qid]; desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; /* Choose a TX rate index. */ if (IEEE80211_IS_MULTICAST(wh->i_addr1) || type != IEEE80211_FC0_TYPE_DATA) ridx = iwn_rval2ridx(ieee80211_min_basic_rate(ic)); else if (ic->ic_fixed_mcs != -1) ridx = sc->fixed_ridx; else if (ic->ic_fixed_rate != -1) ridx = sc->fixed_ridx; else { if (ni->ni_flags & IEEE80211_NODE_HT) ridx = iwn_mcs2ridx[ni->ni_txmcs]; else ridx = wn->ridx[ni->ni_txrate]; } rinfo = &iwn_rates[ridx]; #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { struct iwn_tx_radiotap_header *tap = &sc->sc_txtap; uint16_t chan_flags; tap->wt_flags = 0; tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); chan_flags = ni->ni_chan->ic_flags; if (ic->ic_curmode != IEEE80211_MODE_11N) chan_flags &= ~IEEE80211_CHAN_HT; tap->wt_chan_flags = htole16(chan_flags); if ((ni->ni_flags & IEEE80211_NODE_HT) && !IEEE80211_IS_MULTICAST(wh->i_addr1) && type == IEEE80211_FC0_TYPE_DATA) { tap->wt_rate = (0x80 | ni->ni_txmcs); } else tap->wt_rate = rinfo->rate; if ((ic->ic_flags & IEEE80211_F_WEPON) && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_txtap_len, m, BPF_DIRECTION_OUT); } #endif // totlen = m->m_pkthdr.len; totlen = mbuf_pkthdr_len(m); /* Encrypt the frame if need be. */ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { /* Retrieve key for TX. */ k = ieee80211_get_txkey(ic, wh, ni); if (k->k_cipher != IEEE80211_CIPHER_CCMP) { /* Do software encryption. */ if ((m = ieee80211_encrypt(ic, m, k)) == NULL) return ENOBUFS; /* 802.11 header may have moved. */ wh = mtod(m, struct ieee80211_frame *); // totlen = m->m_pkthdr.len; totlen = mbuf_pkthdr_len(m); } else /* HW appends CCMP MIC. */ totlen += IEEE80211_CCMP_HDRLEN; } data->totlen = totlen; /* Prepare TX firmware command. */ cmd = &ring->cmd[ring->cur]; cmd->code = IWN_CMD_TX_DATA; cmd->flags = 0; cmd->qid = ring->qid; cmd->idx = ring->cur; tx = (struct iwn_cmd_data *)cmd->data; /* NB: No need to clear tx, all fields are reinitialized here. */ tx->scratch = 0; /* clear "scratch" area */ flags = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { /* Unicast frame, check if an ACK is expected. */ if (!hasqos || (qos & IEEE80211_QOS_ACK_POLICY_MASK) != IEEE80211_QOS_ACK_POLICY_NOACK) flags |= IWN_TX_NEED_ACK; } if (type == IEEE80211_FC0_TYPE_CTL && subtype == IEEE80211_FC0_SUBTYPE_BAR) { struct ieee80211_frame_min *mwh; uint8_t *barfrm; uint16_t ctl; mwh = mtod(m, struct ieee80211_frame_min *); barfrm = (uint8_t *)&mwh[1]; ctl = LE_READ_2(barfrm); tid = (ctl & IEEE80211_BA_TID_INFO_MASK) >> IEEE80211_BA_TID_INFO_SHIFT; flags |= (IWN_TX_NEED_ACK | IWN_TX_IMM_BA); } if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) flags |= IWN_TX_MORE_FRAG; /* Cannot happen yet. */ /* Check if frame must be protected using RTS/CTS or CTS-to-self. */ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { /* NB: Group frames are sent using CCK in 802.11b/g/n (2GHz). */ if (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) { flags |= IWN_TX_NEED_RTS; } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && IWN_RIDX_IS_OFDM(ridx)) { if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) flags |= IWN_TX_NEED_CTS; else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) flags |= IWN_TX_NEED_RTS; } if (flags & (IWN_TX_NEED_RTS | IWN_TX_NEED_CTS)) { if (sc->hw_type != IWN_HW_REV_TYPE_4965) { /* 5000 autoselects RTS/CTS or CTS-to-self. */ flags &= ~(IWN_TX_NEED_RTS | IWN_TX_NEED_CTS); flags |= IWN_TX_NEED_PROTECTION; } else flags |= IWN_TX_FULL_TXOP; } } if (type == IEEE80211_FC0_TYPE_CTL && subtype == IEEE80211_FC0_SUBTYPE_BAR) tx->id = wn->id; else if (IEEE80211_IS_MULTICAST(wh->i_addr1) || type != IEEE80211_FC0_TYPE_DATA) tx->id = sc->broadcast_id; else tx->id = wn->id; if (type == IEEE80211_FC0_TYPE_MGT) { #ifndef IEEE80211_STA_ONLY /* Tell HW to set timestamp in probe responses. */ if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) flags |= IWN_TX_INSERT_TSTAMP; #endif if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) tx->timeout = htole16(3); else tx->timeout = htole16(2); } else tx->timeout = htole16(0); if (hdrlen & 3) { /* First segment length must be a multiple of 4. */ flags |= IWN_TX_NEED_PADDING; pad = 4 - (hdrlen & 3); } else pad = 0; tx->len = htole16(totlen); tx->tid = tid; tx->rts_ntries = 60; tx->data_ntries = 15; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); if ((ni->ni_flags & IEEE80211_NODE_HT) && tx->id != sc->broadcast_id && rinfo->ht_plcp != IWN_RATE_HT_SISO_MCS_INV_PLCP) { tx->plcp = rinfo->ht_plcp; tx->rflags = IWN_RFLAG_MCS; if (ieee80211_node_supports_ht_sgi20(ni)) tx->rflags |= IWN_RFLAG_SGI; if (iwn_rxon_ht40_enabled(sc)) { tx->rflags |= IWN_RFLAG_HT40; if (ieee80211_node_supports_ht_sgi40(ni)) { tx->rflags |= IWN_RFLAG_SGI; } } if (iwn_is_mimo_ht_plcp(rinfo->ht_plcp)) tx->rflags |= IWN_RFLAG_ANT(sc->txchainmask); else tx->rflags |= IWN_RFLAG_ANT(IWN_LSB(sc->txchainmask)); } else { tx->plcp = rinfo->plcp; if (IWN_RIDX_IS_CCK(ridx)) tx->rflags = IWN_RFLAG_CCK; else tx->rflags = 0; } if (tx->id == sc->broadcast_id || ic->ic_fixed_mcs != -1 || ic->ic_fixed_rate != -1) { /* Group or management frame, or fixed Tx rate. */ tx->linkq = 0; /* XXX Alternate between antenna A and B? */ txant = IWN_LSB(sc->txchainmask); tx->rflags |= IWN_RFLAG_ANT(txant); } else { tx->linkq = 0; /* initial index into firmware LQ retry table */ flags |= IWN_TX_LINKQ; /* enable multi-rate retry */ } /* Set physical address of "scratch area". */ tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); tx->hiaddr = IWN_HIADDR(data->scratch_paddr); /* Copy 802.11 header in TX command. */ memcpy((uint8_t *)(tx + 1), wh, hdrlen); if (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP) { /* Trim 802.11 header and prepend CCMP IV. */ mbuf_adj(m, hdrlen - IEEE80211_CCMP_HDRLEN); ivp = mtod(m, uint8_t *); k->k_tsc++; ivp[0] = k->k_tsc; ivp[1] = k->k_tsc >> 8; ivp[2] = 0; ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; ivp[4] = k->k_tsc >> 16; ivp[5] = k->k_tsc >> 24; ivp[6] = k->k_tsc >> 32; ivp[7] = k->k_tsc >> 40; tx->security = IWN_CIPHER_CCMP; if (qid >= sc->first_agg_txq) flags |= IWN_TX_AMPDU_CCMP; memcpy(tx->key, k->k_key, k->k_len); /* TX scheduler includes CCMP MIC len w/5000 Series. */ if (sc->hw_type != IWN_HW_REV_TYPE_4965) totlen += IEEE80211_CCMP_MICLEN; } else { /* Trim 802.11 header. */ mbuf_adj(m, hdrlen); tx->security = 0; } tx->flags = htole32(flags); nsegs = data->map->cursor->getPhysicalSegmentsWithCoalesce(m, &segs[0], IWN_MAX_SCATTER - 1); if (nsegs == 0) { XYLog("%s: can't map mbuf (error %d)\n", DEVNAME(sc), nsegs); mbuf_freem(m); return ENOMEM; } data->m = m; data->ni = ni; data->ampdu_txmcs = ni->ni_txmcs; /* updated upon Tx interrupt */ DPRINTFN(4, ("sending data: qid=%d idx=%d len=%d nsegs=%d\n", ring->qid, ring->cur, mbuf_pkthdr_len(m), nsegs)); /* Fill TX descriptor. */ desc->nsegs = 1 + nsegs; /* First DMA segment is used by the TX command. */ desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr)); desc->segs[0].len = htole16(IWN_HIADDR(data->cmd_paddr) | (4 + sizeof (*tx) + hdrlen + pad) << 4); /* Other DMA segments are for data payload. */ for (i = 0; i < nsegs; i++) { seg = &segs[i]; desc->segs[i + 1].addr = htole32(IWN_LOADDR(seg->location)); desc->segs[i + 1].len = htole16(IWN_HIADDR(seg->location) | seg->length << 4); // XYLog("DMA segments index=%d location=0x%llx length=%llu", i, seg->location, seg->length); } // XYLog("----------end sending data------\n"); // bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, // BUS_DMASYNC_PREWRITE); // bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map, // (caddr_t)cmd - ring->cmd_dma.vaddr, sizeof (*cmd), // BUS_DMASYNC_PREWRITE); // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, // (caddr_t)desc - ring->desc_dma.vaddr, sizeof (*desc), // BUS_DMASYNC_PREWRITE); /* Update TX scheduler. */ ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen); /* Kick TX ring. */ ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); /* Mark TX ring as full if we reach a certain threshold. */ if (++ring->queued > IWN_TX_RING_HIMARK) { // XYLog("%s sc->qfullmsk is FULL qid=%d ring->cur=%d ring->queued=%d\n", __FUNCTION__, ring->qid, ring->cur, ring->queued); sc->qfullmsk |= 1 << ring->qid; } return 0; } void ItlIwn:: iwn_start(struct _ifnet *ifp) { struct iwn_softc *sc = (struct iwn_softc*)ifp->if_softc; ItlIwn *that = container_of(sc, ItlIwn, com); that->getMainCommandGate()->attemptAction(_iwn_start_task, &that->com.sc_ic.ic_ac.ac_if); } IOReturn ItlIwn:: _iwn_start_task(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) { struct _ifnet *ifp = (struct _ifnet *)arg0; struct iwn_softc *sc = (struct iwn_softc *)ifp->if_softc; ItlIwn *that = container_of(sc, ItlIwn, com); struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; mbuf_t m; if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) return kIOReturnError; for (;;) { if (sc->qfullmsk != 0) { ifq_set_oactive(&ifp->if_snd); break; } /* Send pending management frames first. */ m = mq_dequeue(&ic->ic_mgtq); if (m != NULL) { // ni = m->m_pkthdr.ph_cookie; ni = (struct ieee80211_node *)mbuf_pkthdr_rcvif(m); goto sendit; } if ( #ifndef AIRPORT ic->ic_state != IEEE80211_S_RUN || #endif (ic->ic_xflags & IEEE80211_F_TX_MGMT_ONLY)) break; /* Encapsulate and send data frames. */ m = ifq_dequeue(&ifp->if_snd); if (m == NULL) break; #if NBPFILTER > 0 if (ifp->if_bpf != NULL) bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) continue; sendit: #if NBPFILTER > 0 if (ic->ic_rawbpf != NULL) bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT); #endif if (that->iwn_tx(sc, m, ni) != 0) { ieee80211_release_node(ic, ni); ifp->netStat->outputErrors++; continue; } ifp->netStat->outputPackets++; sc->sc_tx_timer = 5; ifp->if_timer = 1; } return kIOReturnSuccess; } void ItlIwn:: iwn_watchdog(struct _ifnet *ifp) { struct iwn_softc *sc = (struct iwn_softc *)ifp->if_softc; ItlIwn *that = container_of(sc, ItlIwn, com); ifp->if_timer = 0; if (sc->sc_tx_timer > 0) { if (--sc->sc_tx_timer == 0) { XYLog("%s: device timeout\n", sc->sc_dev.dv_xname); that->iwn_stop(ifp); task_add(systq, &sc->init_task); ifp->netStat->outputErrors++; return; } ifp->if_timer = 1; } ieee80211_watchdog(ifp); } int ItlIwn:: iwn_ioctl(struct _ifnet *ifp, u_long cmd, caddr_t data) { struct iwn_softc *sc = (struct iwn_softc *)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; ItlIwn *that = container_of(sc, ItlIwn, com); int s, error = 0; // error = rw_enter(&sc->sc_rwlock, RW_WRITE | RW_INTR); if (error) return error; s = splnet(); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; /* FALLTHROUGH */ case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (!(ifp->if_flags & IFF_RUNNING)) error = that->iwn_init(ifp); } else { if (ifp->if_flags & IFF_RUNNING) that->iwn_stop(ifp); } break; case SIOCS80211POWER: error = ieee80211_ioctl(ifp, cmd, data); if (error != ENETRESET) break; if (ic->ic_state == IEEE80211_S_RUN && sc->calib.state == IWN_CALIB_STATE_RUN) { if (ic->ic_flags & IEEE80211_F_PMGTON) error = that->iwn_set_pslevel(sc, 0, 3, 0); else /* back to CAM */ error = that->iwn_set_pslevel(sc, 0, 0, 0); } else { /* Defer until transition to IWN_CALIB_STATE_RUN. */ error = 0; } break; default: error = ieee80211_ioctl(ifp, cmd, data); } if (error == ENETRESET) { error = 0; if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) { that->iwn_stop(ifp); error = that->iwn_init(ifp); } } splx(s); // rw_exit_write(&sc->sc_rwlock); return error; } /* * Send a command to the firmware. */ int ItlIwn:: iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async) { DPRINTFN(2, ("%s code=%d size=%d\n", __FUNCTION__, code, size)); struct iwn_ops *ops = &sc->ops; struct iwn_tx_ring *ring = &sc->txq[4]; struct iwn_tx_desc *desc; struct iwn_tx_data *data; struct iwn_tx_cmd *cmd; mbuf_t m; bus_addr_t paddr; int totlen, error = 0; unsigned int max_chunks = 1; IOPhysicalSegment seg; desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; totlen = 4 + size; if (size > sizeof cmd->data) { /* Command is too large to fit in a descriptor. */ if (totlen > MCLBYTES) return EINVAL; // MGETHDR(m, M_DONTWAIT, MT_DATA); // if (totlen > MHLEN) { // MCLGET(m, M_DONTWAIT); // if (!(m->m_flags & M_EXT)) { // mbuf_freem(m); // return ENOMEM; // } // } mbuf_allocpacket(MBUF_WAITOK, totlen, &max_chunks, &m); if (m == NULL) { XYLog("%s: could not get fw cmd mbuf (%zd bytes)\n", DEVNAME(sc), totlen); return ENOMEM; } mbuf_setlen(m, totlen); mbuf_pkthdr_setlen(m, totlen); cmd = mtod(m, struct iwn_tx_cmd *); // error = bus_dmamap_load(sc->sc_dmat, data->map, cmd, totlen, // NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE); // if (error != 0) { // mbuf_freem(m); // return error; // } data->map->dm_nsegs = data->map->cursor->getPhysicalSegmentsWithCoalesce(m, &seg, 1); if (data->map->dm_nsegs == 0) { XYLog("%s: could not load fw cmd mbuf (%zd bytes)\n", DEVNAME(sc), totlen); mbuf_freem(m); return ENOMEM; } data->m = m; paddr = seg.location; } else { cmd = &ring->cmd[ring->cur]; paddr = data->cmd_paddr; } cmd->code = code; cmd->flags = 0; cmd->qid = ring->qid; cmd->idx = ring->cur; memcpy(cmd->data, buf, size); desc->nsegs = 1; desc->segs[0].addr = htole32(IWN_LOADDR(paddr)); desc->segs[0].len = htole16(IWN_HIADDR(paddr) | totlen << 4); // if (size > sizeof cmd->data) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, totlen, // BUS_DMASYNC_PREWRITE); // } else { // bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map, // (caddr_t)cmd - ring->cmd_dma.vaddr, totlen, // BUS_DMASYNC_PREWRITE); // } // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, // (caddr_t)desc - ring->desc_dma.vaddr, sizeof (*desc), // BUS_DMASYNC_PREWRITE); /* Update TX scheduler. */ ops->update_sched(sc, ring->qid, ring->cur, 0, 0); /* Kick command ring. */ ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); return async ? 0 : tsleep_nsec(desc, PCATCH, "iwncmd", SEC_TO_NSEC(1)); } int ItlIwn:: iwn4965_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn4965_node_info hnode; caddr_t src, dst; /* * We use the node structure for 5000 Series internally (it is * a superset of the one for 4965AGN). We thus copy the common * fields before sending the command. */ src = (caddr_t)node; dst = (caddr_t)&hnode; memcpy(dst, src, 48); /* Skip TSC, RX MIC and TX MIC fields from ``src''. */ memcpy(dst + 48, src + 72, 20); return that->iwn_cmd(sc, IWN_CMD_ADD_NODE, &hnode, sizeof hnode, async); } int ItlIwn:: iwn5000_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async) { ItlIwn *that = container_of(sc, ItlIwn, com); /* Direct mapping. */ return that->iwn_cmd(sc, IWN_CMD_ADD_NODE, node, sizeof (*node), async); } int ItlIwn:: iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) { struct ieee80211com *ic = &sc->sc_ic; struct iwn_node *wn = (struct iwn_node *)ni; struct iwn_cmd_link_quality linkq; struct ieee80211_rateset *rs = &ni->ni_rates; uint8_t txant; int i, ridx, ridx_min, ridx_max, j, mimo, tab = 0, rflags = 0; /* Use the first valid TX antenna. */ txant = IWN_LSB(sc->txchainmask); memset(&linkq, 0, sizeof linkq); linkq.id = wn->id; linkq.antmsk_1stream = txant; linkq.antmsk_2stream = IWN_ANT_AB; linkq.ampdu_max = IWN_AMPDU_MAX; linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ #if 0 // RTS/CTS protection not yet tested if (ni->ni_flags & IEEE80211_NODE_HT && sc->agg_queue_mask > 0 && ic->ic_flags & IEEE80211_F_USEPROT) if (sc->hw_type != IWN_HW_REV_TYPE_4965 && sc->hw_type != IWN_HW_REV_TYPE_5300 && sc->hw_type != IWN_HW_REV_TYPE_5150 && sc->hw_type != IWN_HW_REV_TYPE_5350 && sc->hw_type != IWN_HW_REV_TYPE_5100) linkq.flags |= IWN_LINK_QUAL_FLAGS_SET_STA_TLC_RTS; #endif /* * Fill the LQ rate selection table with legacy and/or HT rates * in descending order, i.e. with the node's current TX rate first. * In cases where throughput of an HT rate corresponds to a legacy * rate it makes no sense to add both. We rely on the fact that * iwn_rates is laid out such that equivalent HT/legacy rates share * the same IWN_RATE_*_INDEX value. Also, rates not applicable to * legacy/HT are assumed to be marked with an 'invalid' PLCP value. */ j = 0; ridx_min = iwn_rval2ridx(ieee80211_min_basic_rate(ic)); mimo = iwn_is_mimo_mcs(ni->ni_txmcs); ridx_max = (mimo ? IWN_LAST_HT_RATE : IWN_LAST_HT_SISO_RATE); for (ridx = ridx_max; ridx >= ridx_min; ridx--) { uint8_t plcp = iwn_rates[ridx].plcp; uint8_t ht_plcp = iwn_rates[ridx].ht_plcp; if (j >= IWN_MAX_TX_RETRIES) break; tab = 0; rflags = 0; if (ni->ni_flags & IEEE80211_NODE_HT) { if (ht_plcp == IWN_RATE_HT_SISO_MCS_INV_PLCP) continue; /* Do not mix SISO and MIMO HT rates. */ if ((mimo && !iwn_is_mimo_ht_plcp(ht_plcp)) || (!mimo && iwn_is_mimo_ht_plcp(ht_plcp))) continue; for (i = ni->ni_txmcs; i >= 0; i--) { if (ic->ic_tx_mcs_set == IEEE80211_TX_MCS_SET_DEFINED && isclr(ni->ni_rxmcs, i)) continue; if (ridx != iwn_mcs2ridx[i]) continue; tab = ht_plcp; rflags |= IWN_RFLAG_MCS; /* First two Tx attempts may use 40MHz/SGI. */ if (j > 1) break; if (iwn_rxon_ht40_enabled(sc)) rflags |= IWN_RFLAG_HT40; if (ieee80211_ra_use_ht_sgi(ni)) rflags |= IWN_RFLAG_SGI; } } else if (plcp != IWN_RATE_INVM_PLCP) { for (i = ni->ni_txrate; i >= 0; i--) { if (iwn_rates[ridx].rate == (rs->rs_rates[i] & IEEE80211_RATE_VAL)) { tab = plcp; break; } } } if (tab == 0 && rflags == 0) continue; if (iwn_is_mimo_ht_plcp(ht_plcp)) rflags |= IWN_RFLAG_ANT(sc->txchainmask); else rflags |= IWN_RFLAG_ANT(txant); if (IWN_RIDX_IS_CCK(ridx)) rflags |= IWN_RFLAG_CCK; DPRINTFN(2, ("lq.retry[%d].plcp = 0x%x, lq.retry[i].rflags = 0x%x\n", j, tab, rflags)); linkq.retry[j].plcp = tab; linkq.retry[j].rflags = rflags; j++; } linkq.mimo = (mimo ? j : 0); /* Fill the rest with the lowest possible rate */ while (j < IWN_MAX_TX_RETRIES) { tab = iwn_rates[ridx_min].plcp; rflags = 0; if (IWN_RIDX_IS_CCK(ridx_min)) rflags |= IWN_RFLAG_CCK; rflags |= IWN_RFLAG_ANT(txant); DPRINTFN(2, ("lq.retry[%d].plcp = 0x%x, lq.retry[i].rflags = 0x%x\n", j, tab, rflags)); linkq.retry[j].plcp = tab; linkq.retry[j].rflags = rflags; j++; } return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1); } /* * Broadcast node is used to send group-addressed and management frames. */ int ItlIwn:: iwn_add_broadcast_node(struct iwn_softc *sc, int async, int ridx) { struct iwn_ops *ops = &sc->ops; struct iwn_node_info node; struct iwn_cmd_link_quality linkq; const struct iwn_rate *rinfo; uint8_t txant; int i, error; memset(&node, 0, sizeof node); IEEE80211_ADDR_COPY(node.macaddr, etherbroadcastaddr); node.id = sc->broadcast_id; DPRINTF(("adding broadcast node\n")); if ((error = ops->add_node(sc, &node, async)) != 0) return error; /* Use the first valid TX antenna. */ txant = IWN_LSB(sc->txchainmask); memset(&linkq, 0, sizeof linkq); linkq.id = sc->broadcast_id; linkq.antmsk_1stream = txant; linkq.antmsk_2stream = IWN_ANT_AB; linkq.ampdu_max = IWN_AMPDU_MAX_NO_AGG; linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ /* Use lowest mandatory bit-rate. */ rinfo = &iwn_rates[ridx]; linkq.retry[0].plcp = rinfo->plcp; if (IWN_RIDX_IS_CCK(ridx)) linkq.retry[0].rflags = IWN_RFLAG_CCK; linkq.retry[0].rflags |= IWN_RFLAG_ANT(txant); /* Use same bit-rate for all TX retries. */ for (i = 1; i < IWN_MAX_TX_RETRIES; i++) { linkq.retry[i].plcp = linkq.retry[0].plcp; linkq.retry[i].rflags = linkq.retry[0].rflags; } return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, async); } void ItlIwn:: iwn_updateedca(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); #define IWN_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; struct ieee80211_node *ni = ic->ic_bss; ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_edca_params cmd; int aci; memset(&cmd, 0, sizeof cmd); for (aci = 0; aci < EDCA_NUM_AC; aci++) { const struct ieee80211_edca_ac_params *ac = &ic->ic_edca_ac[aci]; cmd.ac[aci].aifsn = ac->ac_aifsn; cmd.ac[aci].cwmin = htole16(IWN_EXP2(ac->ac_ecwmin)); cmd.ac[aci].cwmax = htole16(IWN_EXP2(ac->ac_ecwmax)); cmd.ac[aci].txoplimit = htole16(IEEE80211_TXOP_TO_US(ac->ac_txoplimit)); } if (ni->ni_flags & IEEE80211_NODE_QOS) cmd.flags |= htole32(IWN_EDCA_UPDATE); if (ni->ni_flags & IEEE80211_NODE_HT) cmd.flags |= htole32(IWN_EDCA_FLG_TGN); (void)that->iwn_cmd(sc, IWN_CMD_EDCA_PARAMS, &cmd, sizeof cmd, 1); #undef IWN_EXP2 } void ItlIwn:: iwn_set_led(struct iwn_softc *sc, uint8_t which, uint8_t off, uint8_t on) { struct iwn_cmd_led led; /* Clear microcode LED ownership. */ IWN_CLRBITS(sc, IWN_LED, IWN_LED_BSM_CTRL); led.which = which; led.unit = htole32(10000); /* on/off in unit of 100ms */ led.off = off; led.on = on; (void)iwn_cmd(sc, IWN_CMD_SET_LED, &led, sizeof led, 1); } /* * Set the critical temperature at which the firmware will stop the radio * and notify us. */ int ItlIwn:: iwn_set_critical_temp(struct iwn_softc *sc) { struct iwn_critical_temp crit; int32_t temp; IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_CTEMP_STOP_RF); if (sc->hw_type == IWN_HW_REV_TYPE_5150) temp = (IWN_CTOK(110) - sc->temp_off) * -5; else if (sc->hw_type == IWN_HW_REV_TYPE_4965) temp = IWN_CTOK(110); else temp = 110; memset(&crit, 0, sizeof crit); crit.tempR = htole32(temp); DPRINTF(("setting critical temperature to %d\n", temp)); return iwn_cmd(sc, IWN_CMD_SET_CRITICAL_TEMP, &crit, sizeof crit, 0); } int ItlIwn:: iwn_set_timing(struct iwn_softc *sc, struct ieee80211_node *ni) { struct iwn_cmd_timing cmd; uint64_t val, mod; memset(&cmd, 0, sizeof cmd); memcpy(&cmd.tstamp, ni->ni_tstamp, sizeof (uint64_t)); cmd.bintval = htole16(ni->ni_intval); cmd.lintval = htole16(10); /* Compute remaining time until next beacon. */ val = (uint64_t)ni->ni_intval * IEEE80211_DUR_TU; mod = letoh64(cmd.tstamp) % val; cmd.binitval = htole32((uint32_t)(val - mod)); DPRINTF(("timing bintval=%u, tstamp=%llu, init=%u\n", ni->ni_intval, letoh64(cmd.tstamp), (uint32_t)(val - mod))); return iwn_cmd(sc, IWN_CMD_TIMING, &cmd, sizeof cmd, 1); } void ItlIwn:: iwn4965_power_calibration(struct iwn_softc *sc, int temp) { /* Adjust TX power if need be (delta >= 3 degC). */ DPRINTF(("temperature %d->%d\n", sc->temp, temp)); if (abs(temp - sc->temp) >= 3) { /* Record temperature of last calibration. */ sc->temp = temp; (void)iwn4965_set_txpower(sc, 1); } } /* * Set TX power for current channel (each rate has its own power settings). * This function takes into account the regulatory information from EEPROM, * the current temperature and the current voltage. */ int ItlIwn:: iwn4965_set_txpower(struct iwn_softc *sc, int async) { /* Fixed-point arithmetic division using a n-bit fractional part. */ #define fdivround(a, b, n) \ ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n)) /* Linear interpolation. */ #define interpolate(x, x1, y1, x2, y2, n) \ ((y1) + fdivround(((int)(x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) static const int tdiv[IWN_NATTEN_GROUPS] = { 9, 8, 8, 8, 6 }; struct ieee80211com *ic = &sc->sc_ic; ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_ucode_info *uc = &sc->ucode_info; struct ieee80211_channel *ch; struct iwn4965_cmd_txpower cmd; struct iwn4965_eeprom_chan_samples *chans; const uint8_t *rf_gain, *dsp_gain; int32_t vdiff, tdiff; int i, c, grp, maxpwr, is_ht40 = 0; uint8_t chan, ext_chan; /* Retrieve current channel from last RXON. */ chan = sc->rxon.chan; DPRINTF(("setting TX power for channel %d\n", chan)); ch = &ic->ic_channels[chan]; memset(&cmd, 0, sizeof cmd); cmd.band = IEEE80211_IS_CHAN_5GHZ(ch) ? 0 : 1; cmd.chan = chan; if (IEEE80211_IS_CHAN_5GHZ(ch)) { maxpwr = sc->maxpwr5GHz; rf_gain = iwn4965_rf_gain_5ghz; dsp_gain = iwn4965_dsp_gain_5ghz; } else { maxpwr = sc->maxpwr2GHz; rf_gain = iwn4965_rf_gain_2ghz; dsp_gain = iwn4965_dsp_gain_2ghz; } /* Compute voltage compensation. */ vdiff = ((int32_t)letoh32(uc->volt) - sc->eeprom_voltage) / 7; if (vdiff > 0) vdiff *= 2; if (abs(vdiff) > 2) vdiff = 0; DPRINTF(("voltage compensation=%d (UCODE=%d, EEPROM=%d)\n", vdiff, letoh32(uc->volt), sc->eeprom_voltage)); /* Get channel attenuation group. */ if (chan <= 20) /* 1-20 */ grp = 4; else if (chan <= 43) /* 34-43 */ grp = 0; else if (chan <= 70) /* 44-70 */ grp = 1; else if (chan <= 124) /* 71-124 */ grp = 2; else /* 125-200 */ grp = 3; DPRINTF(("chan %d, attenuation group=%d\n", chan, grp)); /* Get channel sub-band. */ for (i = 0; i < IWN_NBANDS; i++) if (sc->bands[i].lo != 0 && sc->bands[i].lo <= chan && chan <= sc->bands[i].hi) break; if (i == IWN_NBANDS) /* Can't happen in real-life. */ return EINVAL; chans = sc->bands[i].chans; DPRINTF(("chan %d sub-band=%d\n", chan, i)); if (that->iwn_rxon_ht40_enabled(sc)) { is_ht40 = 1; if (le32toh(sc->rxon.flags) & IWN_RXON_HT_HT40MINUS) ext_chan = chan - 2; else ext_chan = chan + 2; } else ext_chan = chan; for (c = 0; c < 2; c++) { uint8_t power, gain, temp; int maxchpwr, pwr, ridx, idx; power = interpolate(ext_chan, chans[0].num, chans[0].samples[c][1].power, chans[1].num, chans[1].samples[c][1].power, 1); gain = interpolate(ext_chan, chans[0].num, chans[0].samples[c][1].gain, chans[1].num, chans[1].samples[c][1].gain, 1); temp = interpolate(ext_chan, chans[0].num, chans[0].samples[c][1].temp, chans[1].num, chans[1].samples[c][1].temp, 1); DPRINTF(("TX chain %d: power=%d gain=%d temp=%d\n", c, power, gain, temp)); /* Compute temperature compensation. */ tdiff = ((sc->temp - temp) * 2) / tdiv[grp]; DPRINTF(("temperature compensation=%d (current=%d, " "EEPROM=%d)\n", tdiff, sc->temp, temp)); for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) { /* Convert dBm to half-dBm. */ if (is_ht40) maxchpwr = sc->maxpwr40[chan] * 2; else maxchpwr = sc->maxpwr[chan] * 2; #ifdef notyet if (ridx > iwn_mcs2ridx[7] && ridx < iwn_mcs2ridx[16]) maxchpwr -= 6; /* MIMO 2T: -3dB */ #endif pwr = maxpwr; /* Adjust TX power based on rate. */ if ((ridx % 8) == 5) pwr -= 15; /* OFDM48: -7.5dB */ else if ((ridx % 8) == 6) pwr -= 17; /* OFDM54: -8.5dB */ else if ((ridx % 8) == 7) pwr -= 20; /* OFDM60: -10dB */ else pwr -= 10; /* Others: -5dB */ /* Do not exceed channel max TX power. */ if (pwr > maxchpwr) pwr = maxchpwr; idx = gain - (pwr - power) - tdiff - vdiff; if (ridx > iwn_mcs2ridx[7]) /* MIMO */ idx += (int32_t)letoh32(uc->atten[grp][c]); if (cmd.band == 0) idx += 9; /* 5GHz */ if (ridx == IWN_RIDX_MAX) idx += 5; /* CCK */ /* Make sure idx stays in a valid range. */ if (idx < 0) idx = 0; else if (idx > IWN4965_MAX_PWR_INDEX) idx = IWN4965_MAX_PWR_INDEX; DPRINTF(("TX chain %d, rate idx %d: power=%d\n", c, ridx, idx)); cmd.power[ridx].rf_gain[c] = rf_gain[idx]; cmd.power[ridx].dsp_gain[c] = dsp_gain[idx]; } } DPRINTF(("setting TX power for chan %d\n", chan)); return that->iwn_cmd(sc, IWN_CMD_TXPOWER, &cmd, sizeof cmd, async); #undef interpolate #undef fdivround } int ItlIwn:: iwn5000_set_txpower(struct iwn_softc *sc, int async) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn5000_cmd_txpower cmd; /* * TX power calibration is handled automatically by the firmware * for 5000 Series. */ memset(&cmd, 0, sizeof cmd); cmd.global_limit = 2 * IWN5000_TXPOWER_MAX_DBM; /* 16 dBm */ cmd.flags = IWN5000_TXPOWER_NO_CLOSED; cmd.srv_limit = IWN5000_TXPOWER_AUTO; DPRINTF(("setting TX power\n")); return that->iwn_cmd(sc, IWN_CMD_TXPOWER_DBM, &cmd, sizeof cmd, async); } /* * Retrieve the maximum RSSI (in dBm) among receivers. */ int ItlIwn:: iwn4965_get_rssi(const struct iwn_rx_stat *stat) { struct iwn4965_rx_phystat *phy = (struct iwn4965_rx_phystat *)stat->phybuf; uint8_t mask, agc; int rssi; mask = (letoh16(phy->antenna) >> 4) & IWN_ANT_ABC; agc = (letoh16(phy->agc) >> 7) & 0x7f; rssi = 0; if (mask & IWN_ANT_A) rssi = MAX(rssi, phy->rssi[0]); if (mask & IWN_ANT_B) rssi = MAX(rssi, phy->rssi[2]); if (mask & IWN_ANT_C) rssi = MAX(rssi, phy->rssi[4]); return rssi - agc - IWN_RSSI_TO_DBM; } int ItlIwn:: iwn5000_get_rssi(const struct iwn_rx_stat *stat) { struct iwn5000_rx_phystat *phy = (struct iwn5000_rx_phystat *)stat->phybuf; uint8_t agc; int rssi; agc = (letoh32(phy->agc) >> 9) & 0x7f; rssi = MAX(letoh16(phy->rssi[0]) & 0xff, letoh16(phy->rssi[1]) & 0xff); rssi = MAX(letoh16(phy->rssi[2]) & 0xff, rssi); return rssi - agc - IWN_RSSI_TO_DBM; } /* * Retrieve the average noise (in dBm) among receivers. */ int ItlIwn:: iwn_get_noise(const struct iwn_rx_general_stats *stats) { int i, total, nbant, noise; total = nbant = 0; for (i = 0; i < 3; i++) { if ((noise = letoh32(stats->noise[i]) & 0xff) == 0) continue; total += noise; nbant++; } /* There should be at least one antenna but check anyway. */ return (nbant == 0) ? -127 : (total / nbant) - 107; } /* * Compute temperature (in degC) from last received statistics. */ int ItlIwn:: iwn4965_get_temperature(struct iwn_softc *sc) { struct iwn_ucode_info *uc = &sc->ucode_info; int32_t r1, r2, r3, r4, temp; if (sc->rx_stats_flags & IWN_STATS_FLAGS_BAND_HT40) { r1 = letoh32(uc->temp[0].chan40MHz); r2 = letoh32(uc->temp[1].chan40MHz); r3 = letoh32(uc->temp[2].chan40MHz); } else { r1 = letoh32(uc->temp[0].chan20MHz); r2 = letoh32(uc->temp[1].chan20MHz); r3 = letoh32(uc->temp[2].chan20MHz); } r4 = letoh32(sc->rawtemp); if (r1 == r3) /* Prevents division by 0 (should not happen). */ return 0; /* Sign-extend 23-bit R4 value to 32-bit. */ r4 = ((r4 & 0xffffff) ^ 0x800000) - 0x800000; /* Compute temperature in Kelvin. */ temp = (259 * (r4 - r2)) / (r3 - r1); temp = (temp * 97) / 100 + 8; DPRINTF(("temperature %dK/%dC\n", temp, IWN_KTOC(temp))); return IWN_KTOC(temp); } int ItlIwn:: iwn5000_get_temperature(struct iwn_softc *sc) { int32_t temp; /* * Temperature is not used by the driver for 5000 Series because * TX power calibration is handled by firmware. */ temp = letoh32(sc->rawtemp); if (sc->hw_type == IWN_HW_REV_TYPE_5150) { temp = (temp / -5) + sc->temp_off; temp = IWN_KTOC(temp); } return temp; } /* * Initialize sensitivity calibration state machine. */ int ItlIwn:: iwn_init_sensitivity(struct iwn_softc *sc) { struct iwn_ops *ops = &sc->ops; struct iwn_calib_state *calib = &sc->calib; uint32_t flags; int error; /* Reset calibration state machine. */ memset(calib, 0, sizeof (*calib)); calib->state = IWN_CALIB_STATE_INIT; calib->cck_state = IWN_CCK_STATE_HIFA; /* Set initial correlation values. */ calib->ofdm_x1 = sc->limits->min_ofdm_x1; calib->ofdm_mrc_x1 = sc->limits->min_ofdm_mrc_x1; calib->ofdm_x4 = sc->limits->min_ofdm_x4; calib->ofdm_mrc_x4 = sc->limits->min_ofdm_mrc_x4; calib->cck_x4 = 125; calib->cck_mrc_x4 = sc->limits->min_cck_mrc_x4; calib->energy_cck = sc->limits->energy_cck; /* Write initial sensitivity. */ if ((error = iwn_send_sensitivity(sc)) != 0) return error; /* Write initial gains. */ if ((error = ops->init_gains(sc)) != 0) return error; /* Request statistics at each beacon interval. */ flags = 0; DPRINTFN(2, ("sending request for statistics\n")); return iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, sizeof flags, 1); } /* * Collect noise and RSSI statistics for the first 20 beacons received * after association and use them to determine connected antennas and * to set differential gains. */ void ItlIwn:: iwn_collect_noise(struct iwn_softc *sc, const struct iwn_rx_general_stats *stats) { struct iwn_ops *ops = &sc->ops; struct iwn_calib_state *calib = &sc->calib; uint32_t val; int i; /* Accumulate RSSI and noise for all 3 antennas. */ for (i = 0; i < 3; i++) { calib->rssi[i] += letoh32(stats->rssi[i]) & 0xff; calib->noise[i] += letoh32(stats->noise[i]) & 0xff; } /* NB: We update differential gains only once after 20 beacons. */ if (++calib->nbeacons < 20) return; /* Determine highest average RSSI. */ val = MAX(calib->rssi[0], calib->rssi[1]); val = MAX(calib->rssi[2], val); /* Determine which antennas are connected. */ sc->chainmask = sc->rxchainmask; for (i = 0; i < 3; i++) if (val - calib->rssi[i] > 15 * 20) sc->chainmask &= ~(1 << i); DPRINTF(("RX chains mask: theoretical=0x%x, actual=0x%x\n", sc->rxchainmask, sc->chainmask)); /* If none of the TX antennas are connected, keep at least one. */ if ((sc->chainmask & sc->txchainmask) == 0) sc->chainmask |= IWN_LSB(sc->txchainmask); (void)ops->set_gains(sc); calib->state = IWN_CALIB_STATE_RUN; #ifdef notyet /* XXX Disable RX chains with no antennas connected. */ sc->rxon.rxchain = htole16(IWN_RXCHAIN_SEL(sc->chainmask)); (void)iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); #endif /* Enable power-saving mode if requested by user. */ if (sc->sc_ic.ic_flags & IEEE80211_F_PMGTON) (void)iwn_set_pslevel(sc, 0, 3, 1); } int ItlIwn:: iwn4965_init_gains(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_phy_calib_gain cmd; memset(&cmd, 0, sizeof cmd); cmd.code = IWN4965_PHY_CALIB_DIFF_GAIN; /* Differential gains initially set to 0 for all 3 antennas. */ DPRINTF(("setting initial differential gains\n")); return that->iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); } int ItlIwn:: iwn5000_init_gains(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_phy_calib cmd; memset(&cmd, 0, sizeof cmd); cmd.code = sc->reset_noise_gain; cmd.ngroups = 1; cmd.isvalid = 1; DPRINTF(("setting initial differential gains\n")); return that->iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); } int ItlIwn:: iwn4965_set_gains(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_calib_state *calib = &sc->calib; struct iwn_phy_calib_gain cmd; int i, delta, noise; /* Get minimal noise among connected antennas. */ noise = INT_MAX; /* NB: There's at least one antenna. */ for (i = 0; i < 3; i++) if (sc->chainmask & (1 << i)) noise = MIN(calib->noise[i], noise); memset(&cmd, 0, sizeof cmd); cmd.code = IWN4965_PHY_CALIB_DIFF_GAIN; /* Set differential gains for connected antennas. */ for (i = 0; i < 3; i++) { if (sc->chainmask & (1 << i)) { /* Compute attenuation (in unit of 1.5dB). */ delta = (noise - (int32_t)calib->noise[i]) / 30; /* NB: delta <= 0 */ /* Limit to [-4.5dB,0]. */ cmd.gain[i] = MIN(abs(delta), 3); if (delta < 0) cmd.gain[i] |= 1 << 2; /* sign bit */ } } DPRINTF(("setting differential gains Ant A/B/C: %x/%x/%x (%x)\n", cmd.gain[0], cmd.gain[1], cmd.gain[2], sc->chainmask)); return that->iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); } int ItlIwn:: iwn5000_set_gains(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_calib_state *calib = &sc->calib; struct iwn_phy_calib_gain cmd; int i, ant, div, delta; /* We collected 20 beacons and !=6050 need a 1.5 factor. */ div = (sc->hw_type == IWN_HW_REV_TYPE_6050) ? 20 : 30; memset(&cmd, 0, sizeof cmd); cmd.code = sc->noise_gain; cmd.ngroups = 1; cmd.isvalid = 1; /* * Get first available RX antenna as referential. * IWN_LSB() return values start with 1, but antenna gain array * cmd.gain[] and noise array calib->noise[] start with 0. */ ant = IWN_LSB(sc->rxchainmask) - 1; /* Set differential gains for other antennas. */ for (i = ant + 1; i < 3; i++) { if (sc->chainmask & (1 << i)) { /* The delta is relative to antenna "ant". */ delta = ((int32_t)calib->noise[ant] - (int32_t)calib->noise[i]) / div; DPRINTF(("Ant[%d] vs. Ant[%d]: delta %d\n", ant, i, delta)); /* Limit to [-4.5dB,+4.5dB]. */ cmd.gain[i] = MIN(abs(delta), 3); if (delta < 0) cmd.gain[i] |= 1 << 2; /* sign bit */ DPRINTF(("Setting differential gains for antenna %d: %x\n", i, cmd.gain[i])); } } return that->iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); } /* * Tune RF RX sensitivity based on the number of false alarms detected * during the last beacon period. */ void ItlIwn:: iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats) { #define inc(val, inc, max) \ if ((val) < (max)) { \ if ((val) < (max) - (inc)) \ (val) += (inc); \ else \ (val) = (max); \ needs_update = 1; \ } #define dec(val, dec, min) \ if ((val) > (min)) { \ if ((val) > (min) + (dec)) \ (val) -= (dec); \ else \ (val) = (min); \ needs_update = 1; \ } const struct iwn_sensitivity_limits *limits = sc->limits; struct iwn_calib_state *calib = &sc->calib; uint32_t val, rxena, fa; uint32_t energy[3], energy_min; uint8_t noise[3], noise_ref; int i, needs_update = 0; /* Check that we've been enabled long enough. */ if ((rxena = letoh32(stats->general.load)) == 0) return; /* Compute number of false alarms since last call for OFDM. */ fa = letoh32(stats->ofdm.bad_plcp) - calib->bad_plcp_ofdm; fa += letoh32(stats->ofdm.fa) - calib->fa_ofdm; fa *= 200 * IEEE80211_DUR_TU; /* 200TU */ /* Save counters values for next call. */ calib->bad_plcp_ofdm = letoh32(stats->ofdm.bad_plcp); calib->fa_ofdm = letoh32(stats->ofdm.fa); if (fa > 50 * rxena) { /* High false alarm count, decrease sensitivity. */ DPRINTFN(2, ("OFDM high false alarm count: %u\n", fa)); inc(calib->ofdm_x1, 1, limits->max_ofdm_x1); inc(calib->ofdm_mrc_x1, 1, limits->max_ofdm_mrc_x1); inc(calib->ofdm_x4, 1, limits->max_ofdm_x4); inc(calib->ofdm_mrc_x4, 1, limits->max_ofdm_mrc_x4); } else if (fa < 5 * rxena) { /* Low false alarm count, increase sensitivity. */ DPRINTFN(2, ("OFDM low false alarm count: %u\n", fa)); dec(calib->ofdm_x1, 1, limits->min_ofdm_x1); dec(calib->ofdm_mrc_x1, 1, limits->min_ofdm_mrc_x1); dec(calib->ofdm_x4, 1, limits->min_ofdm_x4); dec(calib->ofdm_mrc_x4, 1, limits->min_ofdm_mrc_x4); } /* Compute maximum noise among 3 receivers. */ for (i = 0; i < 3; i++) noise[i] = (letoh32(stats->general.noise[i]) >> 8) & 0xff; val = MAX(noise[0], noise[1]); val = MAX(noise[2], val); /* Insert it into our samples table. */ calib->noise_samples[calib->cur_noise_sample] = val; calib->cur_noise_sample = (calib->cur_noise_sample + 1) % 20; /* Compute maximum noise among last 20 samples. */ noise_ref = calib->noise_samples[0]; for (i = 1; i < 20; i++) noise_ref = MAX(noise_ref, calib->noise_samples[i]); /* Compute maximum energy among 3 receivers. */ for (i = 0; i < 3; i++) energy[i] = letoh32(stats->general.energy[i]); val = MIN(energy[0], energy[1]); val = MIN(energy[2], val); /* Insert it into our samples table. */ calib->energy_samples[calib->cur_energy_sample] = val; calib->cur_energy_sample = (calib->cur_energy_sample + 1) % 10; /* Compute minimum energy among last 10 samples. */ energy_min = calib->energy_samples[0]; for (i = 1; i < 10; i++) energy_min = MAX(energy_min, calib->energy_samples[i]); energy_min += 6; /* Compute number of false alarms since last call for CCK. */ fa = letoh32(stats->cck.bad_plcp) - calib->bad_plcp_cck; fa += letoh32(stats->cck.fa) - calib->fa_cck; fa *= 200 * IEEE80211_DUR_TU; /* 200TU */ /* Save counters values for next call. */ calib->bad_plcp_cck = letoh32(stats->cck.bad_plcp); calib->fa_cck = letoh32(stats->cck.fa); if (fa > 50 * rxena) { /* High false alarm count, decrease sensitivity. */ DPRINTFN(2, ("CCK high false alarm count: %u\n", fa)); calib->cck_state = IWN_CCK_STATE_HIFA; calib->low_fa = 0; if (calib->cck_x4 > 160) { calib->noise_ref = noise_ref; if (calib->energy_cck > 2) dec(calib->energy_cck, 2, energy_min); } if (calib->cck_x4 < 160) { calib->cck_x4 = 161; needs_update = 1; } else inc(calib->cck_x4, 3, limits->max_cck_x4); inc(calib->cck_mrc_x4, 3, limits->max_cck_mrc_x4); } else if (fa < 5 * rxena) { /* Low false alarm count, increase sensitivity. */ DPRINTFN(2, ("CCK low false alarm count: %u\n", fa)); calib->cck_state = IWN_CCK_STATE_LOFA; calib->low_fa++; if (calib->cck_state != IWN_CCK_STATE_INIT && (((int32_t)calib->noise_ref - (int32_t)noise_ref) > 2 || calib->low_fa > 100)) { inc(calib->energy_cck, 2, limits->min_energy_cck); dec(calib->cck_x4, 3, limits->min_cck_x4); dec(calib->cck_mrc_x4, 3, limits->min_cck_mrc_x4); } } else { /* Not worth to increase or decrease sensitivity. */ DPRINTFN(2, ("CCK normal false alarm count: %u\n", fa)); calib->low_fa = 0; calib->noise_ref = noise_ref; if (calib->cck_state == IWN_CCK_STATE_HIFA) { /* Previous interval had many false alarms. */ dec(calib->energy_cck, 8, energy_min); } calib->cck_state = IWN_CCK_STATE_INIT; } if (needs_update) (void)iwn_send_sensitivity(sc); #undef dec #undef inc } int ItlIwn:: iwn_send_sensitivity(struct iwn_softc *sc) { struct iwn_calib_state *calib = &sc->calib; struct iwn_enhanced_sensitivity_cmd cmd; int len; memset(&cmd, 0, sizeof cmd); len = sizeof (struct iwn_sensitivity_cmd); cmd.which = IWN_SENSITIVITY_WORKTBL; /* OFDM modulation. */ cmd.corr_ofdm_x1 = htole16(calib->ofdm_x1); cmd.corr_ofdm_mrc_x1 = htole16(calib->ofdm_mrc_x1); cmd.corr_ofdm_x4 = htole16(calib->ofdm_x4); cmd.corr_ofdm_mrc_x4 = htole16(calib->ofdm_mrc_x4); cmd.energy_ofdm = htole16(sc->limits->energy_ofdm); cmd.energy_ofdm_th = htole16(62); /* CCK modulation. */ cmd.corr_cck_x4 = htole16(calib->cck_x4); cmd.corr_cck_mrc_x4 = htole16(calib->cck_mrc_x4); cmd.energy_cck = htole16(calib->energy_cck); /* Barker modulation: use default values. */ cmd.corr_barker = htole16(190); cmd.corr_barker_mrc = htole16(390); if (!(sc->sc_flags & IWN_FLAG_ENH_SENS)) goto send; /* Enhanced sensitivity settings. */ len = sizeof (struct iwn_enhanced_sensitivity_cmd); cmd.ofdm_det_slope_mrc = htole16(668); cmd.ofdm_det_icept_mrc = htole16(4); cmd.ofdm_det_slope = htole16(486); cmd.ofdm_det_icept = htole16(37); cmd.cck_det_slope_mrc = htole16(853); cmd.cck_det_icept_mrc = htole16(4); cmd.cck_det_slope = htole16(476); cmd.cck_det_icept = htole16(99); send: return iwn_cmd(sc, IWN_CMD_SET_SENSITIVITY, &cmd, len, 1); } /* * Set STA mode power saving level (between 0 and 5). * Level 0 is CAM (Continuously Aware Mode), 5 is for maximum power saving. */ int ItlIwn:: iwn_set_pslevel(struct iwn_softc *sc, int dtim, int level, int async) { struct iwn_pmgt_cmd cmd; const struct iwn_pmgt *pmgt; uint32_t max, skip_dtim; pcireg_t reg; int i; /* Select which PS parameters to use. */ if (dtim <= 2) pmgt = &iwn_pmgt[0][level]; else if (dtim <= 10) pmgt = &iwn_pmgt[1][level]; else pmgt = &iwn_pmgt[2][level]; memset(&cmd, 0, sizeof cmd); if (level != 0) /* not CAM */ cmd.flags |= htole16(IWN_PS_ALLOW_SLEEP); if (level == 5) cmd.flags |= htole16(IWN_PS_FAST_PD); /* Retrieve PCIe Active State Power Management (ASPM). */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_LCSR); if (!(reg & PCI_PCIE_LCSR_ASPM_L0S)) /* L0s Entry disabled. */ cmd.flags |= htole16(IWN_PS_PCI_PMGT); cmd.rxtimeout = htole32(pmgt->rxtimeout * 1024); cmd.txtimeout = htole32(pmgt->txtimeout * 1024); if (dtim == 0) { dtim = 1; skip_dtim = 0; } else skip_dtim = pmgt->skip_dtim; if (skip_dtim != 0) { cmd.flags |= htole16(IWN_PS_SLEEP_OVER_DTIM); max = pmgt->intval[4]; if (max == (uint32_t)-1) max = dtim * (skip_dtim + 1); else if (max > dtim) max = (max / dtim) * dtim; } else max = dtim; for (i = 0; i < 5; i++) cmd.intval[i] = htole32(MIN(max, pmgt->intval[i])); DPRINTF(("setting power saving level to %d\n", level)); return iwn_cmd(sc, IWN_CMD_SET_POWER_MODE, &cmd, sizeof cmd, async); } int ItlIwn:: iwn_send_btcoex(struct iwn_softc *sc) { struct iwn_bluetooth cmd; memset(&cmd, 0, sizeof cmd); cmd.flags = IWN_BT_COEX_CHAN_ANN | IWN_BT_COEX_BT_PRIO; cmd.lead_time = IWN_BT_LEAD_TIME_DEF; cmd.max_kill = IWN_BT_MAX_KILL_DEF; DPRINTF(("configuring bluetooth coexistence\n")); return iwn_cmd(sc, IWN_CMD_BT_COEX, &cmd, sizeof(cmd), 0); } int ItlIwn:: iwn_send_advanced_btcoex(struct iwn_softc *sc) { static const uint32_t btcoex_3wire[12] = { 0xaaaaaaaa, 0xaaaaaaaa, 0xaeaaaaaa, 0xaaaaaaaa, 0xcc00ff28, 0x0000aaaa, 0xcc00aaaa, 0x0000aaaa, 0xc0004000, 0x00004000, 0xf0005000, 0xf0005000, }; struct iwn_btcoex_priotable btprio; struct iwn_btcoex_prot btprot; int error, i; if (sc->hw_type == IWN_HW_REV_TYPE_2030 || sc->hw_type == IWN_HW_REV_TYPE_135) { struct iwn2000_btcoex_config btconfig; memset(&btconfig, 0, sizeof btconfig); btconfig.flags = IWN_BT_COEX6000_CHAN_INHIBITION | (IWN_BT_COEX6000_MODE_3W << IWN_BT_COEX6000_MODE_SHIFT) | IWN_BT_SYNC_2_BT_DISABLE; btconfig.max_kill = 5; btconfig.bt3_t7_timer = 1; btconfig.kill_ack = htole32(0xffff0000); btconfig.kill_cts = htole32(0xffff0000); btconfig.sample_time = 2; btconfig.bt3_t2_timer = 0xc; for (i = 0; i < 12; i++) btconfig.lookup_table[i] = htole32(btcoex_3wire[i]); btconfig.valid = htole16(0xff); btconfig.prio_boost = htole32(0xf0); DPRINTF(("configuring advanced bluetooth coexistence\n")); error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig, sizeof(btconfig), 1); if (error != 0) return (error); } else { struct iwn6000_btcoex_config btconfig; memset(&btconfig, 0, sizeof btconfig); btconfig.flags = IWN_BT_COEX6000_CHAN_INHIBITION | (IWN_BT_COEX6000_MODE_3W << IWN_BT_COEX6000_MODE_SHIFT) | IWN_BT_SYNC_2_BT_DISABLE; btconfig.max_kill = 5; btconfig.bt3_t7_timer = 1; btconfig.kill_ack = htole32(0xffff0000); btconfig.kill_cts = htole32(0xffff0000); btconfig.sample_time = 2; btconfig.bt3_t2_timer = 0xc; for (i = 0; i < 12; i++) btconfig.lookup_table[i] = htole32(btcoex_3wire[i]); btconfig.valid = htole16(0xff); btconfig.prio_boost = 0xf0; DPRINTF(("configuring advanced bluetooth coexistence\n")); error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig, sizeof(btconfig), 1); if (error != 0) return (error); } memset(&btprio, 0, sizeof btprio); btprio.calib_init1 = 0x6; btprio.calib_init2 = 0x7; btprio.calib_periodic_low1 = 0x2; btprio.calib_periodic_low2 = 0x3; btprio.calib_periodic_high1 = 0x4; btprio.calib_periodic_high2 = 0x5; btprio.dtim = 0x6; btprio.scan52 = 0x8; btprio.scan24 = 0xa; error = iwn_cmd(sc, IWN_CMD_BT_COEX_PRIOTABLE, &btprio, sizeof(btprio), 1); if (error != 0) return (error); /* Force BT state machine change */ memset(&btprot, 0, sizeof btprot); btprot.open = 1; btprot.type = 1; error = iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof(btprot), 1); if (error != 0) return (error); btprot.open = 0; return (iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof(btprot), 1)); } int ItlIwn:: iwn5000_runtime_calib(struct iwn_softc *sc) { struct iwn5000_calib_config cmd; memset(&cmd, 0, sizeof cmd); cmd.ucode.once.enable = 0xffffffff; cmd.ucode.once.start = IWN5000_CALIB_DC; DPRINTF(("configuring runtime calibration\n")); return iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof(cmd), 0); } int ItlIwn:: iwn_config(struct iwn_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwn_ops *ops = &sc->ops; struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; uint32_t txmask; uint16_t rxchain; int error, ridx; /* Set radio temperature sensor offset. */ if (sc->hw_type == IWN_HW_REV_TYPE_6005) { error = iwn6000_temp_offset_calib(sc); if (error != 0) { XYLog("%s: could not set temperature offset\n", sc->sc_dev.dv_xname); return error; } } if (sc->hw_type == IWN_HW_REV_TYPE_2030 || sc->hw_type == IWN_HW_REV_TYPE_2000 || sc->hw_type == IWN_HW_REV_TYPE_135 || sc->hw_type == IWN_HW_REV_TYPE_105) { error = iwn2000_temp_offset_calib(sc); if (error != 0) { XYLog("%s: could not set temperature offset\n", sc->sc_dev.dv_xname); return error; } } if (sc->hw_type == IWN_HW_REV_TYPE_6050 || sc->hw_type == IWN_HW_REV_TYPE_6005) { /* Configure runtime DC calibration. */ error = iwn5000_runtime_calib(sc); if (error != 0) { XYLog("%s: could not configure runtime calibration\n", sc->sc_dev.dv_xname); return error; } } /* Configure valid TX chains for >=5000 Series. */ if (sc->hw_type != IWN_HW_REV_TYPE_4965) { txmask = htole32(sc->txchainmask); DPRINTF(("configuring valid TX chains 0x%x\n", txmask)); error = iwn_cmd(sc, IWN5000_CMD_TX_ANT_CONFIG, &txmask, sizeof txmask, 0); if (error != 0) { XYLog("%s: could not configure valid TX chains\n", sc->sc_dev.dv_xname); return error; } } /* Configure bluetooth coexistence. */ if (sc->sc_flags & IWN_FLAG_ADV_BT_COEX) error = iwn_send_advanced_btcoex(sc); else error = iwn_send_btcoex(sc); if (error != 0) { XYLog("%s: could not configure bluetooth coexistence\n", sc->sc_dev.dv_xname); return error; } /* Set mode, channel, RX filter and enable RX. */ memset(&sc->rxon, 0, sizeof (struct iwn_rxon)); // IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl)); IEEE80211_ADDR_COPY(sc->rxon.myaddr, ic->ic_myaddr); IEEE80211_ADDR_COPY(sc->rxon.wlap, ic->ic_myaddr); sc->rxon.chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan); sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); if (IEEE80211_IS_CHAN_2GHZ(ic->ic_ibss_chan)) { sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); if (ic->ic_flags & IEEE80211_F_USEPROT) sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT); DPRINTF(("%s: 2ghz prot 0x%x\n", __func__, le32toh(sc->rxon.flags))); } switch (ic->ic_opmode) { case IEEE80211_M_STA: sc->rxon.mode = IWN_MODE_STA; sc->rxon.filter = htole32(IWN_FILTER_MULTICAST); break; case IEEE80211_M_MONITOR: sc->rxon.mode = IWN_MODE_MONITOR; sc->rxon.filter = htole32(IWN_FILTER_MULTICAST | IWN_FILTER_CTL | IWN_FILTER_PROMISC); break; default: /* Should not get there. */ break; } sc->rxon.cck_mask = 0x0f; /* not yet negotiated */ sc->rxon.ofdm_mask = 0xff; /* not yet negotiated */ sc->rxon.ht_single_mask = 0xff; sc->rxon.ht_dual_mask = 0xff; sc->rxon.ht_triple_mask = 0xff; rxchain = IWN_RXCHAIN_VALID(sc->rxchainmask) | IWN_RXCHAIN_MIMO_COUNT(sc->nrxchains) | IWN_RXCHAIN_IDLE_COUNT(sc->nrxchains); if (ic->ic_opmode == IEEE80211_M_MONITOR) { rxchain |= IWN_RXCHAIN_FORCE_SEL(sc->rxchainmask); rxchain |= IWN_RXCHAIN_FORCE_MIMO_SEL(sc->rxchainmask); rxchain |= (IWN_RXCHAIN_DRIVER_FORCE | IWN_RXCHAIN_MIMO_FORCE); } sc->rxon.rxchain = htole16(rxchain); DPRINTF(("setting configuration\n")); DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x rxchain %x\n", __func__, sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask, sc->rxon.ofdm_mask, sc->rxon.rxchain)); error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 0); if (error != 0) { XYLog("%s: RXON command failed\n", sc->sc_dev.dv_xname); return error; } ridx = (sc->sc_ic.ic_curmode == IEEE80211_MODE_11A) ? IWN_RIDX_OFDM : IWN_RIDX_CCK; if ((error = iwn_add_broadcast_node(sc, 0, ridx)) != 0) { XYLog("%s: could not add broadcast node\n", sc->sc_dev.dv_xname); return error; } /* Configuration has changed, set TX power accordingly. */ if ((error = ops->set_txpower(sc, 0)) != 0) { XYLog("%s: could not set TX power\n", sc->sc_dev.dv_xname); return error; } if ((error = iwn_set_critical_temp(sc)) != 0) { XYLog("%s: could not set critical temperature\n", sc->sc_dev.dv_xname); return error; } /* Set power saving level to CAM during initialization. */ if ((error = iwn_set_pslevel(sc, 0, 0, 0)) != 0) { XYLog("%s: could not set power saving level\n", sc->sc_dev.dv_xname); return error; } return 0; } uint16_t ItlIwn:: iwn_get_active_dwell_time(struct iwn_softc *sc, uint16_t flags, uint8_t n_probes) { /* No channel? Default to 2GHz settings */ if (flags & IEEE80211_CHAN_2GHZ) { return (IWN_ACTIVE_DWELL_TIME_2GHZ + IWN_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1)); } /* 5GHz dwell time */ return (IWN_ACTIVE_DWELL_TIME_5GHZ + IWN_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1)); } /* * Limit the total dwell time to 85% of the beacon interval. * * Returns the dwell time in milliseconds. */ uint16_t ItlIwn:: iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; int bintval = 0; /* bintval is in TU (1.024mS) */ if (ni != NULL) bintval = ni->ni_intval; /* * If it's non-zero, we should calculate the minimum of * it and the DWELL_BASE. * * XXX Yes, the math should take into account that bintval * is 1.024mS, not 1mS.. */ if (ic->ic_state == IEEE80211_S_RUN && bintval > 0) return (MIN(IWN_PASSIVE_DWELL_BASE, ((bintval * 85) / 100))); /* No association context? Default */ return dwell_time; } uint16_t ItlIwn:: iwn_get_passive_dwell_time(struct iwn_softc *sc, uint16_t flags) { uint16_t passive; if (flags & IEEE80211_CHAN_2GHZ) { passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_2GHZ; } else { passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_5GHZ; } /* Clamp to the beacon interval if we're associated */ return (iwn_limit_dwell(sc, passive)); } int ItlIwn:: iwn_scan(struct iwn_softc *sc, uint16_t flags, int bgscan) { XYLog("%s flags=%d bgscan=%d\n", __FUNCTION__, flags, bgscan); struct ieee80211com *ic = &sc->sc_ic; struct iwn_scan_hdr *hdr; struct iwn_cmd_data *tx; struct iwn_scan_essid *essid; struct iwn_scan_chan *chan; struct ieee80211_frame *wh; struct ieee80211_rateset *rs; struct ieee80211_channel *c; uint8_t *buf, *frm; uint16_t rxchain, dwell_active, dwell_passive; uint8_t txant; int buflen, error, is_active; buf = (uint8_t *)malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); if (buf == NULL) { XYLog("%s: could not allocate buffer for scan command\n", sc->sc_dev.dv_xname); return ENOMEM; } hdr = (struct iwn_scan_hdr *)buf; /* * Move to the next channel if no frames are received within 10ms * after sending the probe request. */ hdr->quiet_time = htole16(10); /* timeout in milliseconds */ hdr->quiet_threshold = htole16(1); /* min # of packets */ if (bgscan) { int bintval; /* Set maximum off-channel time. */ hdr->max_out = htole32(200 * 1024); /* Configure scan pauses which service on-channel traffic. */ bintval = ic->ic_bss->ni_intval ? ic->ic_bss->ni_intval : 100; hdr->pause_scan = htole32(((100 / bintval) << 22) | ((100 % bintval) * 1024)); } /* Select antennas for scanning. */ rxchain = IWN_RXCHAIN_VALID(sc->rxchainmask) | IWN_RXCHAIN_FORCE_MIMO_SEL(sc->rxchainmask) | IWN_RXCHAIN_DRIVER_FORCE; if ((flags & IEEE80211_CHAN_5GHZ) && sc->hw_type == IWN_HW_REV_TYPE_4965) { /* * On 4965 ant A and C must be avoided in 5GHz because of a * HW bug which causes very weak RSSI values being reported. */ rxchain |= IWN_RXCHAIN_FORCE_SEL(IWN_ANT_B); } else /* Use all available RX antennas. */ rxchain |= IWN_RXCHAIN_FORCE_SEL(sc->rxchainmask); hdr->rxchain = htole16(rxchain); hdr->filter = htole32(IWN_FILTER_MULTICAST | IWN_FILTER_BEACON); tx = (struct iwn_cmd_data *)(hdr + 1); tx->flags = htole32(IWN_TX_AUTO_SEQ); tx->id = sc->broadcast_id; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); if (flags & IEEE80211_CHAN_5GHZ) { /* Send probe requests at 6Mbps. */ tx->plcp = iwn_rates[IWN_RATE_6M_INDEX].plcp; rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; } else { hdr->flags = htole32(IWN_RXON_24GHZ | IWN_RXON_AUTO); if (bgscan && sc->hw_type == IWN_HW_REV_TYPE_4965 && sc->rxon.chan > 14) { /* * 4965 firmware can crash when sending probe requests * with CCK rates while associated to a 5GHz AP. * Send probe requests at 6Mbps OFDM as a workaround. */ tx->plcp = iwn_rates[IWN_RATE_6M_INDEX].plcp; } else { /* Send probe requests at 1Mbps. */ tx->plcp = iwn_rates[IWN_RATE_1M_INDEX].plcp; tx->rflags = IWN_RFLAG_CCK; } rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; } /* Use the first valid TX antenna. */ txant = IWN_LSB(sc->txchainmask); tx->rflags |= IWN_RFLAG_ANT(txant); /* * Only do active scanning if we're announcing a probe request * for a given SSID (or more, if we ever add it to the driver.) */ is_active = 0; /* * If we're scanning for a specific SSID, add it to the command. */ essid = (struct iwn_scan_essid *)(tx + 1); if (ic->ic_des_esslen != 0) { essid[0].id = IEEE80211_ELEMID_SSID; essid[0].len = ic->ic_des_esslen; memcpy(essid[0].data, ic->ic_des_essid, ic->ic_des_esslen); is_active = 1; } /* * Build a probe request frame. Most of the following code is a * copy & paste of what is done in net80211. */ wh = (struct ieee80211_frame *)(essid + 20); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr); *(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */ *(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */ frm = (uint8_t *)(wh + 1); frm = ieee80211_add_ssid(frm, NULL, 0); frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); if (ic->ic_flags & IEEE80211_F_HTON) frm = ieee80211_add_htcaps(frm, ic); /* Set length of probe request. */ tx->len = htole16(frm - (uint8_t *)wh); /* * If active scanning is requested but a certain channel is * marked passive, we can do active scanning if we detect * transmissions. * * There is an issue with some firmware versions that triggers * a sysassert on a "good CRC threshold" of zero (== disabled), * on a radar channel even though this means that we should NOT * send probes. * * The "good CRC threshold" is the number of frames that we * need to receive during our dwell time on a channel before * sending out probes -- setting this to a huge value will * mean we never reach it, but at the same time work around * the aforementioned issue. Thus use IWN_GOOD_CRC_TH_NEVER * here instead of IWN_GOOD_CRC_TH_DISABLED. * * This was fixed in later versions along with some other * scan changes, and the threshold behaves as a flag in those * versions. */ /* * If we're doing active scanning, set the crc_threshold * to a suitable value. This is different to active veruss * passive scanning depending upon the channel flags; the * firmware will obey that particular check for us. */ if (sc->tlv_feature_flags & IWN_UCODE_TLV_FLAGS_NEWSCAN) hdr->crc_threshold = is_active ? IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_DISABLED; else hdr->crc_threshold = is_active ? IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_NEVER; chan = (struct iwn_scan_chan *)frm; for (c = &ic->ic_channels[1]; c <= &ic->ic_channels[IEEE80211_CHAN_MAX]; c++) { if ((c->ic_flags & flags) != flags) continue; chan->chan = htole16(ieee80211_chan2ieee(ic, c)); DPRINTFN(2, ("adding channel %d\n", chan->chan)); chan->flags = 0; if (ic->ic_des_esslen != 0) chan->flags |= htole32(IWN_CHAN_NPBREQS(1)); if (c->ic_flags & IEEE80211_CHAN_PASSIVE) chan->flags |= htole32(IWN_CHAN_PASSIVE); else chan->flags |= htole32(IWN_CHAN_ACTIVE); /* * Calculate the active/passive dwell times. */ dwell_active = iwn_get_active_dwell_time(sc, flags, is_active); dwell_passive = iwn_get_passive_dwell_time(sc, flags); /* Make sure they're valid */ if (dwell_passive <= dwell_active) dwell_passive = dwell_active + 1; chan->active = htole16(dwell_active); chan->passive = htole16(dwell_passive); chan->dsp_gain = 0x6e; if (IEEE80211_IS_CHAN_5GHZ(c)) { chan->rf_gain = 0x3b; } else { chan->rf_gain = 0x28; } hdr->nchan++; chan++; } buflen = (uint8_t *)chan - buf; hdr->len = htole16(buflen); error = iwn_cmd(sc, IWN_CMD_SCAN, buf, buflen, 1); if (error == 0) { /* * The current mode might have been fixed during association. * Ensure all channels get scanned. */ if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); sc->sc_flags |= IWN_FLAG_SCANNING; if (bgscan) sc->sc_flags |= IWN_FLAG_BGSCAN; } ::free(buf); return error; } void ItlIwn:: iwn_scan_abort(struct iwn_softc *sc) { XYLog("%s\n", __FUNCTION__); iwn_cmd(sc, IWN_CMD_SCAN_ABORT, NULL, 0, 1); /* XXX Cannot wait for status response in interrupt context. */ DELAY(100); sc->sc_flags &= ~IWN_FLAG_SCANNING; sc->sc_flags &= ~IWN_FLAG_BGSCAN; } int ItlIwn:: iwn_bgscan(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; ItlIwn *that = container_of(sc, ItlIwn, com); int error; if (sc->sc_flags & IWN_FLAG_SCANNING) return 0; error = that->iwn_scan(sc, IEEE80211_CHAN_2GHZ, 1); if (error) XYLog("%s: could not initiate background scan\n", sc->sc_dev.dv_xname); return error; } void ItlIwn:: iwn_rxon_configure_ht40(struct ieee80211com *ic, struct ieee80211_node *ni) { struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; uint8_t sco = (ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK); int htprot = (ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK); sc->rxon.flags &= ~htole32(IWN_RXON_HT_CHANMODE_MIXED2040 | IWN_RXON_HT_CHANMODE_PURE40 | IWN_RXON_HT_HT40MINUS); if (ieee80211_node_supports_ht_chan40(ni) && (sco == IEEE80211_HTOP0_SCO_SCA || sco == IEEE80211_HTOP0_SCO_SCB)) { if (sco == IEEE80211_HTOP0_SCO_SCB) sc->rxon.flags |= htole32(IWN_RXON_HT_HT40MINUS); if (htprot == IEEE80211_HTPROT_20MHZ) sc->rxon.flags |= htole32(IWN_RXON_HT_CHANMODE_PURE40); else sc->rxon.flags |= htole32( IWN_RXON_HT_CHANMODE_MIXED2040); } } int ItlIwn:: iwn_rxon_ht40_enabled(struct iwn_softc *sc) { return ((le32toh(sc->rxon.flags) & IWN_RXON_HT_CHANMODE_MIXED2040) || (le32toh(sc->rxon.flags) & IWN_RXON_HT_CHANMODE_PURE40)) ? 1 : 0; } int ItlIwn:: iwn_auth(struct iwn_softc *sc, int arg) { XYLog("%s\n", __FUNCTION__); struct iwn_ops *ops = &sc->ops; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; int error, ridx; int bss_switch = (!IEEE80211_ADDR_EQ(sc->bss_node_addr, etheranyaddr) && !IEEE80211_ADDR_EQ(sc->bss_node_addr, ni->ni_macaddr)); /* Update adapter configuration. */ IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid); sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan); sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); if (ic->ic_flags & IEEE80211_F_USEPROT) sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT); DPRINTF(("%s: 2ghz prot 0x%x\n", __func__, le32toh(sc->rxon.flags))); } if (ic->ic_flags & IEEE80211_F_SHSLOT) sc->rxon.flags |= htole32(IWN_RXON_SHSLOT); else sc->rxon.flags &= ~htole32(IWN_RXON_SHSLOT); if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) sc->rxon.flags |= htole32(IWN_RXON_SHPREAMBLE); else sc->rxon.flags &= ~htole32(IWN_RXON_SHPREAMBLE); switch (ic->ic_curmode) { case IEEE80211_MODE_11A: sc->rxon.cck_mask = 0; sc->rxon.ofdm_mask = 0x15; break; case IEEE80211_MODE_11B: sc->rxon.cck_mask = 0x03; sc->rxon.ofdm_mask = 0; break; default: /* Assume 802.11b/g/n. */ sc->rxon.cck_mask = 0x0f; sc->rxon.ofdm_mask = 0x15; } /* Configure 40MHz early to avoid problems on 6205 devices. */ iwn_rxon_configure_ht40(ic, ni); DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x\n", __func__, sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask, sc->rxon.ofdm_mask)); error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); if (error != 0) { XYLog("%s: RXON command failed\n", sc->sc_dev.dv_xname); return error; } /* Configuration has changed, set TX power accordingly. */ if ((error = ops->set_txpower(sc, 1)) != 0) { XYLog("%s: could not set TX power\n", sc->sc_dev.dv_xname); return error; } /* * Reconfiguring RXON clears the firmware nodes table so we must * add the broadcast node again. */ ridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWN_RIDX_OFDM : IWN_RIDX_CCK; if ((error = iwn_add_broadcast_node(sc, 1, ridx)) != 0) { XYLog("%s: could not add broadcast node\n", sc->sc_dev.dv_xname); return error; } /* * Make sure the firmware gets to see a beacon before we send * the auth request. Otherwise the Tx attempt can fail due to * the firmware's built-in regulatory domain enforcement. * Delaying here for every incoming deauth frame can result in a DoS. * Don't delay if we're here because of an incoming frame (arg != -1) * or if we're already waiting for a response (ic_mgt_timer != 0). * If we are switching APs after a background scan then net80211 has * just faked the reception of a deauth frame from our old AP, so it * is safe to delay in that case. */ if ((arg == -1 || bss_switch) && ic->ic_mgt_timer == 0) DELAY(ni->ni_intval * 3 * IEEE80211_DUR_TU); /* We can now clear the cached address of our previous AP. */ memset(sc->bss_node_addr, 0, sizeof(sc->bss_node_addr)); return 0; } int ItlIwn:: iwn_run(struct iwn_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwn_ops *ops = &sc->ops; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; struct iwn_node *wn = (struct iwn_node *)ni; struct iwn_node_info node; int error; if (ic->ic_opmode == IEEE80211_M_MONITOR) { /* Link LED blinks while monitoring. */ iwn_set_led(sc, IWN_LED_LINK, 50, 50); return 0; } if ((error = iwn_set_timing(sc, ni)) != 0) { XYLog("%s: could not set timing\n", sc->sc_dev.dv_xname); return error; } /* Update adapter configuration. */ sc->rxon.associd = htole16(IEEE80211_AID(ni->ni_associd)); /* Short preamble and slot time are negotiated when associating. */ sc->rxon.flags &= ~htole32(IWN_RXON_SHPREAMBLE | IWN_RXON_SHSLOT); if (ic->ic_flags & IEEE80211_F_SHSLOT) sc->rxon.flags |= htole32(IWN_RXON_SHSLOT); if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) sc->rxon.flags |= htole32(IWN_RXON_SHPREAMBLE); sc->rxon.filter |= htole32(IWN_FILTER_BSS); /* HT is negotiated when associating. */ if (ni->ni_flags & IEEE80211_NODE_HT) { enum ieee80211_htprot htprot = (ieee80211_htprot)(ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK); DPRINTF(("%s: htprot = %d\n", __func__, htprot)); sc->rxon.flags |= htole32(IWN_RXON_HT_PROTMODE(htprot)); } else sc->rxon.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3)); iwn_rxon_configure_ht40(ic, ni); if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) { /* 11a or 11n 5GHz */ sc->rxon.cck_mask = 0; sc->rxon.ofdm_mask = 0x15; } else if (ni->ni_flags & IEEE80211_NODE_HT) { /* 11n 2GHz */ sc->rxon.cck_mask = 0x0f; sc->rxon.ofdm_mask = 0x15; } else { if (ni->ni_rates.rs_nrates == 4) { /* 11b */ sc->rxon.cck_mask = 0x03; sc->rxon.ofdm_mask = 0; } else { /* assume 11g */ sc->rxon.cck_mask = 0x0f; sc->rxon.ofdm_mask = 0x15; } } DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x\n", __func__, sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask, sc->rxon.ofdm_mask)); error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); if (error != 0) { XYLog("%s: could not update configuration\n", sc->sc_dev.dv_xname); return error; } /* Configuration has changed, set TX power accordingly. */ if ((error = ops->set_txpower(sc, 1)) != 0) { XYLog("%s: could not set TX power\n", sc->sc_dev.dv_xname); return error; } /* Fake a join to initialize the TX rate. */ ((struct iwn_node *)ni)->id = IWN_ID_BSS; iwn_newassoc(ic, ni, 1); /* Add BSS node. */ memset(&node, 0, sizeof node); IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr); node.id = IWN_ID_BSS; if (ni->ni_flags & IEEE80211_NODE_HT) { node.htmask = (IWN_AMDPU_SIZE_FACTOR_MASK | IWN_AMDPU_DENSITY_MASK); node.htflags = htole32( IWN_AMDPU_SIZE_FACTOR( (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_LE)) | IWN_AMDPU_DENSITY( (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_SS) >> 2)); if (iwn_rxon_ht40_enabled(sc)) node.htflags |= htole32(IWN_40MHZ_ENABLE); } DPRINTF(("adding BSS node\n")); error = ops->add_node(sc, &node, 1); if (error != 0) { XYLog("%s: could not add BSS node\n", sc->sc_dev.dv_xname); return error; } /* Cache address of AP in case it changes after a background scan. */ IEEE80211_ADDR_COPY(sc->bss_node_addr, ni->ni_macaddr); DPRINTF(("setting link quality for node %d\n", node.id)); if ((error = iwn_set_link_quality(sc, ni)) != 0) { XYLog("%s: could not setup link quality for node %d\n", sc->sc_dev.dv_xname, node.id); return error; } if ((error = iwn_init_sensitivity(sc)) != 0) { XYLog("%s: could not set sensitivity\n", sc->sc_dev.dv_xname); return error; } /* Start periodic calibration timer. */ sc->calib.state = IWN_CALIB_STATE_ASSOC; sc->calib_cnt = 0; timeout_add_msec(&sc->calib_to, 500); ieee80211_ra_node_init(ic, &wn->rn, &wn->ni); /* Link LED always on while associated. */ iwn_set_led(sc, IWN_LED_LINK, 0, 1); return 0; } /* * We support CCMP hardware encryption/decryption of unicast frames only. * HW support for TKIP really sucks. We should let TKIP die anyway. */ int ItlIwn:: iwn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (iwn_node *)ni; struct iwn_node_info node; uint16_t kflags; if ((k->k_flags & IEEE80211_KEY_GROUP) || k->k_cipher != IEEE80211_CIPHER_CCMP) return ieee80211_set_key(ic, ni, k); kflags = IWN_KFLAG_CCMP | IWN_KFLAG_MAP | IWN_KFLAG_KID(k->k_id); if (k->k_flags & IEEE80211_KEY_GROUP) kflags |= IWN_KFLAG_GROUP; memset(&node, 0, sizeof node); node.id = (k->k_flags & IEEE80211_KEY_GROUP) ? sc->broadcast_id : wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_KEY; node.kflags = htole16(kflags); node.kid = k->k_id; memcpy(node.key, k->k_key, k->k_len); DPRINTF(("set key id=%d for node %d\n", k->k_id, node.id)); return ops->add_node(sc, &node, 1); } void ItlIwn:: iwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (struct iwn_node *)ni; struct iwn_node_info node; if ((k->k_flags & IEEE80211_KEY_GROUP) || k->k_cipher != IEEE80211_CIPHER_CCMP) { /* See comment about other ciphers above. */ ieee80211_delete_key(ic, ni, k); return; } if (ic->ic_state != IEEE80211_S_RUN) return; /* Nothing to do. */ memset(&node, 0, sizeof node); node.id = (k->k_flags & IEEE80211_KEY_GROUP) ? sc->broadcast_id : wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_KEY; node.kflags = htole16(IWN_KFLAG_INVALID); node.kid = 0xff; DPRINTF(("delete keys for node %d\n", node.id)); (void)ops->add_node(sc, &node, 1); } void ItlIwn:: iwn_update_chw(struct ieee80211com *ic) { XYLog("%s update channel info\n", __FUNCTION__); struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; ItlIwn *that = container_of(sc, ItlIwn, com); if (ic->ic_state != IEEE80211_S_RUN) return; that->iwn_rxon_configure_ht40(ic, ic->ic_bss); sc->ops.update_rxon(sc); that->iwn_set_link_quality(sc, ic->ic_bss); } void ItlIwn:: iwn_updateprot(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; enum ieee80211_htprot htprot; if (ic->ic_state != IEEE80211_S_RUN) return; /* Update ERP protection setting. */ if (ic->ic_flags & IEEE80211_F_USEPROT) sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT); else sc->rxon.flags &= ~htole32(IWN_RXON_TGG_PROT); /* Update HT protection mode setting. */ htprot = (enum ieee80211_htprot)((ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK) >> IEEE80211_HTOP1_PROT_SHIFT); sc->rxon.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3)); sc->rxon.flags |= htole32(IWN_RXON_HT_PROTMODE(htprot)); sc->ops.update_rxon(sc); } void ItlIwn:: iwn_updateslot(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; if (ic->ic_state != IEEE80211_S_RUN) return; if (ic->ic_flags & IEEE80211_F_SHSLOT) sc->rxon.flags |= htole32(IWN_RXON_SHSLOT); else sc->rxon.flags &= ~htole32(IWN_RXON_SHSLOT); if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) sc->rxon.flags |= htole32(IWN_RXON_SHPREAMBLE); else sc->rxon.flags &= ~htole32(IWN_RXON_SHPREAMBLE); sc->ops.update_rxon(sc); } void ItlIwn:: iwn_update_rxon_restore_power(struct iwn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct iwn_ops *ops = &sc->ops; int error; DELAY(100); /* All RXONs wipe the firmware's txpower table. Restore it. */ error = ops->set_txpower(sc, 1); if (error != 0) printf("%s: could not set TX power\n", sc->sc_dev.dv_xname); DELAY(100); /* Restore power saving level */ if (ic->ic_flags & IEEE80211_F_PMGTON) error = iwn_set_pslevel(sc, 0, 3, 1); else error = iwn_set_pslevel(sc, 0, 0, 1); if (error != 0) printf("%s: could not set PS level\n", sc->sc_dev.dv_xname); } void ItlIwn:: iwn5000_update_rxon(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_rxon_assoc rxon_assoc; int s, error; /* Update RXON config. */ memset(&rxon_assoc, 0, sizeof(rxon_assoc)); rxon_assoc.flags = sc->rxon.flags; rxon_assoc.filter = sc->rxon.filter; rxon_assoc.ofdm_mask = sc->rxon.ofdm_mask; rxon_assoc.cck_mask = sc->rxon.cck_mask; rxon_assoc.ht_single_mask = sc->rxon.ht_single_mask; rxon_assoc.ht_dual_mask = sc->rxon.ht_dual_mask; rxon_assoc.ht_triple_mask = sc->rxon.ht_triple_mask; rxon_assoc.rxchain = sc->rxon.rxchain; rxon_assoc.acquisition = sc->rxon.acquisition; s = splnet(); error = that->iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &rxon_assoc, sizeof(rxon_assoc), 1); if (error != 0) printf("%s: RXON_ASSOC command failed\n", sc->sc_dev.dv_xname); that->iwn_update_rxon_restore_power(sc); splx(s); } void ItlIwn:: iwn4965_update_rxon(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn4965_rxon_assoc rxon_assoc; int s, error; /* Update RXON config. */ memset(&rxon_assoc, 0, sizeof(rxon_assoc)); rxon_assoc.flags = sc->rxon.flags; rxon_assoc.filter = sc->rxon.filter; rxon_assoc.ofdm_mask = sc->rxon.ofdm_mask; rxon_assoc.cck_mask = sc->rxon.cck_mask; rxon_assoc.ht_single_mask = sc->rxon.ht_single_mask; rxon_assoc.ht_dual_mask = sc->rxon.ht_dual_mask; rxon_assoc.rxchain = sc->rxon.rxchain; s = splnet(); error = that->iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &rxon_assoc, sizeof(rxon_assoc), 1); if (error != 0) printf("%s: RXON_ASSOC command failed\n", sc->sc_dev.dv_xname); that->iwn_update_rxon_restore_power(sc); splx(s); } /* * This function is called by upper layer when an ADDBA request is received * from another STA and before the ADDBA response is sent. */ int ItlIwn:: iwn_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (struct iwn_node *)ni; struct iwn_node_info node; memset(&node, 0, sizeof node); node.id = wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_ADDBA; node.addba_tid = tid; node.addba_ssn = htole16(ba->ba_winstart); DPRINTF(("ADDBA RA=%d TID=%d SSN=%d\n", wn->id, tid, ba->ba_winstart)); /* XXX async command, so firmware may still fail to add BA agreement */ return ops->add_node(sc, &node, 1); } /* * This function is called by upper layer on teardown of an HT-immediate * Block Ack agreement (eg. uppon receipt of a DELBA frame). */ void ItlIwn:: iwn_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (struct iwn_node *)ni; struct iwn_node_info node; memset(&node, 0, sizeof node); node.id = wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_DELBA; node.delba_tid = tid; DPRINTF(("DELBA RA=%d TID=%d\n", wn->id, tid)); (void)ops->add_node(sc, &node, 1); } /* * This function is called by upper layer when an ADDBA response is received * from another STA. */ int ItlIwn:: iwn_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (struct iwn_node *)ni; struct iwn_node_info node; int qid = sc->first_agg_txq + tid; int error; /* Ensure we can map this TID to an aggregation queue. */ if (tid >= IWN_NUM_AMPDU_TID || ba->ba_winsize > IWN_SCHED_WINSZ || qid > sc->ntxqs || (sc->agg_queue_mask & (1 << qid))) return ENOSPC; /* Enable TX for the specified RA/TID. */ wn->disable_tid &= ~(1 << tid); memset(&node, 0, sizeof node); node.id = wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_DISABLE_TID; node.disable_tid = htole16(wn->disable_tid); error = ops->add_node(sc, &node, 1); if (error != 0) return error; if ((error = iwn_nic_lock(sc)) != 0) return error; ops->ampdu_tx_start(sc, ni, tid, ba->ba_winstart); iwn_nic_unlock(sc); sc->agg_queue_mask |= (1 << qid); sc->sc_tx_ba[tid].wn = wn; ba->ba_bitmap = 0; return 0; } void ItlIwn:: iwn_ampdu_tx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_tx_ba *ba = (struct ieee80211_tx_ba *)&ni->ni_tx_ba[tid]; struct iwn_softc *sc = (struct iwn_softc *)ic->ic_softc; ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_ops *ops = &sc->ops; int qid = sc->first_agg_txq + tid; struct iwn_node *wn = (struct iwn_node *)ni; struct iwn_node_info node; /* Discard all frames in the current window. */ that->iwn_ampdu_txq_advance(sc, &sc->txq[qid], qid, IWN_AGG_SSN_TO_TXQ_IDX(ba->ba_winend)); if (iwn_nic_lock(sc) != 0) return; ops->ampdu_tx_stop(sc, tid, ba->ba_winstart); iwn_nic_unlock(sc); sc->agg_queue_mask &= ~(1 << qid); sc->sc_tx_ba[tid].wn = NULL; ba->ba_bitmap = 0; /* Disable TX for the specified RA/TID. */ wn->disable_tid |= (1 << tid); memset(&node, 0, sizeof node); node.id = wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_DISABLE_TID; node.disable_tid = htole16(wn->disable_tid); ops->add_node(sc, &node, 1); } void ItlIwn:: iwn4965_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, uint8_t tid, uint16_t ssn) { struct iwn_node *wn = (struct iwn_node *)ni; int qid = IWN4965_FIRST_AGG_TXQUEUE + tid; uint16_t idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn); /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_CHGACT); /* Assign RA/TID translation to the queue. */ iwn_mem_write_2(sc, sc->sched_base + IWN4965_SCHED_TRANS_TBL(qid), wn->id << 4 | tid); /* Enable chain-building mode for the queue. */ iwn_prph_setbits(sc, IWN4965_SCHED_QCHAIN_SEL, 1 << qid); /* Set starting sequence number from the ADDBA request. */ sc->txq[qid].cur = sc->txq[qid].read = idx; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | idx); iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), ssn); /* Set scheduler window size. */ iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid), IWN_SCHED_WINSZ); /* Set scheduler frame limit. */ iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid) + 4, IWN_SCHED_LIMIT << 16); /* Enable interrupts for the queue. */ iwn_prph_setbits(sc, IWN4965_SCHED_INTR_MASK, 1 << qid); /* Mark the queue as active. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_ACTIVE | IWN4965_TXQ_STATUS_AGGR_ENA | iwn_tid2fifo[tid] << 1); } void ItlIwn:: iwn4965_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn) { int qid = IWN4965_FIRST_AGG_TXQUEUE + tid; uint16_t idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn); /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_CHGACT); /* Set starting sequence number from the ADDBA request. */ sc->txq[qid].cur = sc->txq[qid].read = idx; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | idx); iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), ssn); /* Disable interrupts for the queue. */ iwn_prph_clrbits(sc, IWN4965_SCHED_INTR_MASK, 1 << qid); /* Mark the queue as inactive. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid] << 1); } void ItlIwn:: iwn5000_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, uint8_t tid, uint16_t ssn) { int qid = IWN5000_FIRST_AGG_TXQUEUE + tid; int idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn); struct iwn_node *wn = (struct iwn_node *)ni; /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_CHGACT); /* Assign RA/TID translation to the queue. */ iwn_mem_write_2(sc, sc->sched_base + IWN5000_SCHED_TRANS_TBL(qid), wn->id << 4 | tid); /* Enable chain-building mode for the queue. */ iwn_prph_setbits(sc, IWN5000_SCHED_QCHAIN_SEL, 1 << qid); /* Enable aggregation for the queue. */ iwn_prph_setbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid); /* Set starting sequence number from the ADDBA request. */ sc->txq[qid].cur = sc->txq[qid].read = idx; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | idx); iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), ssn); /* Set scheduler window size and frame limit. */ iwn_mem_write(sc, sc->sched_base + IWN5000_SCHED_QUEUE_OFFSET(qid) + 4, IWN_SCHED_LIMIT << 16 | IWN_SCHED_WINSZ); /* Enable interrupts for the queue. */ iwn_prph_setbits(sc, IWN5000_SCHED_INTR_MASK, 1 << qid); /* Mark the queue as active. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_ACTIVE | iwn_tid2fifo[tid]); } void ItlIwn:: iwn5000_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn) { int qid = IWN5000_FIRST_AGG_TXQUEUE + tid; int idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn); /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_CHGACT); /* Disable aggregation for the queue. */ iwn_prph_clrbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid); /* Set starting sequence number from the ADDBA request. */ sc->txq[qid].cur = sc->txq[qid].read = idx; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | idx); iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), ssn); /* Disable interrupts for the queue. */ iwn_prph_clrbits(sc, IWN5000_SCHED_INTR_MASK, 1 << qid); /* Mark the queue as inactive. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid]); } /* * Query calibration tables from the initialization firmware. We do this * only once at first boot. Called from a process context. */ int ItlIwn:: iwn5000_query_calibration(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn5000_calib_config cmd; int error; memset(&cmd, 0, sizeof cmd); cmd.ucode.once.enable = 0xffffffff; cmd.ucode.once.start = 0xffffffff; cmd.ucode.once.send = 0xffffffff; cmd.ucode.flags = 0xffffffff; DPRINTF(("sending calibration query\n")); error = that->iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0); if (error != 0) return error; /* Wait at most two seconds for calibration to complete. */ if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) error = that->tsleep_nsec(sc, PCATCH, "iwncal", SEC_TO_NSEC(2)); return error; } /* * Send calibration results to the runtime firmware. These results were * obtained on first boot from the initialization firmware. */ int ItlIwn:: iwn5000_send_calibration(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); int idx, error; for (idx = 0; idx < 5; idx++) { if (sc->calibcmd[idx].buf == NULL) continue; /* No results available. */ DPRINTF(("send calibration result idx=%d len=%d\n", idx, sc->calibcmd[idx].len)); error = that->iwn_cmd(sc, IWN_CMD_PHY_CALIB, sc->calibcmd[idx].buf, sc->calibcmd[idx].len, 0); if (error != 0) { XYLog("%s: could not send calibration result\n", sc->sc_dev.dv_xname); return error; } } return 0; } int ItlIwn:: iwn5000_send_wimax_coex(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn5000_wimax_coex wimax; #ifdef notyet if (sc->hw_type == IWN_HW_REV_TYPE_6050) { /* Enable WiMAX coexistence for combo adapters. */ wimax.flags = IWN_WIMAX_COEX_ASSOC_WA_UNMASK | IWN_WIMAX_COEX_UNASSOC_WA_UNMASK | IWN_WIMAX_COEX_STA_TABLE_VALID | IWN_WIMAX_COEX_ENABLE; memcpy(wimax.events, iwn6050_wimax_events, sizeof iwn6050_wimax_events); } else #endif { /* Disable WiMAX coexistence. */ wimax.flags = 0; memset(wimax.events, 0, sizeof wimax.events); } DPRINTF(("Configuring WiMAX coexistence\n")); return that->iwn_cmd(sc, IWN5000_CMD_WIMAX_COEX, &wimax, sizeof wimax, 0); } int ItlIwn:: iwn5000_crystal_calib(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn5000_phy_calib_crystal cmd; memset(&cmd, 0, sizeof cmd); cmd.code = IWN5000_PHY_CALIB_CRYSTAL; cmd.ngroups = 1; cmd.isvalid = 1; cmd.cap_pin[0] = letoh32(sc->eeprom_crystal) & 0xff; cmd.cap_pin[1] = (letoh32(sc->eeprom_crystal) >> 16) & 0xff; DPRINTF(("sending crystal calibration %d, %d\n", cmd.cap_pin[0], cmd.cap_pin[1])); return that->iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); } int ItlIwn:: iwn6000_temp_offset_calib(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn6000_phy_calib_temp_offset cmd; memset(&cmd, 0, sizeof cmd); cmd.code = IWN6000_PHY_CALIB_TEMP_OFFSET; cmd.ngroups = 1; cmd.isvalid = 1; if (sc->eeprom_temp != 0) cmd.offset = htole16(sc->eeprom_temp); else cmd.offset = htole16(IWN_DEFAULT_TEMP_OFFSET); DPRINTF(("setting radio sensor offset to %d\n", letoh16(cmd.offset))); return that->iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); } int ItlIwn:: iwn2000_temp_offset_calib(struct iwn_softc *sc) { ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn2000_phy_calib_temp_offset cmd; memset(&cmd, 0, sizeof cmd); cmd.code = IWN2000_PHY_CALIB_TEMP_OFFSET; cmd.ngroups = 1; cmd.isvalid = 1; if (sc->eeprom_rawtemp != 0) { cmd.offset_low = htole16(sc->eeprom_rawtemp); cmd.offset_high = htole16(sc->eeprom_temp); } else { cmd.offset_low = htole16(IWN_DEFAULT_TEMP_OFFSET); cmd.offset_high = htole16(IWN_DEFAULT_TEMP_OFFSET); } cmd.burnt_voltage_ref = htole16(sc->eeprom_voltage); DPRINTF(("setting radio sensor offset to %d:%d, voltage to %d\n", letoh16(cmd.offset_low), letoh16(cmd.offset_high), letoh16(cmd.burnt_voltage_ref))); return that->iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); } /* * This function is called after the runtime firmware notifies us of its * readiness (called in a process context). */ int ItlIwn:: iwn4965_post_alive(struct iwn_softc *sc) { XYLog("%s\n", __FUNCTION__); int error, qid; if ((error = iwn_nic_lock(sc)) != 0) return error; /* Clear TX scheduler state in SRAM. */ sc->sched_base = iwn_prph_read(sc, IWN_SCHED_SRAM_ADDR); iwn_mem_set_region_4(sc, sc->sched_base + IWN4965_SCHED_CTX_OFF, 0, IWN4965_SCHED_CTX_LEN / sizeof (uint32_t)); /* Set physical address of TX scheduler rings (1KB aligned). */ iwn_prph_write(sc, IWN4965_SCHED_DRAM_ADDR, sc->sched_dma.paddr >> 10); IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY); /* Disable chain mode for all our 16 queues. */ iwn_prph_write(sc, IWN4965_SCHED_QCHAIN_SEL, 0); for (qid = 0; qid < IWN4965_NTXQUEUES; qid++) { iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), 0); IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | 0); /* Set scheduler window size. */ iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid), IWN_SCHED_WINSZ); /* Set scheduler frame limit. */ iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid) + 4, IWN_SCHED_LIMIT << 16); } /* Enable interrupts for all our 16 queues. */ iwn_prph_write(sc, IWN4965_SCHED_INTR_MASK, 0xffff); /* Identify TX FIFO rings (0-7). */ iwn_prph_write(sc, IWN4965_SCHED_TXFACT, 0xff); /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */ for (qid = 0; qid < 7; qid++) { static uint8_t qid2fifo[] = { 3, 2, 1, 0, 4, 5, 6 }; iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_ACTIVE | qid2fifo[qid] << 1); } iwn_nic_unlock(sc); return 0; } /* * This function is called after the initialization or runtime firmware * notifies us of its readiness (called in a process context). */ int ItlIwn:: iwn5000_post_alive(struct iwn_softc *sc) { XYLog("%s\n", __FUNCTION__); ItlIwn *that = container_of(sc, ItlIwn, com); int error, qid; /* Switch to using ICT interrupt mode. */ that->iwn5000_ict_reset(sc); if ((error = iwn_nic_lock(sc)) != 0) return error; /* Clear TX scheduler state in SRAM. */ sc->sched_base = iwn_prph_read(sc, IWN_SCHED_SRAM_ADDR); iwn_mem_set_region_4(sc, sc->sched_base + IWN5000_SCHED_CTX_OFF, 0, IWN5000_SCHED_CTX_LEN / sizeof (uint32_t)); /* Set physical address of TX scheduler rings (1KB aligned). */ iwn_prph_write(sc, IWN5000_SCHED_DRAM_ADDR, sc->sched_dma.paddr >> 10); /* Disable scheduler chain extension (enabled by default in HW). */ iwn_prph_write(sc, IWN5000_SCHED_CHAINEXT_EN, 0); IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY); /* Enable chain mode for all queues, except command queue. */ iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffef); iwn_prph_write(sc, IWN5000_SCHED_AGGR_SEL, 0); for (qid = 0; qid < IWN5000_NTXQUEUES; qid++) { iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), 0); IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | 0); iwn_mem_write(sc, sc->sched_base + IWN5000_SCHED_QUEUE_OFFSET(qid), 0); /* Set scheduler window size and frame limit. */ iwn_mem_write(sc, sc->sched_base + IWN5000_SCHED_QUEUE_OFFSET(qid) + 4, IWN_SCHED_LIMIT << 16 | IWN_SCHED_WINSZ); } /* Enable interrupts for all our 20 queues. */ iwn_prph_write(sc, IWN5000_SCHED_INTR_MASK, 0xfffff); /* Identify TX FIFO rings (0-7). */ iwn_prph_write(sc, IWN5000_SCHED_TXFACT, 0xff); /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */ for (qid = 0; qid < 7; qid++) { static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 }; iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]); } iwn_nic_unlock(sc); /* Configure WiMAX coexistence for combo adapters. */ error = iwn5000_send_wimax_coex(sc); if (error != 0) { XYLog("%s: could not configure WiMAX coexistence\n", sc->sc_dev.dv_xname); return error; } if (sc->hw_type != IWN_HW_REV_TYPE_5150) { /* Perform crystal calibration. */ error = iwn5000_crystal_calib(sc); if (error != 0) { XYLog("%s: crystal calibration failed\n", sc->sc_dev.dv_xname); return error; } } if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) { /* Query calibration from the initialization firmware. */ if ((error = iwn5000_query_calibration(sc)) != 0) { XYLog("%s: could not query calibration\n", sc->sc_dev.dv_xname); return error; } /* * We have the calibration results now, reboot with the * runtime firmware (call ourselves recursively!) */ that->iwn_hw_stop(sc); error = that->iwn_hw_init(sc); } else { /* Send calibration results to runtime firmware. */ error = iwn5000_send_calibration(sc); } return error; } /* * The firmware boot code is small and is intended to be copied directly into * the NIC internal memory (no DMA transfer). */ int ItlIwn:: iwn4965_load_bootcode(struct iwn_softc *sc, const uint8_t *ucode, int size) { XYLog("%s\n", __FUNCTION__); int error, ntries; size /= sizeof (uint32_t); if ((error = iwn_nic_lock(sc)) != 0) return error; /* Copy microcode image into NIC memory. */ iwn_prph_write_region_4(sc, IWN_BSM_SRAM_BASE, (const uint32_t *)ucode, size); iwn_prph_write(sc, IWN_BSM_WR_MEM_SRC, 0); iwn_prph_write(sc, IWN_BSM_WR_MEM_DST, IWN_FW_TEXT_BASE); iwn_prph_write(sc, IWN_BSM_WR_DWCOUNT, size); /* Start boot load now. */ iwn_prph_write(sc, IWN_BSM_WR_CTRL, IWN_BSM_WR_CTRL_START); /* Wait for transfer to complete. */ for (ntries = 0; ntries < 1000; ntries++) { if (!(iwn_prph_read(sc, IWN_BSM_WR_CTRL) & IWN_BSM_WR_CTRL_START)) break; DELAY(10); } if (ntries == 1000) { XYLog("%s: could not load boot firmware\n", sc->sc_dev.dv_xname); iwn_nic_unlock(sc); return ETIMEDOUT; } /* Enable boot after power up. */ iwn_prph_write(sc, IWN_BSM_WR_CTRL, IWN_BSM_WR_CTRL_START_EN); iwn_nic_unlock(sc); return 0; } int ItlIwn:: iwn4965_load_firmware(struct iwn_softc *sc) { XYLog("%s\n", __FUNCTION__); ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_fw_info *fw = &sc->fw; struct iwn_dma_info *dma = &sc->fw_dma; int error; /* Copy initialization sections into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, fw->init.data, fw->init.datasz); // bus_dmamap_sync(sc->sc_dmat, dma->map, 0, fw->init.datasz, // BUS_DMASYNC_PREWRITE); memcpy((uint8_t *)dma->vaddr + IWN4965_FW_DATA_MAXSZ, fw->init.text, fw->init.textsz); // bus_dmamap_sync(sc->sc_dmat, dma->map, IWN4965_FW_DATA_MAXSZ, // fw->init.textsz, BUS_DMASYNC_PREWRITE); /* Tell adapter where to find initialization sections. */ if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_write(sc, IWN_BSM_DRAM_DATA_ADDR, dma->paddr >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_DATA_SIZE, fw->init.datasz); iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_ADDR, (dma->paddr + IWN4965_FW_DATA_MAXSZ) >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_SIZE, fw->init.textsz); iwn_nic_unlock(sc); /* Load firmware boot code. */ error = iwn4965_load_bootcode(sc, fw->boot.text, fw->boot.textsz); if (error != 0) { XYLog("%s: could not load boot firmware\n", sc->sc_dev.dv_xname); return error; } /* Now press "execute". */ IWN_WRITE(sc, IWN_RESET, 0); /* Wait at most one second for first alive notification. */ if ((error = that->tsleep_nsec(sc, PCATCH, "iwninit", SEC_TO_NSEC(1))) != 0) { XYLog("%s: timeout waiting for adapter to initialize\n", sc->sc_dev.dv_xname); return error; } /* Retrieve current temperature for initial TX power calibration. */ sc->rawtemp = sc->ucode_info.temp[3].chan20MHz; sc->temp = iwn4965_get_temperature(sc); /* Copy runtime sections into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, fw->main.data, fw->main.datasz); // bus_dmamap_sync(sc->sc_dmat, dma->map, 0, fw->main.datasz, // BUS_DMASYNC_PREWRITE); memcpy((uint8_t *)dma->vaddr + IWN4965_FW_DATA_MAXSZ, fw->main.text, fw->main.textsz); // bus_dmamap_sync(sc->sc_dmat, dma->map, IWN4965_FW_DATA_MAXSZ, // fw->main.textsz, BUS_DMASYNC_PREWRITE); /* Tell adapter where to find runtime sections. */ if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_write(sc, IWN_BSM_DRAM_DATA_ADDR, dma->paddr >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_DATA_SIZE, fw->main.datasz); iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_ADDR, (dma->paddr + IWN4965_FW_DATA_MAXSZ) >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_SIZE, IWN_FW_UPDATED | fw->main.textsz); iwn_nic_unlock(sc); return 0; } int ItlIwn:: iwn5000_load_firmware_section(struct iwn_softc *sc, uint32_t dst, const uint8_t *section, int size) { XYLog("%s\n", __FUNCTION__); ItlIwn *that = container_of(sc, ItlIwn, com); struct iwn_dma_info *dma = &sc->fw_dma; int error; /* Copy firmware section into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, section, size); // bus_dmamap_sync(sc->sc_dmat, dma->map, 0, size, BUS_DMASYNC_PREWRITE); if ((error = iwn_nic_lock(sc)) != 0) return error; IWN_WRITE(sc, IWN_FH_TX_CONFIG(IWN_SRVC_DMACHNL), IWN_FH_TX_CONFIG_DMA_PAUSE); IWN_WRITE(sc, IWN_FH_SRAM_ADDR(IWN_SRVC_DMACHNL), dst); IWN_WRITE(sc, IWN_FH_TFBD_CTRL0(IWN_SRVC_DMACHNL), IWN_LOADDR(dma->paddr)); IWN_WRITE(sc, IWN_FH_TFBD_CTRL1(IWN_SRVC_DMACHNL), IWN_HIADDR(dma->paddr) << 28 | size); IWN_WRITE(sc, IWN_FH_TXBUF_STATUS(IWN_SRVC_DMACHNL), IWN_FH_TXBUF_STATUS_TBNUM(1) | IWN_FH_TXBUF_STATUS_TBIDX(1) | IWN_FH_TXBUF_STATUS_TFBD_VALID); /* Kick Flow Handler to start DMA transfer. */ IWN_WRITE(sc, IWN_FH_TX_CONFIG(IWN_SRVC_DMACHNL), IWN_FH_TX_CONFIG_DMA_ENA | IWN_FH_TX_CONFIG_CIRQ_HOST_ENDTFD); iwn_nic_unlock(sc); /* Wait at most five seconds for FH DMA transfer to complete. */ return that->tsleep_nsec(sc, PCATCH, "iwninit", SEC_TO_NSEC(5)); } int ItlIwn:: iwn5000_load_firmware(struct iwn_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwn_fw_part *fw; int error; /* Load the initialization firmware on first boot only. */ fw = (sc->sc_flags & IWN_FLAG_CALIB_DONE) ? &sc->fw.main : &sc->fw.init; error = iwn5000_load_firmware_section(sc, IWN_FW_TEXT_BASE, fw->text, fw->textsz); if (error != 0) { XYLog("%s: could not load firmware %s section\n", sc->sc_dev.dv_xname, ".text"); return error; } error = iwn5000_load_firmware_section(sc, IWN_FW_DATA_BASE, fw->data, fw->datasz); if (error != 0) { XYLog("%s: could not load firmware %s section\n", sc->sc_dev.dv_xname, ".data"); return error; } /* Now press "execute". */ IWN_WRITE(sc, IWN_RESET, 0); return 0; } /* * Extract text and data sections from a legacy firmware image. */ int ItlIwn:: iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw) { const uint32_t *ptr; size_t hdrlen = 24; uint32_t rev; ptr = (const uint32_t *)fw->data; rev = letoh32(*ptr++); /* Check firmware API version. */ if (IWN_FW_API(rev) <= 1) { XYLog("%s: bad firmware, need API version >=2\n", sc->sc_dev.dv_xname); return EINVAL; } if (IWN_FW_API(rev) >= 3) { /* Skip build number (version 2 header). */ hdrlen += 4; ptr++; } if (fw->size < hdrlen) { XYLog("%s: firmware too short: %zu bytes\n", sc->sc_dev.dv_xname, fw->size); return EINVAL; } fw->main.textsz = letoh32(*ptr++); fw->main.datasz = letoh32(*ptr++); fw->init.textsz = letoh32(*ptr++); fw->init.datasz = letoh32(*ptr++); fw->boot.textsz = letoh32(*ptr++); /* Check that all firmware sections fit. */ if (fw->size < hdrlen + fw->main.textsz + fw->main.datasz + fw->init.textsz + fw->init.datasz + fw->boot.textsz) { XYLog("%s: firmware too short: %zu bytes\n", sc->sc_dev.dv_xname, fw->size); return EINVAL; } /* Get pointers to firmware sections. */ fw->main.text = (const uint8_t *)ptr; fw->main.data = fw->main.text + fw->main.textsz; fw->init.text = fw->main.data + fw->main.datasz; fw->init.data = fw->init.text + fw->init.textsz; fw->boot.text = fw->init.data + fw->init.datasz; return 0; } /* * Extract text and data sections from a TLV firmware image. */ int ItlIwn:: iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, uint16_t alt) { const struct iwn_fw_tlv_hdr *hdr; const struct iwn_fw_tlv *tlv; const uint8_t *ptr, *end; uint64_t altmask; uint32_t len; if (fw->size < sizeof (*hdr)) { XYLog("%s: firmware too short: %zu bytes\n", sc->sc_dev.dv_xname, fw->size); return EINVAL; } hdr = (const struct iwn_fw_tlv_hdr *)fw->data; if (hdr->signature != htole32(IWN_FW_SIGNATURE)) { XYLog("%s: bad firmware signature 0x%08x\n", sc->sc_dev.dv_xname, letoh32(hdr->signature)); return EINVAL; } DPRINTF(("FW: \"%.64s\", build 0x%x\n", hdr->descr, letoh32(hdr->build))); /* * Select the closest supported alternative that is less than * or equal to the specified one. */ altmask = letoh64(hdr->altmask); while (alt > 0 && !(altmask & (1ULL << alt))) alt--; /* Downgrade. */ DPRINTF(("using alternative %d\n", alt)); ptr = (const uint8_t *)(hdr + 1); end = (const uint8_t *)(fw->data + fw->size); /* Parse type-length-value fields. */ while (ptr + sizeof (*tlv) <= end) { tlv = (const struct iwn_fw_tlv *)ptr; len = letoh32(tlv->len); ptr += sizeof (*tlv); if (ptr + len > end) { XYLog("%s: firmware too short: %zu bytes\n", sc->sc_dev.dv_xname, fw->size); return EINVAL; } /* Skip other alternatives. */ if (tlv->alt != 0 && tlv->alt != htole16(alt)) goto next; switch (letoh16(tlv->type)) { case IWN_FW_TLV_MAIN_TEXT: fw->main.text = ptr; fw->main.textsz = len; break; case IWN_FW_TLV_MAIN_DATA: fw->main.data = ptr; fw->main.datasz = len; break; case IWN_FW_TLV_INIT_TEXT: fw->init.text = ptr; fw->init.textsz = len; break; case IWN_FW_TLV_INIT_DATA: fw->init.data = ptr; fw->init.datasz = len; break; case IWN_FW_TLV_BOOT_TEXT: fw->boot.text = ptr; fw->boot.textsz = len; break; case IWN_FW_TLV_ENH_SENS: if (len != 0) { XYLog("%s: TLV type %d has invalid size %u\n", sc->sc_dev.dv_xname, letoh16(tlv->type), len); goto next; } sc->sc_flags |= IWN_FLAG_ENH_SENS; break; case IWN_FW_TLV_PHY_CALIB: if (len != sizeof(uint32_t)) { XYLog("%s: TLV type %d has invalid size %u\n", sc->sc_dev.dv_xname, letoh16(tlv->type), len); goto next; } if (letoh32(*ptr) <= IWN5000_PHY_CALIB_MAX) { sc->reset_noise_gain = letoh32(*ptr); sc->noise_gain = letoh32(*ptr) + 1; } break; case IWN_FW_TLV_FLAGS: if (len < sizeof(uint32_t)) break; if (len % sizeof(uint32_t)) break; sc->tlv_feature_flags = letoh32(*ptr); DPRINTF(("feature: 0x%08x\n", sc->tlv_feature_flags)); break; default: DPRINTF(("TLV type %d not handled\n", letoh16(tlv->type))); break; } next: /* TLV fields are 32-bit aligned. */ ptr += (len + 3) & ~3; } return 0; } int ItlIwn:: iwn_read_firmware(struct iwn_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwn_fw_info *fw = &sc->fw; int error = 0; OSData *fwData = NULL; /* * Some PHY calibration commands are firmware-dependent; these * are the default values that will be overridden if * necessary. */ sc->reset_noise_gain = IWN5000_PHY_CALIB_RESET_NOISE_GAIN; sc->noise_gain = IWN5000_PHY_CALIB_NOISE_GAIN; memset(fw, 0, sizeof (*fw)); /* Read firmware image from filesystem. */ // if ((error = loadfirmware(sc->fwname, &fw->data, &fw->size)) != 0) { // XYLog("%s: could not read firmware %s (error %d)\n", // sc->sc_dev.dv_xname, sc->fwname, error); // return error; // } fwData = getFWDescByName(sc->fwname); if (fwData == NULL) { error = EINVAL; XYLog("%s resource load fail.\n", sc->fwname); return error; } fw->size = fwData->getLength() * 4; fw->data = (u_char *)malloc(fw->size, 1, 1); uncompressFirmware((u_char *)fw->data, (uint *)&fw->size, (u_char *)fwData->getBytesNoCopy(), fwData->getLength()); XYLog("load firmware %s done\n", sc->fwname); OSSafeReleaseNULL(fwData); if (fw->size < sizeof (uint32_t)) { XYLog("%s: firmware too short: %zu bytes\n", sc->sc_dev.dv_xname, fw->size); ::free(fw->data); return EINVAL; } /* Retrieve text and data sections. */ if (*(const uint32_t *)fw->data != 0) /* Legacy image. */ error = iwn_read_firmware_leg(sc, fw); else error = iwn_read_firmware_tlv(sc, fw, 1); if (error != 0) { XYLog("%s: could not read firmware sections\n", sc->sc_dev.dv_xname); ::free(fw->data); return error; } /* Make sure text and data sections fit in hardware memory. */ if (fw->main.textsz > sc->fw_text_maxsz || fw->main.datasz > sc->fw_data_maxsz || fw->init.textsz > sc->fw_text_maxsz || fw->init.datasz > sc->fw_data_maxsz || fw->boot.textsz > IWN_FW_BOOT_TEXT_MAXSZ || (fw->boot.textsz & 3) != 0) { XYLog("%s: firmware sections too large\n", sc->sc_dev.dv_xname); ::free(fw->data); return EINVAL; } /* We can proceed with loading the firmware. */ return 0; } int ItlIwn:: iwn_clock_wait(struct iwn_softc *sc) { int ntries; /* Set "initialization complete" bit. */ IWN_SETBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_INIT_DONE); /* Wait for clock stabilization. */ for (ntries = 0; ntries < 2500; ntries++) { if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_MAC_CLOCK_READY) return 0; DELAY(10); } XYLog("%s: timeout waiting for clock stabilization\n", sc->sc_dev.dv_xname); return ETIMEDOUT; } int ItlIwn:: iwn_apm_init(struct iwn_softc *sc) { pcireg_t reg; int error; /* Disable L0s exit timer (NMI bug workaround). */ IWN_SETBITS(sc, IWN_GIO_CHICKEN, IWN_GIO_CHICKEN_DIS_L0S_TIMER); /* Don't wait for ICH L0s (ICH bug workaround). */ IWN_SETBITS(sc, IWN_GIO_CHICKEN, IWN_GIO_CHICKEN_L1A_NO_L0S_RX); /* Set FH wait threshold to max (HW bug under stress workaround). */ IWN_SETBITS(sc, IWN_DBG_HPET_MEM, 0xffff0000); /* Enable HAP INTA to move adapter from L1a to L0s. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_HAP_WAKE_L1A); /* Retrieve PCIe Active State Power Management (ASPM). */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_LCSR); /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */ if (reg & PCI_PCIE_LCSR_ASPM_L1) /* L1 Entry enabled. */ IWN_SETBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); else IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); if (sc->hw_type != IWN_HW_REV_TYPE_4965 && sc->hw_type <= IWN_HW_REV_TYPE_1000) IWN_SETBITS(sc, IWN_ANA_PLL, IWN_ANA_PLL_INIT); /* Wait for clock stabilization before accessing prph. */ if ((error = iwn_clock_wait(sc)) != 0) return error; if ((error = iwn_nic_lock(sc)) != 0) return error; if (sc->hw_type == IWN_HW_REV_TYPE_4965) { /* Enable DMA and BSM (Bootstrap State Machine). */ iwn_prph_write(sc, IWN_APMG_CLK_EN, IWN_APMG_CLK_CTRL_DMA_CLK_RQT | IWN_APMG_CLK_CTRL_BSM_CLK_RQT); } else { /* Enable DMA. */ iwn_prph_write(sc, IWN_APMG_CLK_EN, IWN_APMG_CLK_CTRL_DMA_CLK_RQT); } DELAY(20); /* Disable L1-Active. */ iwn_prph_setbits(sc, IWN_APMG_PCI_STT, IWN_APMG_PCI_STT_L1A_DIS); iwn_nic_unlock(sc); return 0; } void ItlIwn:: iwn_apm_stop_master(struct iwn_softc *sc) { int ntries; /* Stop busmaster DMA activity. */ IWN_SETBITS(sc, IWN_RESET, IWN_RESET_STOP_MASTER); for (ntries = 0; ntries < 100; ntries++) { if (IWN_READ(sc, IWN_RESET) & IWN_RESET_MASTER_DISABLED) return; DELAY(10); } XYLog("%s: timeout waiting for master\n", sc->sc_dev.dv_xname); } void ItlIwn:: iwn_apm_stop(struct iwn_softc *sc) { iwn_apm_stop_master(sc); /* Reset the entire device. */ IWN_SETBITS(sc, IWN_RESET, IWN_RESET_SW); DELAY(10); /* Clear "initialization complete" bit. */ IWN_CLRBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_INIT_DONE); } int ItlIwn:: iwn4965_nic_config(struct iwn_softc *sc) { if (IWN_RFCFG_TYPE(sc->rfcfg) == 1) { /* * I don't believe this to be correct but this is what the * vendor driver is doing. Probably the bits should not be * shifted in IWN_RFCFG_*. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_RFCFG_TYPE(sc->rfcfg) | IWN_RFCFG_STEP(sc->rfcfg) | IWN_RFCFG_DASH(sc->rfcfg)); } IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_RADIO_SI | IWN_HW_IF_CONFIG_MAC_SI); return 0; } int ItlIwn:: iwn5000_nic_config(struct iwn_softc *sc) { uint32_t tmp; int error; if (IWN_RFCFG_TYPE(sc->rfcfg) < 3) { IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_RFCFG_TYPE(sc->rfcfg) | IWN_RFCFG_STEP(sc->rfcfg) | IWN_RFCFG_DASH(sc->rfcfg)); } IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_RADIO_SI | IWN_HW_IF_CONFIG_MAC_SI); if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_EARLY_PWROFF_DIS); if (sc->hw_type == IWN_HW_REV_TYPE_1000) { /* * Select first Switching Voltage Regulator (1.32V) to * solve a stability issue related to noisy DC2DC line * in the silicon of 1000 Series. */ tmp = iwn_prph_read(sc, IWN_APMG_DIGITAL_SVR); tmp &= ~IWN_APMG_DIGITAL_SVR_VOLTAGE_MASK; tmp |= IWN_APMG_DIGITAL_SVR_VOLTAGE_1_32; iwn_prph_write(sc, IWN_APMG_DIGITAL_SVR, tmp); } iwn_nic_unlock(sc); if (sc->sc_flags & IWN_FLAG_INTERNAL_PA) { /* Use internal power amplifier only. */ IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA); } if ((sc->hw_type == IWN_HW_REV_TYPE_6050 || sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) { /* Indicate that ROM calibration version is >=6. */ IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6); } if (sc->hw_type == IWN_HW_REV_TYPE_6005) IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2); if (sc->hw_type == IWN_HW_REV_TYPE_2030 || sc->hw_type == IWN_HW_REV_TYPE_2000 || sc->hw_type == IWN_HW_REV_TYPE_135 || sc->hw_type == IWN_HW_REV_TYPE_105) IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_IQ_INVERT); return 0; } /* * Take NIC ownership over Intel Active Management Technology (AMT). */ int ItlIwn:: iwn_hw_prepare(struct iwn_softc *sc) { int ntries; /* Check if hardware is ready. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_NIC_READY); for (ntries = 0; ntries < 5; ntries++) { if (IWN_READ(sc, IWN_HW_IF_CONFIG) & IWN_HW_IF_CONFIG_NIC_READY) return 0; DELAY(10); } /* Hardware not ready, force into ready state. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_PREPARE); for (ntries = 0; ntries < 15000; ntries++) { if (!(IWN_READ(sc, IWN_HW_IF_CONFIG) & IWN_HW_IF_CONFIG_PREPARE_DONE)) break; DELAY(10); } if (ntries == 15000) return ETIMEDOUT; /* Hardware should be ready now. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_NIC_READY); for (ntries = 0; ntries < 5; ntries++) { if (IWN_READ(sc, IWN_HW_IF_CONFIG) & IWN_HW_IF_CONFIG_NIC_READY) return 0; DELAY(10); } return ETIMEDOUT; } int ItlIwn:: iwn_hw_init(struct iwn_softc *sc) { struct iwn_ops *ops = &sc->ops; int error, chnl, qid; /* Clear pending interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); if ((error = iwn_apm_init(sc)) != 0) { XYLog("%s: could not power on adapter\n", sc->sc_dev.dv_xname); return error; } /* Select VMAIN power source. */ if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_clrbits(sc, IWN_APMG_PS, IWN_APMG_PS_PWR_SRC_MASK); iwn_nic_unlock(sc); /* Perform adapter-specific initialization. */ if ((error = ops->nic_config(sc)) != 0) return error; /* Initialize RX ring. */ if ((error = iwn_nic_lock(sc)) != 0) return error; IWN_WRITE(sc, IWN_FH_RX_CONFIG, 0); IWN_WRITE(sc, IWN_FH_RX_WPTR, 0); /* Set physical address of RX ring (256-byte aligned). */ IWN_WRITE(sc, IWN_FH_RX_BASE, sc->rxq.desc_dma.paddr >> 8); /* Set physical address of RX status (16-byte aligned). */ IWN_WRITE(sc, IWN_FH_STATUS_WPTR, sc->rxq.stat_dma.paddr >> 4); /* Enable RX. */ IWN_WRITE(sc, IWN_FH_RX_CONFIG, IWN_FH_RX_CONFIG_ENA | IWN_FH_RX_CONFIG_IGN_RXF_EMPTY | /* HW bug workaround */ IWN_FH_RX_CONFIG_IRQ_DST_HOST | IWN_FH_RX_CONFIG_SINGLE_FRAME | IWN_FH_RX_CONFIG_RB_TIMEOUT(0x11) | /* about 1/2 msec */ IWN_FH_RX_CONFIG_NRBD(IWN_RX_RING_COUNT_LOG)); iwn_nic_unlock(sc); IWN_WRITE(sc, IWN_FH_RX_WPTR, (IWN_RX_RING_COUNT - 1) & ~7); if ((error = iwn_nic_lock(sc)) != 0) return error; /* Initialize TX scheduler. */ iwn_prph_write(sc, sc->sched_txfact_addr, 0); /* Set physical address of "keep warm" page (16-byte aligned). */ IWN_WRITE(sc, IWN_FH_KW_ADDR, sc->kw_dma.paddr >> 4); /* Initialize TX rings. */ for (qid = 0; qid < sc->ntxqs; qid++) { struct iwn_tx_ring *txq = &sc->txq[qid]; /* Set physical address of TX ring (256-byte aligned). */ IWN_WRITE(sc, IWN_FH_CBBC_QUEUE(qid), txq->desc_dma.paddr >> 8); } iwn_nic_unlock(sc); /* Enable DMA channels. */ for (chnl = 0; chnl < sc->ndmachnls; chnl++) { IWN_WRITE(sc, IWN_FH_TX_CONFIG(chnl), IWN_FH_TX_CONFIG_DMA_ENA | IWN_FH_TX_CONFIG_DMA_CREDIT_ENA); } /* Clear "radio off" and "commands blocked" bits. */ IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_CMD_BLOCKED); /* Clear pending interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); /* Enable interrupt coalescing. */ IWN_WRITE(sc, IWN_INT_COALESCING, 512 / 8); /* Enable interrupts. */ IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); /* _Really_ make sure "radio off" bit is cleared! */ IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); /* Enable shadow registers. */ if (sc->hw_type >= IWN_HW_REV_TYPE_6000) IWN_SETBITS(sc, IWN_SHADOW_REG_CTRL, 0x800fffff); if ((error = ops->load_firmware(sc)) != 0) { XYLog("%s: could not load firmware\n", sc->sc_dev.dv_xname); return error; } /* Wait at most one second for firmware alive notification. */ if ((error = tsleep_nsec(sc, PCATCH, "iwninit", SEC_TO_NSEC(1))) != 0) { XYLog("%s: timeout waiting for adapter to initialize\n", sc->sc_dev.dv_xname); return error; } /* Do post-firmware initialization. */ return ops->post_alive(sc); } void ItlIwn:: iwn_hw_stop(struct iwn_softc *sc) { int chnl, qid, ntries; IWN_WRITE(sc, IWN_RESET, IWN_RESET_NEVO); /* Disable interrupts. */ IWN_WRITE(sc, IWN_INT_MASK, 0); IWN_WRITE(sc, IWN_INT, 0xffffffff); IWN_WRITE(sc, IWN_FH_INT, 0xffffffff); sc->sc_flags &= ~IWN_FLAG_USE_ICT; /* Make sure we no longer hold the NIC lock. */ iwn_nic_unlock(sc); /* Stop TX scheduler. */ iwn_prph_write(sc, sc->sched_txfact_addr, 0); /* Stop all DMA channels. */ if (iwn_nic_lock(sc) == 0) { for (chnl = 0; chnl < sc->ndmachnls; chnl++) { IWN_WRITE(sc, IWN_FH_TX_CONFIG(chnl), 0); for (ntries = 0; ntries < 200; ntries++) { if (IWN_READ(sc, IWN_FH_TX_STATUS) & IWN_FH_TX_STATUS_IDLE(chnl)) break; DELAY(10); } } iwn_nic_unlock(sc); } /* Stop RX ring. */ iwn_reset_rx_ring(sc, &sc->rxq); /* Reset all TX rings. */ for (qid = 0; qid < sc->ntxqs; qid++) iwn_reset_tx_ring(sc, &sc->txq[qid]); if (iwn_nic_lock(sc) == 0) { iwn_prph_write(sc, IWN_APMG_CLK_DIS, IWN_APMG_CLK_CTRL_DMA_CLK_RQT); iwn_nic_unlock(sc); } DELAY(5); /* Power OFF adapter. */ iwn_apm_stop(sc); } int ItlIwn:: iwn_init(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct iwn_softc *sc = (struct iwn_softc *)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; int error; memset(sc->bss_node_addr, 0, sizeof(sc->bss_node_addr)); sc->agg_queue_mask = 0; memset(sc->sc_tx_ba, 0, sizeof(sc->sc_tx_ba)); if ((error = iwn_hw_prepare(sc)) != 0) { XYLog("%s: hardware not ready\n", sc->sc_dev.dv_xname); goto fail; } /* Initialize interrupt mask to default value. */ sc->int_mask = IWN_INT_MASK_DEF; sc->sc_flags &= ~IWN_FLAG_USE_ICT; /* Check that the radio is not disabled by hardware switch. */ if (!(IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL)) { XYLog("%s: radio is disabled by hardware switch\n", sc->sc_dev.dv_xname); error = EPERM; /* :-) */ /* Re-enable interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); return error; } /* Read firmware images from the filesystem. */ if ((error = iwn_read_firmware(sc)) != 0) { XYLog("%s: could not read firmware\n", sc->sc_dev.dv_xname); goto fail; } /* Initialize hardware and upload firmware. */ error = iwn_hw_init(sc); ::free(sc->fw.data); if (error != 0) { XYLog("%s: could not initialize hardware\n", sc->sc_dev.dv_xname); goto fail; } /* Configure adapter now that it is ready. */ if ((error = iwn_config(sc)) != 0) { XYLog("%s: could not configure device\n", sc->sc_dev.dv_xname); goto fail; } ifq_clr_oactive(&ifp->if_snd); ifp->if_flags |= IFF_RUNNING; if (ic->ic_opmode != IEEE80211_M_MONITOR) ieee80211_begin_scan(ifp); else ieee80211_new_state(ic, IEEE80211_S_RUN, -1); return 0; fail: iwn_stop(ifp); return error; } void ItlIwn:: iwn_stop(struct _ifnet *ifp) { struct iwn_softc *sc = (struct iwn_softc *)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; timeout_del(&sc->calib_to); ifp->if_timer = sc->sc_tx_timer = 0; ifp->if_flags &= ~IFF_RUNNING; ifq_clr_oactive(&ifp->if_snd); ieee80211_new_state(ic, IEEE80211_S_INIT, -1); /* Power OFF hardware. */ iwn_hw_stop(sc); } ================================================ FILE: itlwm/hal_iwn/ItlIwn.hpp ================================================ /* * Copyright (C) 2020 pigworlds * * 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. */ /* $OpenBSD: if_iwn.c,v 1.243 2020/11/12 15:16:18 krw Exp $ */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Driver for Intel WiFi Link 4965 and 1000/5000/6000 Series 802.11 network * adapters. */ #ifndef ItlIwn_hpp #define ItlIwn_hpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include "if_iwnreg.h" #include "if_iwnvar.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include class ItlIwn : public ItlHalService, ItlDriverInfo, ItlDriverController { OSDeclareDefaultStructors(ItlIwn) public: //kext void free() override; virtual bool attach(IOPCIDevice *device) override; virtual void detach(IOPCIDevice *device) override; IOReturn enable(IONetworkInterface *netif) override; IOReturn disable(IONetworkInterface *netif) override; virtual struct ieee80211com *get80211Controller() override; static bool intrFilter(OSObject *object, IOFilterInterruptEventSource *src); static IOReturn _iwn_start_task(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); virtual ItlDriverInfo *getDriverInfo() override; virtual ItlDriverController *getDriverController() override; //driver info virtual const char *getFirmwareVersion() override; virtual int16_t getBSSNoise() override; virtual bool is5GBandSupport() override; virtual int getTxNSS() override; virtual const char *getFirmwareName() override; virtual UInt32 supportedFeatures() override; virtual const char *getFirmwareCountryCode() override; virtual uint32_t getTxQueueSize() override; //driver controller virtual void clearScanningFlags() override; virtual IOReturn setMulticastList(IOEthernetAddress *addr, int count) override; void releaseAll(); void joinSSID(const char *ssid, const char *pwd); //utils static void *mallocarray(size_t, size_t, int, int); static int iwn_match(struct IOPCIDevice *device); bool iwn_attach(struct iwn_softc *sc, struct pci_attach_args *pa); int iwn4965_attach(struct iwn_softc *, pci_product_id_t); int iwn5000_attach(struct iwn_softc *, pci_product_id_t); #if NBPFILTER > 0 void iwn_radiotap_attach(struct iwn_softc *); #endif int iwn_activate(struct iwn_softc *sc, int); void iwn_wakeup(struct iwn_softc *); static void iwn_init_task(void *); int iwn_eeprom_lock(struct iwn_softc *); int iwn_init_otprom(struct iwn_softc *); int iwn_read_prom_data(struct iwn_softc *, uint32_t, void *, int); int iwn_dma_contig_alloc(bus_dma_tag_t, struct iwn_dma_info *, void **, bus_size_t, bus_size_t); void iwn_dma_contig_free(struct iwn_dma_info *); int iwn_alloc_sched(struct iwn_softc *); void iwn_free_sched(struct iwn_softc *); int iwn_alloc_kw(struct iwn_softc *); void iwn_free_kw(struct iwn_softc *); int iwn_alloc_ict(struct iwn_softc *); void iwn_free_ict(struct iwn_softc *); int iwn_alloc_fwmem(struct iwn_softc *); void iwn_free_fwmem(struct iwn_softc *); int iwn_alloc_rx_ring(struct iwn_softc *, struct iwn_rx_ring *); void iwn_reset_rx_ring(struct iwn_softc *, struct iwn_rx_ring *); void iwn_free_rx_ring(struct iwn_softc *, struct iwn_rx_ring *); int iwn_alloc_tx_ring(struct iwn_softc *, struct iwn_tx_ring *, int); void iwn_reset_tx_ring(struct iwn_softc *, struct iwn_tx_ring *); void iwn_free_tx_ring(struct iwn_softc *, struct iwn_tx_ring *); void iwn5000_ict_reset(struct iwn_softc *); int iwn_read_eeprom(struct iwn_softc *); static void iwn4965_read_eeprom(struct iwn_softc *); void iwn4965_print_power_group(struct iwn_softc *, int); static void iwn5000_read_eeprom(struct iwn_softc *); void iwn_read_eeprom_channels(struct iwn_softc *, int, uint32_t); void iwn_read_eeprom_enhinfo(struct iwn_softc *); static struct ieee80211_node *iwn_node_alloc(struct ieee80211com *); static void iwn_newassoc(struct ieee80211com *, struct ieee80211_node *, int); int iwn_media_change(struct _ifnet *); static int iwn_newstate(struct ieee80211com *, enum ieee80211_state, int); static void iwn_iter_func(void *, struct ieee80211_node *); static void iwn_calib_timeout(void *); int iwn_ccmp_decap(struct iwn_softc *, mbuf_t, struct ieee80211_node *); void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *, struct mbuf_list *); void iwn_ra_choose(struct iwn_softc *, struct ieee80211_node *); void iwn_ampdu_rate_control(struct iwn_softc *, struct ieee80211_node *, struct iwn_tx_ring *, uint16_t, uint16_t); void iwn_ht_single_rate_control(struct iwn_softc *, struct ieee80211_node *, uint8_t, uint8_t, uint8_t, int); void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); void iwn5000_rx_calib_results(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); void iwn_ampdu_txq_advance(struct iwn_softc *, struct iwn_tx_ring *, int, int); void iwn_ampdu_tx_done(struct iwn_softc *, struct iwn_tx_ring *, struct iwn_rx_desc *, uint16_t, uint8_t, uint8_t, uint8_t, int, uint32_t, struct iwn_txagg_status *); static void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); void iwn_tx_done_free_txdata(struct iwn_softc *, struct iwn_tx_data *); void iwn_clear_oactive(struct iwn_softc *, struct iwn_tx_ring *); void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, uint8_t, uint8_t, uint8_t, int, int, uint16_t); void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *); void iwn_notif_intr(struct iwn_softc *); void iwn_wakeup_intr(struct iwn_softc *); void iwn_fatal_intr(struct iwn_softc *); static int iwn_intr(OSObject *object, IOInterruptEventSource* sender, int count); static void iwn4965_update_sched(struct iwn_softc *, int, int, uint8_t, uint16_t); static void iwn4965_reset_sched(struct iwn_softc *, int, int); static void iwn5000_update_sched(struct iwn_softc *, int, int, uint8_t, uint16_t); static void iwn5000_reset_sched(struct iwn_softc *, int, int); int iwn_tx(struct iwn_softc *, mbuf_t, struct ieee80211_node *); int iwn_rval2ridx(int); static void iwn_start(struct _ifnet *); static void iwn_watchdog(struct _ifnet *); static int iwn_ioctl(struct _ifnet *, u_long, caddr_t); int iwn_cmd(struct iwn_softc *, int, const void *, int, int); static int iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *, int); static int iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *, int); int iwn_set_link_quality(struct iwn_softc *, struct ieee80211_node *); int iwn_add_broadcast_node(struct iwn_softc *, int, int); static void iwn_updateedca(struct ieee80211com *); void iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t); int iwn_set_critical_temp(struct iwn_softc *); int iwn_set_timing(struct iwn_softc *, struct ieee80211_node *); static void iwn4965_power_calibration(struct iwn_softc *, int); static int iwn4965_set_txpower(struct iwn_softc *, int); static int iwn5000_set_txpower(struct iwn_softc *, int); static int iwn4965_get_rssi(const struct iwn_rx_stat *); static int iwn5000_get_rssi(const struct iwn_rx_stat *); int iwn_get_noise(const struct iwn_rx_general_stats *); static int iwn4965_get_temperature(struct iwn_softc *); static int iwn5000_get_temperature(struct iwn_softc *); int iwn_init_sensitivity(struct iwn_softc *); void iwn_collect_noise(struct iwn_softc *, const struct iwn_rx_general_stats *); static int iwn4965_init_gains(struct iwn_softc *); static int iwn5000_init_gains(struct iwn_softc *); static int iwn4965_set_gains(struct iwn_softc *); static int iwn5000_set_gains(struct iwn_softc *); void iwn_tune_sensitivity(struct iwn_softc *, const struct iwn_rx_stats *); int iwn_send_sensitivity(struct iwn_softc *); int iwn_set_pslevel(struct iwn_softc *, int, int, int); int iwn_send_temperature_offset(struct iwn_softc *); int iwn_send_btcoex(struct iwn_softc *); int iwn_send_advanced_btcoex(struct iwn_softc *); int iwn5000_runtime_calib(struct iwn_softc *); int iwn_config(struct iwn_softc *); uint16_t iwn_get_active_dwell_time(struct iwn_softc *, uint16_t, uint8_t); uint16_t iwn_limit_dwell(struct iwn_softc *, uint16_t); uint16_t iwn_get_passive_dwell_time(struct iwn_softc *, uint16_t); int iwn_scan(struct iwn_softc *, uint16_t, int); void iwn_scan_abort(struct iwn_softc *); static int iwn_bgscan(struct ieee80211com *); void iwn_rxon_configure_ht40(struct ieee80211com *, struct ieee80211_node *); int iwn_rxon_ht40_enabled(struct iwn_softc *); int iwn_auth(struct iwn_softc *, int); int iwn_run(struct iwn_softc *); static int iwn_set_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); static void iwn_delete_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); static void iwn_updateprot(struct ieee80211com *); static void iwn_updateslot(struct ieee80211com *); void iwn_update_rxon_restore_power(struct iwn_softc *); static void iwn5000_update_rxon(struct iwn_softc *); static void iwn4965_update_rxon(struct iwn_softc *); static int iwn_ampdu_rx_start(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwn_ampdu_rx_stop(struct ieee80211com *, struct ieee80211_node *, uint8_t); static int iwn_ampdu_tx_start(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwn_ampdu_tx_stop(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwn4965_ampdu_tx_start(struct iwn_softc *, struct ieee80211_node *, uint8_t, uint16_t); static void iwn4965_ampdu_tx_stop(struct iwn_softc *, uint8_t, uint16_t); static void iwn5000_ampdu_tx_start(struct iwn_softc *, struct ieee80211_node *, uint8_t, uint16_t); static void iwn5000_ampdu_tx_stop(struct iwn_softc *, uint8_t, uint16_t); static void iwn_update_chw(struct ieee80211com *); static int iwn5000_query_calibration(struct iwn_softc *); static int iwn5000_send_calibration(struct iwn_softc *); static int iwn5000_send_wimax_coex(struct iwn_softc *); static int iwn5000_crystal_calib(struct iwn_softc *); static int iwn6000_temp_offset_calib(struct iwn_softc *); static int iwn2000_temp_offset_calib(struct iwn_softc *); static int iwn4965_post_alive(struct iwn_softc *); static int iwn5000_post_alive(struct iwn_softc *); static int iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *, int); static int iwn4965_load_firmware(struct iwn_softc *); static int iwn5000_load_firmware_section(struct iwn_softc *, uint32_t, const uint8_t *, int); static int iwn5000_load_firmware(struct iwn_softc *); int iwn_read_firmware_leg(struct iwn_softc *, struct iwn_fw_info *); int iwn_read_firmware_tlv(struct iwn_softc *, struct iwn_fw_info *, uint16_t); int iwn_read_firmware(struct iwn_softc *); int iwn_clock_wait(struct iwn_softc *); int iwn_apm_init(struct iwn_softc *); void iwn_apm_stop_master(struct iwn_softc *); void iwn_apm_stop(struct iwn_softc *); static int iwn4965_nic_config(struct iwn_softc *); static int iwn5000_nic_config(struct iwn_softc *); int iwn_hw_prepare(struct iwn_softc *); int iwn_hw_init(struct iwn_softc *); void iwn_hw_stop(struct iwn_softc *); int iwn_init(struct _ifnet *); void iwn_stop(struct _ifnet *); public: IOInterruptEventSource* fInterrupt; struct pci_attach_args pci; struct iwn_softc com; }; #endif ================================================ FILE: itlwm/hal_iwn/if_iwnreg.h ================================================ /* * Copyright (C) 2020 pigworlds * * 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. */ /* $OpenBSD: if_iwnreg.h,v 1.59 2021/11/12 11:41:04 stsp Exp */ /*- * Copyright (c) 2007, 2008 * Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define IWN_TX_RING_COUNT 256 #define IWN_TX_RING_LOMARK 192 #define IWN_TX_RING_HIMARK 224 #define IWN_RX_RING_COUNT_LOG 6 #define IWN_RX_RING_COUNT (1 << IWN_RX_RING_COUNT_LOG) #define IWN4965_NTXQUEUES 16 #define IWN4965_FIRST_AGG_TXQUEUE 7 #define IWN5000_NTXQUEUES 20 #define IWN5000_FIRST_AGG_TXQUEUE 10 #define IWN4965_NDMACHNLS 7 #define IWN5000_NDMACHNLS 8 #define IWN_SRVC_DMACHNL 9 #define IWN_ICT_SIZE 4096 #define IWN_ICT_COUNT (IWN_ICT_SIZE / sizeof (uint32_t)) /* Maximum number of DMA segments for TX. */ #define IWN_MAX_SCATTER 20 /* RX buffers must be large enough to hold a full 4K A-MPDU. */ #define IWN_RBUF_SIZE (4 * 1024) #if defined(__LP64__) /* HW supports 36-bit DMA addresses. */ #define IWN_LOADDR(paddr) ((uint32_t)(paddr)) #define IWN_HIADDR(paddr) (((paddr) >> 32) & 0xf) #else #define IWN_LOADDR(paddr) (paddr) #define IWN_HIADDR(paddr) (0) #endif /* Base Address Register. */ #define IWN_PCI_BAR0 PCI_MAPREG_START /* * Control and status registers. */ #define IWN_HW_IF_CONFIG 0x000 #define IWN_INT_COALESCING 0x004 #define IWN_INT_PERIODIC 0x005 /* use IWN_WRITE_1 */ #define IWN_INT 0x008 #define IWN_INT_MASK 0x00c #define IWN_FH_INT 0x010 #define IWN_RESET 0x020 #define IWN_GP_CNTRL 0x024 #define IWN_HW_REV 0x028 #define IWN_EEPROM 0x02c #define IWN_EEPROM_GP 0x030 #define IWN_OTP_GP 0x034 #define IWN_GIO 0x03c #define IWN_GP_DRIVER 0x050 #define IWN_UCODE_GP1_CLR 0x05c #define IWN_LED 0x094 #define IWN_DRAM_INT_TBL 0x0a0 #define IWN_SHADOW_REG_CTRL 0x0a8 #define IWN_GIO_CHICKEN 0x100 #define IWN_ANA_PLL 0x20c #define IWN_HW_REV_WA 0x22c #define IWN_DBG_HPET_MEM 0x240 #define IWN_DBG_LINK_PWR_MGMT 0x250 #define IWN_MEM_RADDR 0x40c #define IWN_MEM_WADDR 0x410 #define IWN_MEM_WDATA 0x418 #define IWN_MEM_RDATA 0x41c #define IWN_PRPH_WADDR 0x444 #define IWN_PRPH_RADDR 0x448 #define IWN_PRPH_WDATA 0x44c #define IWN_PRPH_RDATA 0x450 #define IWN_HBUS_TARG_WRPTR 0x460 /* * Flow-Handler registers. */ #define IWN_FH_TFBD_CTRL0(qid) (0x1900 + (qid) * 8) #define IWN_FH_TFBD_CTRL1(qid) (0x1904 + (qid) * 8) #define IWN_FH_KW_ADDR 0x197c #define IWN_FH_SRAM_ADDR(qid) (0x19a4 + (qid) * 4) #define IWN_FH_CBBC_QUEUE(qid) (0x19d0 + (qid) * 4) #define IWN_FH_STATUS_WPTR 0x1bc0 #define IWN_FH_RX_BASE 0x1bc4 #define IWN_FH_RX_WPTR 0x1bc8 #define IWN_FH_RX_CONFIG 0x1c00 #define IWN_FH_RX_STATUS 0x1c44 #define IWN_FH_TX_CONFIG(qid) (0x1d00 + (qid) * 32) #define IWN_FH_TXBUF_STATUS(qid) (0x1d08 + (qid) * 32) #define IWN_FH_TX_CHICKEN 0x1e98 #define IWN_FH_TX_STATUS 0x1eb0 /* * TX scheduler registers. */ #define IWN_SCHED_BASE 0xa02c00 #define IWN_SCHED_SRAM_ADDR (IWN_SCHED_BASE + 0x000) #define IWN5000_SCHED_DRAM_ADDR (IWN_SCHED_BASE + 0x008) #define IWN4965_SCHED_DRAM_ADDR (IWN_SCHED_BASE + 0x010) #define IWN5000_SCHED_TXFACT (IWN_SCHED_BASE + 0x010) #define IWN4965_SCHED_TXFACT (IWN_SCHED_BASE + 0x01c) #define IWN4965_SCHED_QUEUE_RDPTR(qid) (IWN_SCHED_BASE + 0x064 + (qid) * 4) #define IWN5000_SCHED_QUEUE_RDPTR(qid) (IWN_SCHED_BASE + 0x068 + (qid) * 4) #define IWN4965_SCHED_QCHAIN_SEL (IWN_SCHED_BASE + 0x0d0) #define IWN4965_SCHED_INTR_MASK (IWN_SCHED_BASE + 0x0e4) #define IWN5000_SCHED_QCHAIN_SEL (IWN_SCHED_BASE + 0x0e8) #define IWN4965_SCHED_QUEUE_STATUS(qid) (IWN_SCHED_BASE + 0x104 + (qid) * 4) #define IWN5000_SCHED_INTR_MASK (IWN_SCHED_BASE + 0x108) #define IWN5000_SCHED_QUEUE_STATUS(qid) (IWN_SCHED_BASE + 0x10c + (qid) * 4) #define IWN5000_SCHED_CHAINEXT_EN (IWN_SCHED_BASE + 0x244) #define IWN5000_SCHED_AGGR_SEL (IWN_SCHED_BASE + 0x248) /* * Offsets in TX scheduler's SRAM. */ #define IWN4965_SCHED_CTX_OFF 0x380 #define IWN4965_SCHED_CTX_LEN 416 #define IWN4965_SCHED_QUEUE_OFFSET(qid) (0x380 + (qid) * 8) #define IWN4965_SCHED_TRANS_TBL(qid) (0x500 + (qid) * 2) #define IWN5000_SCHED_CTX_OFF 0x600 #define IWN5000_SCHED_CTX_LEN 520 #define IWN5000_SCHED_QUEUE_OFFSET(qid) (0x600 + (qid) * 8) #define IWN5000_SCHED_TRANS_TBL(qid) (0x7e0 + (qid) * 2) /* * NIC internal memory offsets. */ #define IWN_APMG_CLK_CTRL 0x3000 #define IWN_APMG_CLK_EN 0x3004 #define IWN_APMG_CLK_DIS 0x3008 #define IWN_APMG_PS 0x300c #define IWN_APMG_DIGITAL_SVR 0x3058 #define IWN_APMG_ANALOG_SVR 0x306c #define IWN_APMG_PCI_STT 0x3010 #define IWN_BSM_WR_CTRL 0x3400 #define IWN_BSM_WR_MEM_SRC 0x3404 #define IWN_BSM_WR_MEM_DST 0x3408 #define IWN_BSM_WR_DWCOUNT 0x340c #define IWN_BSM_DRAM_TEXT_ADDR 0x3490 #define IWN_BSM_DRAM_TEXT_SIZE 0x3494 #define IWN_BSM_DRAM_DATA_ADDR 0x3498 #define IWN_BSM_DRAM_DATA_SIZE 0x349c #define IWN_BSM_SRAM_BASE 0x3800 /* Possible flags for register IWN_HW_IF_CONFIG. */ #define IWN_HW_IF_CONFIG_4965_R (1 << 4) #define IWN_HW_IF_CONFIG_MAC_SI (1 << 8) #define IWN_HW_IF_CONFIG_RADIO_SI (1 << 9) #define IWN_HW_IF_CONFIG_EEPROM_LOCKED (1 << 21) #define IWN_HW_IF_CONFIG_NIC_READY (1 << 22) #define IWN_HW_IF_CONFIG_HAP_WAKE_L1A (1 << 23) #define IWN_HW_IF_CONFIG_PREPARE_DONE (1 << 25) #define IWN_HW_IF_CONFIG_PREPARE (1 << 27) /* Possible values for register IWN_INT_PERIODIC. */ #define IWN_INT_PERIODIC_DIS 0x00 #define IWN_INT_PERIODIC_ENA 0xff /* Possible flags for registers IWN_PRPH_RADDR/IWN_PRPH_WADDR. */ #define IWN_PRPH_DWORD ((sizeof (uint32_t) - 1) << 24) /* Possible values for IWN_BSM_WR_MEM_DST. */ #define IWN_FW_TEXT_BASE 0x00000000 #define IWN_FW_DATA_BASE 0x00800000 /* Possible flags for register IWN_RESET. */ #define IWN_RESET_NEVO (1U << 0) #define IWN_RESET_SW (1U << 7) #define IWN_RESET_MASTER_DISABLED (1U << 8) #define IWN_RESET_STOP_MASTER (1U << 9) #define IWN_RESET_LINK_PWR_MGMT_DIS (1U << 31) /* Possible flags for register IWN_GP_CNTRL. */ #define IWN_GP_CNTRL_MAC_ACCESS_ENA (1 << 0) #define IWN_GP_CNTRL_MAC_CLOCK_READY (1 << 0) #define IWN_GP_CNTRL_INIT_DONE (1 << 2) #define IWN_GP_CNTRL_MAC_ACCESS_REQ (1 << 3) #define IWN_GP_CNTRL_SLEEP (1 << 4) #define IWN_GP_CNTRL_RFKILL (1 << 27) /* Possible flags for register IWN_HW_REV. */ #define IWN_HW_REV_TYPE_SHIFT 4 #define IWN_HW_REV_TYPE_MASK 0x000001f0 #define IWN_HW_REV_TYPE_4965 0 #define IWN_HW_REV_TYPE_5300 2 #define IWN_HW_REV_TYPE_5350 3 #define IWN_HW_REV_TYPE_5150 4 #define IWN_HW_REV_TYPE_5100 5 #define IWN_HW_REV_TYPE_1000 6 #define IWN_HW_REV_TYPE_6000 7 #define IWN_HW_REV_TYPE_6050 8 #define IWN_HW_REV_TYPE_6005 11 #define IWN_HW_REV_TYPE_2030 12 #define IWN_HW_REV_TYPE_2000 16 #define IWN_HW_REV_TYPE_105 17 #define IWN_HW_REV_TYPE_135 18 /* Possible flags for register IWN_GIO_CHICKEN. */ #define IWN_GIO_CHICKEN_L1A_NO_L0S_RX (1 << 23) #define IWN_GIO_CHICKEN_DIS_L0S_TIMER (1 << 29) /* Possible flags for register IWN_GIO. */ #define IWN_GIO_L0S_ENA (1 << 1) /* Possible flags for register IWN_GP_DRIVER. */ #define IWN_GP_DRIVER_RADIO_3X3_HYB (0 << 0) #define IWN_GP_DRIVER_RADIO_2X2_HYB (1 << 0) #define IWN_GP_DRIVER_RADIO_2X2_IPA (2 << 0) #define IWN_GP_DRIVER_CALIB_VER6 (1 << 2) #define IWN_GP_DRIVER_6050_1X2 (1 << 3) #define IWN_GP_DRIVER_RADIO_IQ_INVERT (1 << 7) /* Possible flags for register IWN_UCODE_GP1_CLR. */ #define IWN_UCODE_GP1_RFKILL (1 << 1) #define IWN_UCODE_GP1_CMD_BLOCKED (1 << 2) #define IWN_UCODE_GP1_CTEMP_STOP_RF (1 << 3) /* Possible flags/values for register IWN_LED. */ #define IWN_LED_BSM_CTRL (1 << 5) #define IWN_LED_OFF 0x00000038 #define IWN_LED_ON 0x00000078 /* Possible flags for register IWN_DRAM_INT_TBL. */ #define IWN_DRAM_INT_TBL_WRAP_CHECK (1U << 27) #define IWN_DRAM_INT_TBL_ENABLE (1U << 31) /* Possible values for register IWN_ANA_PLL. */ #define IWN_ANA_PLL_INIT 0x00880300 /* Possible flags for register IWN_FH_RX_STATUS. */ #define IWN_FH_RX_STATUS_IDLE (1 << 24) /* Possible flags for register IWN_BSM_WR_CTRL. */ #define IWN_BSM_WR_CTRL_START_EN (1U << 30) #define IWN_BSM_WR_CTRL_START (1U << 31) /* Possible flags for register IWN_INT. */ #define IWN_INT_ALIVE (1U << 0) #define IWN_INT_WAKEUP (1U << 1) #define IWN_INT_SW_RX (1U << 3) #define IWN_INT_CT_REACHED (1U << 6) #define IWN_INT_RF_TOGGLED (1U << 7) #define IWN_INT_SW_ERR (1U << 25) #define IWN_INT_SCHED (1U << 26) #define IWN_INT_FH_TX (1U << 27) #define IWN_INT_RX_PERIODIC (1U << 28) #define IWN_INT_HW_ERR (1U << 29) #define IWN_INT_FH_RX (1U << 31) /* Shortcut. */ #define IWN_INT_MASK_DEF \ (IWN_INT_SW_ERR | IWN_INT_HW_ERR | IWN_INT_FH_TX | \ IWN_INT_FH_RX | IWN_INT_ALIVE | IWN_INT_WAKEUP | \ IWN_INT_SW_RX | IWN_INT_CT_REACHED | IWN_INT_RF_TOGGLED) /* Possible flags for register IWN_FH_INT. */ #define IWN_FH_INT_TX_CHNL(x) (1 << (x)) #define IWN_FH_INT_RX_CHNL(x) (1 << ((x) + 16)) #define IWN_FH_INT_HI_PRIOR (1 << 30) /* Shortcuts for the above. */ #define IWN_FH_INT_TX \ (IWN_FH_INT_TX_CHNL(0) | IWN_FH_INT_TX_CHNL(1)) #define IWN_FH_INT_RX \ (IWN_FH_INT_RX_CHNL(0) | IWN_FH_INT_RX_CHNL(1) | IWN_FH_INT_HI_PRIOR) /* Possible flags/values for register IWN_FH_TX_CONFIG. */ #define IWN_FH_TX_CONFIG_DMA_PAUSE 0 #define IWN_FH_TX_CONFIG_DMA_ENA (1U << 31) #define IWN_FH_TX_CONFIG_CIRQ_HOST_ENDTFD (1U << 20) /* Possible flags/values for register IWN_FH_TXBUF_STATUS. */ #define IWN_FH_TXBUF_STATUS_TBNUM(x) ((x) << 20) #define IWN_FH_TXBUF_STATUS_TBIDX(x) ((x) << 12) #define IWN_FH_TXBUF_STATUS_TFBD_VALID 3 /* Possible flags for register IWN_FH_TX_CHICKEN. */ #define IWN_FH_TX_CHICKEN_SCHED_RETRY (1 << 1) /* Possible flags for register IWN_FH_TX_STATUS. */ #define IWN_FH_TX_STATUS_IDLE(chnl) (1 << ((chnl) + 16)) /* Possible flags for register IWN_FH_RX_CONFIG. */ #define IWN_FH_RX_CONFIG_ENA (1U << 31) #define IWN_FH_RX_CONFIG_NRBD(x) ((x) << 20) #define IWN_FH_RX_CONFIG_RB_SIZE_8K (1U << 16) #define IWN_FH_RX_CONFIG_SINGLE_FRAME (1U << 15) #define IWN_FH_RX_CONFIG_IRQ_DST_HOST (1U << 12) #define IWN_FH_RX_CONFIG_RB_TIMEOUT(x) ((x) << 4) /* units 32 usec */ #define IWN_FH_RX_CONFIG_IGN_RXF_EMPTY (1U << 2) /* Possible flags for register IWN_FH_TX_CONFIG. */ #define IWN_FH_TX_CONFIG_DMA_ENA (1U << 31) #define IWN_FH_TX_CONFIG_DMA_CREDIT_ENA (1U << 3) /* Possible flags for register IWN_EEPROM. */ #define IWN_EEPROM_READ_VALID (1 << 0) #define IWN_EEPROM_CMD (1 << 1) /* Possible flags for register IWN_EEPROM_GP. */ #define IWN_EEPROM_GP_IF_OWNER 0x00000180 /* Possible flags for register IWN_OTP_GP. */ #define IWN_OTP_GP_DEV_SEL_OTP (1 << 16) #define IWN_OTP_GP_RELATIVE_ACCESS (1 << 17) #define IWN_OTP_GP_ECC_CORR_STTS (1 << 20) #define IWN_OTP_GP_ECC_UNCORR_STTS (1 << 21) /* Possible flags for register IWN_SCHED_QUEUE_STATUS. */ #define IWN4965_TXQ_STATUS_ACTIVE 0x0007fc01 #define IWN4965_TXQ_STATUS_INACTIVE 0x0007fc00 #define IWN4965_TXQ_STATUS_AGGR_ENA (1 << 5 | 1 << 8) #define IWN4965_TXQ_STATUS_CHGACT (1 << 10) #define IWN5000_TXQ_STATUS_ACTIVE 0x00ff0018 #define IWN5000_TXQ_STATUS_INACTIVE 0x00ff0010 #define IWN5000_TXQ_STATUS_CHGACT (1 << 19) /* Possible flags for registers IWN_APMG_CLK_*. */ #define IWN_APMG_CLK_CTRL_DMA_CLK_RQT (1 << 9) #define IWN_APMG_CLK_CTRL_BSM_CLK_RQT (1 << 11) /* Possible flags for register IWN_APMG_PS. */ #define IWN_APMG_PS_EARLY_PWROFF_DIS (1 << 22) #define IWN_APMG_PS_PWR_SRC(x) ((x) << 24) #define IWN_APMG_PS_PWR_SRC_VMAIN 0 #define IWN_APMG_PS_PWR_SRC_VAUX 2 #define IWN_APMG_PS_PWR_SRC_MASK IWN_APMG_PS_PWR_SRC(3) #define IWN_APMG_PS_RESET_REQ (1 << 26) /* Possible flags for register IWN_APMG_DIGITAL_SVR. */ #define IWN_APMG_DIGITAL_SVR_VOLTAGE(x) (((x) & 0xf) << 5) #define IWN_APMG_DIGITAL_SVR_VOLTAGE_MASK \ IWN_APMG_DIGITAL_SVR_VOLTAGE(0xf) #define IWN_APMG_DIGITAL_SVR_VOLTAGE_1_32 \ IWN_APMG_DIGITAL_SVR_VOLTAGE(3) /* Possible flags for IWN_APMG_PCI_STT. */ #define IWN_APMG_PCI_STT_L1A_DIS (1 << 11) /* Possible flags for register IWN_BSM_DRAM_TEXT_SIZE. */ #define IWN_FW_UPDATED (1U << 31) #define IWN_SCHED_WINSZ 64 #define IWN_SCHED_LIMIT 64 #define IWN4965_SCHED_COUNT 512 #define IWN5000_SCHED_COUNT (IWN_TX_RING_COUNT + IWN_SCHED_WINSZ) #define IWN4965_SCHEDSZ (IWN4965_NTXQUEUES * IWN4965_SCHED_COUNT * 2) #define IWN5000_SCHEDSZ (IWN5000_NTXQUEUES * IWN5000_SCHED_COUNT * 2) struct iwn_tx_desc { uint8_t reserved1[3]; uint8_t nsegs; struct { uint32_t addr; uint16_t len; } __packed segs[IWN_MAX_SCATTER]; /* Pad to 128 bytes. */ uint32_t reserved2; } __packed; struct iwn_rx_status { uint16_t closed_count; uint16_t closed_rx_count; uint16_t finished_count; uint16_t finished_rx_count; uint32_t reserved[2]; } __packed; struct iwn_rx_desc { uint32_t len; #define IWN_RX_DESC_LEN_MASK 0x00003fff #define IWN_RX_DESC_LEN_SHIFT 0 #define IWN_RX_DESC_FLAG_FLUSH_RB_REQ 0x80000000 #define IWN_RX_DESC_FLAG_IGNORE_TC 0x40000000 #define IWN_RX_DESC_FLAG_FAST_IRQ 0x20000000 uint8_t type; #define IWN_UC_READY 1 #define IWN_ADD_NODE_DONE 24 #define IWN_TX_DONE 28 #define IWN5000_CALIBRATION_RESULT 102 #define IWN5000_CALIBRATION_DONE 103 #define IWN_START_SCAN 130 #define IWN_STOP_SCAN 132 #define IWN_RX_STATISTICS 156 #define IWN_BEACON_STATISTICS 157 #define IWN_STATE_CHANGED 161 #define IWN_BEACON_MISSED 162 #define IWN_RX_PHY 192 #define IWN_MPDU_RX_DONE 193 #define IWN_RX_DONE 195 #define IWN_RX_COMPRESSED_BA 197 uint8_t flags; /* XXX iwlwifi calls this "group_id" */ uint8_t idx; uint8_t qid; } __packed; /* Possible RX status flags. */ #define IWN_RX_NO_CRC_ERR (1 << 0) #define IWN_RX_NO_OVFL_ERR (1 << 1) /* Shortcut for the above. */ #define IWN_RX_NOERROR (IWN_RX_NO_CRC_ERR | IWN_RX_NO_OVFL_ERR) #define IWN_RX_MPDU_MIC_OK (1 << 6) #define IWN_RX_CIPHER_MASK (7 << 8) #define IWN_RX_CIPHER_CCMP (2 << 8) #define IWN_RX_MPDU_DEC (1 << 11) #define IWN_RX_DECRYPT_MASK (3 << 11) #define IWN_RX_DECRYPT_OK (3 << 11) struct iwn_tx_cmd { uint8_t code; #define IWN_CMD_RXON 16 #define IWN_CMD_RXON_ASSOC 17 #define IWN_CMD_EDCA_PARAMS 19 #define IWN_CMD_TIMING 20 #define IWN_CMD_ADD_NODE 24 #define IWN_CMD_TX_DATA 28 #define IWN_CMD_LINK_QUALITY 78 #define IWN_CMD_SET_LED 72 #define IWN5000_CMD_WIMAX_COEX 90 #define IWN5000_CMD_CALIB_CONFIG 101 #define IWN_CMD_SET_POWER_MODE 119 #define IWN_CMD_SCAN 128 #define IWN_CMD_SCAN_ABORT 129 #define IWN_CMD_TXPOWER_DBM 149 #define IWN_CMD_TXPOWER 151 #define IWN5000_CMD_TX_ANT_CONFIG 152 #define IWN_CMD_BT_COEX 155 #define IWN_CMD_GET_STATISTICS 156 #define IWN_CMD_SET_CRITICAL_TEMP 164 #define IWN_CMD_SET_SENSITIVITY 168 #define IWN_CMD_PHY_CALIB 176 #define IWN_CMD_BT_COEX_PRIOTABLE 204 #define IWN_CMD_BT_COEX_PROT 205 uint8_t flags; uint8_t idx; uint8_t qid; uint8_t data[136]; } __packed; /* Antenna flags, used in various commands. */ #define IWN_ANT_A (1 << 0) #define IWN_ANT_B (1 << 1) #define IWN_ANT_C (1 << 2) /* Shortcuts. */ #define IWN_ANT_AB (IWN_ANT_A | IWN_ANT_B) #define IWN_ANT_BC (IWN_ANT_B | IWN_ANT_C) #define IWN_ANT_ABC (IWN_ANT_A | IWN_ANT_B | IWN_ANT_C) /* Structure for command IWN_CMD_RXON. */ struct iwn_rxon { uint8_t myaddr[IEEE80211_ADDR_LEN]; uint16_t reserved1; uint8_t bssid[IEEE80211_ADDR_LEN]; uint16_t reserved2; uint8_t wlap[IEEE80211_ADDR_LEN]; uint16_t reserved3; uint8_t mode; #define IWN_MODE_HOSTAP 1 #define IWN_MODE_STA 3 #define IWN_MODE_IBSS 4 #define IWN_MODE_MONITOR 6 uint8_t air; uint16_t rxchain; #define IWN_RXCHAIN_DRIVER_FORCE (1 << 0) #define IWN_RXCHAIN_VALID(x) (((x) & IWN_ANT_ABC) << 1) #define IWN_RXCHAIN_FORCE_SEL(x) (((x) & IWN_ANT_ABC) << 4) #define IWN_RXCHAIN_FORCE_MIMO_SEL(x) (((x) & IWN_ANT_ABC) << 7) #define IWN_RXCHAIN_IDLE_COUNT(x) ((x) << 10) #define IWN_RXCHAIN_MIMO_COUNT(x) ((x) << 12) #define IWN_RXCHAIN_MIMO_FORCE (1 << 14) uint8_t ofdm_mask; uint8_t cck_mask; uint16_t associd; uint32_t flags; #define IWN_RXON_24GHZ (1 << 0) #define IWN_RXON_CCK (1 << 1) #define IWN_RXON_AUTO (1 << 2) #define IWN_RXON_TGG_PROT (1 << 3) #define IWN_RXON_SHSLOT (1 << 4) #define IWN_RXON_SHPREAMBLE (1 << 5) #define IWN_RXON_NODIVERSITY (1 << 7) #define IWN_RXON_ANTENNA_A (1 << 8) #define IWN_RXON_ANTENNA_B (1 << 9) #define IWN_RXON_TSF (1 << 15) #define IWN_RXON_HT_HT40MINUS (1 << 22) #define IWN_RXON_HT_PROTMODE(x) ((x) << 23) /* 2 bits */ #define IWN_RXON_HT_CHANMODE_PURE40 (1 << 25) #define IWN_RXON_HT_CHANMODE_MIXED2040 (2 << 25) #define IWN_RXON_CTS_TO_SELF (1 << 30) uint32_t filter; #define IWN_FILTER_PROMISC (1 << 0) #define IWN_FILTER_CTL (1 << 1) #define IWN_FILTER_MULTICAST (1 << 2) #define IWN_FILTER_NODECRYPT (1 << 3) #define IWN_FILTER_BSS (1 << 5) #define IWN_FILTER_BEACON (1 << 6) uint8_t chan; uint8_t reserved4; uint8_t ht_single_mask; uint8_t ht_dual_mask; /* The following fields are for >=5000 Series only. */ uint8_t ht_triple_mask; uint8_t reserved5; uint16_t acquisition; uint16_t reserved6; } __packed; /* Structure for command IWN_CMD_RXON_ASSOC. */ struct iwn_rxon_assoc { uint32_t flags; uint32_t filter; uint8_t ofdm_mask; uint8_t cck_mask; uint16_t reserved1; uint8_t ht_single_mask; uint8_t ht_dual_mask; uint8_t ht_triple_mask; uint8_t reserved2; uint16_t rxchain; uint16_t acquisition; uint32_t reserved3; } __packed; struct iwn4965_rxon_assoc { uint32_t flags; uint32_t filter; uint8_t ofdm_mask; uint8_t cck_mask; uint8_t ht_single_mask; uint8_t ht_dual_mask; uint16_t rxchain; uint16_t reserved; }; #define IWN4965_RXONSZ (sizeof (struct iwn_rxon) - 6) #define IWN5000_RXONSZ (sizeof (struct iwn_rxon)) /* Structure for command IWN_CMD_ASSOCIATE. */ struct iwn_assoc { uint32_t flags; uint32_t filter; uint8_t ofdm_mask; uint8_t cck_mask; uint16_t reserved; } __packed; /* Structure for command IWN_CMD_EDCA_PARAMS. */ struct iwn_edca_params { uint32_t flags; #define IWN_EDCA_UPDATE (1 << 0) #define IWN_EDCA_FLG_TGN (1 << 1) #define IWN_EDCA_TXOP (1 << 4) struct { uint16_t cwmin; uint16_t cwmax; uint8_t aifsn; uint8_t reserved; uint16_t txoplimit; } __packed ac[EDCA_NUM_AC]; } __packed; /* Structure for command IWN_CMD_TIMING. */ struct iwn_cmd_timing { uint64_t tstamp; uint16_t bintval; uint16_t atim; uint32_t binitval; uint16_t lintval; uint16_t reserved; } __packed; /* Structure for command IWN_CMD_ADD_NODE. */ struct iwn_node_info { uint8_t control; #define IWN_NODE_UPDATE (1 << 0) uint8_t reserved1[3]; uint8_t macaddr[IEEE80211_ADDR_LEN]; uint16_t reserved2; uint8_t id; #define IWN_ID_BSS 0 #define IWN5000_ID_BROADCAST 15 #define IWN4965_ID_BROADCAST 31 uint8_t flags; #define IWN_FLAG_SET_KEY (1 << 0) #define IWN_FLAG_SET_DISABLE_TID (1 << 1) #define IWN_FLAG_SET_TXRATE (1 << 2) #define IWN_FLAG_SET_ADDBA (1 << 3) #define IWN_FLAG_SET_DELBA (1 << 4) uint16_t reserved3; uint16_t kflags; #define IWN_KFLAG_CCMP (1 << 1) #define IWN_KFLAG_MAP (1 << 3) #define IWN_KFLAG_KID(kid) ((kid) << 8) #define IWN_KFLAG_INVALID (1 << 11) #define IWN_KFLAG_GROUP (1 << 14) uint8_t tsc2; /* TKIP TSC2 */ uint8_t reserved4; uint16_t ttak[5]; uint8_t kid; uint8_t reserved5; uint8_t key[16]; /* The following 3 fields are for 5000 Series only. */ uint64_t tsc; uint8_t rxmic[IEEE80211_TKIP_MICLEN]; uint8_t txmic[IEEE80211_TKIP_MICLEN]; uint32_t htflags; #define IWN_AMDPU_SIZE_FACTOR(x) ((x) << 19) #define IWN_AMDPU_SIZE_FACTOR_MASK ((0x3) << 19) #define IWN_40MHZ_ENABLE (1 << 21) #define IWN_MIMO_DISABLE (1 << 22) #define IWN_AMDPU_DENSITY(x) ((x) << 23) #define IWN_AMDPU_DENSITY_MASK ((0x7) << 23) uint32_t htmask; uint16_t disable_tid; uint16_t reserved6; uint8_t addba_tid; uint8_t delba_tid; uint16_t addba_ssn; uint32_t reserved7; } __packed; struct iwn4965_node_info { uint8_t control; uint8_t reserved1[3]; uint8_t macaddr[IEEE80211_ADDR_LEN]; uint16_t reserved2; uint8_t id; uint8_t flags; uint16_t reserved3; uint16_t kflags; uint8_t tsc2; /* TKIP TSC2 */ uint8_t reserved4; uint16_t ttak[5]; uint8_t kid; uint8_t reserved5; uint8_t key[16]; uint32_t htflags; uint32_t htmask; uint16_t disable_tid; uint16_t reserved6; uint8_t addba_tid; uint8_t delba_tid; uint16_t addba_ssn; uint32_t reserved7; } __packed; #define IWN_RFLAG_MCS (1 << 0) #define IWN_RFLAG_CCK (1 << 1) #define IWN_RFLAG_GREENFIELD (1 << 2) #define IWN_RFLAG_HT40 (1 << 3) #define IWN_RFLAG_DUPLICATE (1 << 4) #define IWN_RFLAG_SGI (1 << 5) #define IWN_RFLAG_ANT(x) ((x) << 6) /* Structure for command IWN_CMD_TX_DATA. */ struct iwn_cmd_data { uint16_t len; uint16_t lnext; uint32_t flags; #define IWN_TX_NEED_PROTECTION (1 << 0) /* 5000 only */ #define IWN_TX_NEED_RTS (1 << 1) #define IWN_TX_NEED_CTS (1 << 2) #define IWN_TX_NEED_ACK (1 << 3) #define IWN_TX_LINKQ (1 << 4) #define IWN_TX_IMM_BA (1 << 6) #define IWN_TX_FULL_TXOP (1 << 7) #define IWN_TX_BT_DISABLE (1 << 12) /* bluetooth coexistence */ #define IWN_TX_AUTO_SEQ (1 << 13) #define IWN_TX_MORE_FRAG (1 << 14) #define IWN_TX_INSERT_TSTAMP (1 << 16) #define IWN_TX_NEED_PADDING (1 << 20) #define IWN_TX_AMPDU_CCMP (1 << 22) uint32_t scratch; uint8_t plcp; uint8_t rflags; uint16_t xrflags; uint8_t id; uint8_t security; #define IWN_CIPHER_WEP40 1 #define IWN_CIPHER_CCMP 2 #define IWN_CIPHER_TKIP 3 #define IWN_CIPHER_WEP104 9 uint8_t linkq; uint8_t reserved2; uint8_t key[16]; uint16_t fnext; uint16_t reserved3; uint32_t lifetime; #define IWN_LIFETIME_INFINITE 0xffffffff uint32_t loaddr; uint8_t hiaddr; uint8_t rts_ntries; uint8_t data_ntries; uint8_t tid; uint16_t timeout; uint16_t txop; } __packed; /* Structure for command IWN_CMD_LINK_QUALITY. */ #define IWN_MAX_TX_RETRIES 16 struct iwn_cmd_link_quality { uint8_t id; uint8_t reserved1; uint16_t ctl; uint8_t flags; #define IWN_LINK_QUAL_FLAGS_SET_STA_TLC_RTS (1 << 0) uint8_t mimo; uint8_t antmsk_1stream; uint8_t antmsk_2stream; uint8_t ridx[EDCA_NUM_AC]; uint16_t ampdu_limit; uint8_t ampdu_threshold; uint8_t ampdu_max; #define IWN_AMPDU_MAX_UNLIMITED 0 #define IWN_AMPDU_MAX_NO_AGG 1 #define IWN_AMPDU_MAX 63 uint32_t reserved2; struct { uint8_t plcp; uint8_t rflags; uint16_t xrflags; } __packed retry[IWN_MAX_TX_RETRIES]; uint32_t reserved3; } __packed; /* Structure for command IWN_CMD_SET_LED. */ struct iwn_cmd_led { uint32_t unit; /* multiplier (in usecs) */ uint8_t which; #define IWN_LED_ACTIVITY 1 #define IWN_LED_LINK 2 uint8_t off; uint8_t on; uint8_t reserved; } __packed; /* Structure for command IWN5000_CMD_WIMAX_COEX. */ struct iwn5000_wimax_event { uint8_t request; uint8_t window; uint8_t reserved; uint8_t flags; } __packed; struct iwn5000_wimax_coex { uint32_t flags; #define IWN_WIMAX_COEX_STA_TABLE_VALID (1 << 0) #define IWN_WIMAX_COEX_UNASSOC_WA_UNMASK (1 << 2) #define IWN_WIMAX_COEX_ASSOC_WA_UNMASK (1 << 3) #define IWN_WIMAX_COEX_ENABLE (1 << 7) struct iwn5000_wimax_event events[16]; } __packed; /* Structures for command IWN5000_CMD_CALIB_CONFIG. */ struct iwn5000_calib_elem { uint32_t enable; uint32_t start; #define IWN5000_CALIB_DC (1 << 1) uint32_t send; uint32_t apply; uint32_t reserved; } __packed; struct iwn5000_calib_status { struct iwn5000_calib_elem once; struct iwn5000_calib_elem perd; uint32_t flags; } __packed; struct iwn5000_calib_config { struct iwn5000_calib_status ucode; struct iwn5000_calib_status driver; uint32_t reserved; } __packed; /* Structure for command IWN_CMD_SET_POWER_MODE. */ struct iwn_pmgt_cmd { uint16_t flags; #define IWN_PS_ALLOW_SLEEP (1 << 0) #define IWN_PS_NOTIFY (1 << 1) #define IWN_PS_SLEEP_OVER_DTIM (1 << 2) #define IWN_PS_PCI_PMGT (1 << 3) #define IWN_PS_FAST_PD (1 << 4) uint8_t keepalive; uint8_t debug; uint32_t rxtimeout; uint32_t txtimeout; uint32_t intval[5]; uint32_t beacons; } __packed; /* Structures for command IWN_CMD_SCAN. */ struct iwn_scan_essid { uint8_t id; uint8_t len; uint8_t data[IEEE80211_NWID_LEN]; } __packed; struct iwn_scan_hdr { uint16_t len; uint8_t reserved1; uint8_t nchan; uint16_t quiet_time; uint16_t quiet_threshold; uint16_t crc_threshold; uint16_t rxchain; uint32_t max_out; /* (in usec) background scans */ uint32_t pause_scan; /* (in usec) background scans */ uint32_t flags; uint32_t filter; /* Followed by a struct iwn_cmd_data. */ /* Followed by an array of 20 structs iwn_scan_essid. */ /* Followed by probe request body. */ /* Followed by an array of ``nchan'' structs iwn_scan_chan. */ } __packed; struct iwn_scan_chan { uint32_t flags; #define IWN_CHAN_PASSIVE (0 << 0) #define IWN_CHAN_ACTIVE (1 << 0) #define IWN_CHAN_NPBREQS(x) (((1 << (x)) - 1) << 1) uint16_t chan; uint8_t rf_gain; uint8_t dsp_gain; uint16_t active; /* msecs */ uint16_t passive; /* msecs */ } __packed; /* Maximum size of a scan command. */ #define IWN_SCAN_MAXSZ (MCLBYTES - 4) /* * For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after * sending probe req. This should be set long enough to hear probe responses * from more than one AP. */ #define IWN_ACTIVE_DWELL_TIME_2GHZ (30) /* all times in msec */ #define IWN_ACTIVE_DWELL_TIME_5GHZ (20) #define IWN_ACTIVE_DWELL_FACTOR_2GHZ (3) #define IWN_ACTIVE_DWELL_FACTOR_5GHZ (2) /* * For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. * Must be set longer than active dwell time. * For the most reliable scan, set > AP beacon interval (typically 100msec). */ #define IWN_PASSIVE_DWELL_TIME_2GHZ (20) /* all times in msec */ #define IWN_PASSIVE_DWELL_TIME_5GHZ (10) #define IWN_PASSIVE_DWELL_BASE (100) #define IWN_CHANNEL_TUNE_TIME (5) /* * If active scanning is requested but a certain channel is * marked passive, we can do active scanning if we detect * transmissions. * * There is an issue with some firmware versions that triggers * a sysassert on a "good CRC threshold" of zero (== disabled), * on a radar channel even though this means that we should NOT * send probes. * * The "good CRC threshold" is the number of frames that we * need to receive during our dwell time on a channel before * sending out probes -- setting this to a huge value will * mean we never reach it, but at the same time work around * the aforementioned issue. Thus use IWN_GOOD_CRC_TH_NEVER * here instead of IWN_GOOD_CRC_TH_DISABLED. * * This was fixed in later versions along with some other * scan changes, and the threshold behaves as a flag in those * versions. */ #define IWN_GOOD_CRC_TH_DISABLED 0 #define IWN_GOOD_CRC_TH_DEFAULT htole16(1) #define IWN_GOOD_CRC_TH_NEVER htole16(0xffff) /* Structure for command IWN_CMD_TXPOWER (4965AGN only.) */ #define IWN_RIDX_MAX 32 struct iwn4965_cmd_txpower { uint8_t band; uint8_t reserved1; uint8_t chan; uint8_t reserved2; struct { uint8_t rf_gain[2]; uint8_t dsp_gain[2]; } __packed power[IWN_RIDX_MAX + 1]; } __packed; /* Structure for command IWN_CMD_TXPOWER_DBM (5000 Series only.) */ struct iwn5000_cmd_txpower { int8_t global_limit; /* in half-dBm */ #define IWN5000_TXPOWER_AUTO 0x7f #define IWN5000_TXPOWER_MAX_DBM 16 uint8_t flags; #define IWN5000_TXPOWER_NO_CLOSED (1 << 6) int8_t srv_limit; /* in half-dBm */ uint8_t reserved; } __packed; /* Structures for command IWN_CMD_BLUETOOTH. */ struct iwn_bluetooth { uint8_t flags; #define IWN_BT_COEX_CHAN_ANN (1 << 0) #define IWN_BT_COEX_BT_PRIO (1 << 1) #define IWN_BT_COEX_2_WIRE (1 << 2) uint8_t lead_time; #define IWN_BT_LEAD_TIME_DEF 30 uint8_t max_kill; #define IWN_BT_MAX_KILL_DEF 5 uint8_t reserved; uint32_t kill_ack; uint32_t kill_cts; } __packed; struct iwn6000_btcoex_config { uint8_t flags; #define IWN_BT_COEX6000_CHAN_INHIBITION 1 #define IWN_BT_COEX6000_MODE_MASK ((1 << 3) | (1 << 4) | (1 << 5)) #define IWN_BT_COEX6000_MODE_SHIFT 3 #define IWN_BT_COEX6000_MODE_DISABLED 0 #define IWN_BT_COEX6000_MODE_LEGACY_2W 1 #define IWN_BT_COEX6000_MODE_3W 2 #define IWN_BT_COEX6000_MODE_4W 3 #define IWN_BT_UCODE_DEFAULT (1<<6) #define IWN_BT_SYNC_2_BT_DISABLE (1<<7) uint8_t lead_time; uint8_t max_kill; uint8_t bt3_t7_timer; uint32_t kill_ack; uint32_t kill_cts; uint8_t sample_time; uint8_t bt3_t2_timer; uint16_t bt4_reaction; uint32_t lookup_table[12]; uint16_t bt4_decision; uint16_t valid; uint8_t prio_boost; uint8_t tx_prio_boost; uint16_t rx_prio_boost; } __packed; struct iwn2000_btcoex_config { uint8_t flags; /* same as in iwn6000_btcoex_config */ uint8_t lead_time; uint8_t max_kill; uint8_t bt3_t7_timer; uint32_t kill_ack; uint32_t kill_cts; uint8_t sample_time; uint8_t bt3_t2_timer; uint16_t bt4_reaction; uint32_t lookup_table[12]; uint16_t bt4_decision; uint16_t valid; uint32_t prio_boost; uint8_t reserved; uint8_t tx_prio_boost; uint16_t rx_prio_boost; } __packed; /* Structure for command IWN_CMD_BT_COEX_PRIOTABLE */ struct iwn_btcoex_priotable { uint8_t calib_init1; uint8_t calib_init2; uint8_t calib_periodic_low1; uint8_t calib_periodic_low2; uint8_t calib_periodic_high1; uint8_t calib_periodic_high2; uint8_t dtim; uint8_t scan52; uint8_t scan24; uint8_t reserved[7]; } __packed; /* Structure for command IWN_CMD_BT_COEX_PROT */ struct iwn_btcoex_prot { uint8_t open; uint8_t type; uint8_t reserved[2]; } __packed; /* Structure for command IWN_CMD_SET_CRITICAL_TEMP. */ struct iwn_critical_temp { uint32_t reserved; uint32_t tempM; uint32_t tempR; /* degK <-> degC conversion macros. */ #define IWN_CTOK(c) ((c) + 273) #define IWN_KTOC(k) ((k) - 273) #define IWN_CTOMUK(c) (((c) * 1000000) + 273150000) } __packed; /* Structures for command IWN_CMD_SET_SENSITIVITY. */ struct iwn_sensitivity_cmd { uint16_t which; #define IWN_SENSITIVITY_DEFAULTTBL 0 #define IWN_SENSITIVITY_WORKTBL 1 uint16_t energy_cck; uint16_t energy_ofdm; uint16_t corr_ofdm_x1; uint16_t corr_ofdm_mrc_x1; uint16_t corr_cck_mrc_x4; uint16_t corr_ofdm_x4; uint16_t corr_ofdm_mrc_x4; uint16_t corr_barker; uint16_t corr_barker_mrc; uint16_t corr_cck_x4; uint16_t energy_ofdm_th; } __packed; struct iwn_enhanced_sensitivity_cmd { uint16_t which; uint16_t energy_cck; uint16_t energy_ofdm; uint16_t corr_ofdm_x1; uint16_t corr_ofdm_mrc_x1; uint16_t corr_cck_mrc_x4; uint16_t corr_ofdm_x4; uint16_t corr_ofdm_mrc_x4; uint16_t corr_barker; uint16_t corr_barker_mrc; uint16_t corr_cck_x4; uint16_t energy_ofdm_th; /* "Enhanced" part. */ uint16_t ina_det_ofdm; uint16_t ina_det_cck; uint16_t corr_11_9_en; uint16_t ofdm_det_slope_mrc; uint16_t ofdm_det_icept_mrc; uint16_t ofdm_det_slope; uint16_t ofdm_det_icept; uint16_t cck_det_slope_mrc; uint16_t cck_det_icept_mrc; uint16_t cck_det_slope; uint16_t cck_det_icept; uint16_t reserved; } __packed; /* Structures for command IWN_CMD_PHY_CALIB. */ struct iwn_phy_calib { uint8_t code; #define IWN4965_PHY_CALIB_DIFF_GAIN 7 #define IWN5000_PHY_CALIB_DC 8 #define IWN5000_PHY_CALIB_LO 9 #define IWN5000_PHY_CALIB_TX_IQ 11 #define IWN5000_PHY_CALIB_CRYSTAL 15 #define IWN5000_PHY_CALIB_BASE_BAND 16 #define IWN5000_PHY_CALIB_TX_IQ_PERIODIC 17 #define IWN5000_PHY_CALIB_RESET_NOISE_GAIN 18 #define IWN5000_PHY_CALIB_NOISE_GAIN 19 #define IWN6000_PHY_CALIB_TEMP_OFFSET 18 #define IWN2000_PHY_CALIB_TEMP_OFFSET 18 #define IWN5000_PHY_CALIB_MAX 253 uint8_t group; uint8_t ngroups; uint8_t isvalid; } __packed; struct iwn5000_phy_calib_crystal { uint8_t code; uint8_t group; uint8_t ngroups; uint8_t isvalid; uint8_t cap_pin[2]; uint8_t reserved[2]; } __packed; struct iwn6000_phy_calib_temp_offset { uint8_t code; uint8_t group; uint8_t ngroups; uint8_t isvalid; int16_t offset; #define IWN_DEFAULT_TEMP_OFFSET 2700 uint16_t reserved; } __packed; struct iwn2000_phy_calib_temp_offset { uint8_t code; uint8_t group; uint8_t ngroups; uint8_t isvalid; int16_t offset_high; int16_t offset_low; int16_t burnt_voltage_ref; int16_t reserved; } __packed; struct iwn_phy_calib_gain { uint8_t code; uint8_t group; uint8_t ngroups; uint8_t isvalid; int8_t gain[3]; uint8_t reserved; } __packed; /* Structure for command IWN_CMD_SPECTRUM_MEASUREMENT. */ struct iwn_spectrum_cmd { uint16_t len; uint8_t token; uint8_t id; uint8_t origin; uint8_t periodic; uint16_t timeout; uint32_t start; uint32_t reserved1; uint32_t flags; uint32_t filter; uint16_t nchan; uint16_t reserved2; struct { uint32_t duration; uint8_t chan; uint8_t type; #define IWN_MEASUREMENT_BASIC (1 << 0) #define IWN_MEASUREMENT_CCA (1 << 1) #define IWN_MEASUREMENT_RPI_HISTOGRAM (1 << 2) #define IWN_MEASUREMENT_NOISE_HISTOGRAM (1 << 3) #define IWN_MEASUREMENT_FRAME (1 << 4) #define IWN_MEASUREMENT_IDLE (1 << 7) uint16_t reserved; } __packed chan[10]; } __packed; /* Structure for IWN_UC_READY notification. */ #define IWN_NATTEN_GROUPS 5 struct iwn_ucode_info { uint8_t minor; uint8_t major; uint16_t reserved1; uint8_t revision[8]; uint8_t type; uint8_t subtype; #define IWN_UCODE_RUNTIME 0 #define IWN_UCODE_INIT 9 uint16_t reserved2; uint32_t logptr; uint32_t errptr; uint32_t tstamp; uint32_t valid; /* The following fields are for UCODE_INIT only. */ int32_t volt; struct { int32_t chan20MHz; int32_t chan40MHz; } __packed temp[4]; int32_t atten[IWN_NATTEN_GROUPS][2]; } __packed; /* Structures for IWN_TX_DONE notification. */ /* Tx status for aggregated frames (A-MPDU). */ struct iwn_txagg_status { uint16_t status; #define IWN_AGG_TX_STATE_TRANSMITTED 0x0000 #define IWN_AGG_TX_STATE_UNDERRUN 0x0001 #define IWN_AGG_TX_STATE_BT_PRIO 0x0002 #define IWN_AGG_TX_STATE_FEW_BYTES 0x0004 #define IWN_AGG_TX_STATE_ABORT 0x0008 #define IWN_AGG_TX_STATE_LAST_SENT_TTL 0x0010 #define IWN_AGG_TX_STATE_LAST_SENT_TRY_CNT 0x0020 #define IWN_AGG_TX_STATE_LAST_SENT_BT_KILL 0x0040 #define IWN_AGG_TX_STATE_SCD_QUERY 0x0080 #define IWN_AGG_TX_STATE_TEST_BAD_CRC32 0x0100 #define IWN_AGG_TX_STATE_RESPONSE_MASK 0x01ff #define IWN_AGG_TX_STATE_DUMP_TX 0x0200 #define IWN_AGG_TX_STATE_DELAY_TX 0x0400 #define IWN_AGG_TX_STATUS_MASK 0x0fff /* Number of TX attempts for first frame in aggregation: */ #define IWN_AGG_TX_TRY 0xf000 #define IWN_AGG_TX_TRY_SHIFT 12 /* Copied from Tx command we have sent to the firmware. */ uint8_t idx; uint8_t qid; } __packed; /* For aggregation queues, index must be aligned to frame sequence number. */ #define IWN_AGG_SSN_TO_TXQ_IDX(x) ((x) & (IWN_TX_RING_COUNT - 1)) /* Tx status codes for non-aggregated frames. */ #define IWN_TX_STATUS_SUCCESS 0x01 #define IWN_TX_STATUS_DIRECT_DONE 0x02 #define IWN_TX_STATUS_POSTPONE_DELAY 0x40 #define IWN_TX_STATUS_POSTPONE_FEW_BYTES 0x41 #define IWN_TX_STATUS_POSTPONE_BT_PRIO 0x42 #define IWN_TX_STATUS_POSTPONE_QUIET_PERIOD 0x43 #define IWN_TX_STATUS_POSTPONE_CALC_TTAK 0x44 #define IWN_TX_STATUS_FAIL_CROSSED_RETRY 0x81 #define IWN_TX_STATUS_FAIL_SHORT_LIMIT 0x82 #define IWN_TX_STATUS_FAIL_LONG_LIMIT 0x83 #define IWN_TX_STATUS_FAIL_FIFO_UNDERRUN 0x84 #define IWN_TX_STATUS_FAIL_DRAIN_FLOW 0x85 #define IWN_TX_STATUS_FAIL_RFKILL_FLUSH 0x86 #define IWN_TX_STATUS_FAIL_LIFE_EXPIRE 0x87 #define IWN_TX_STATUS_FAIL_DEST_PS 0x88 #define IWN_TX_STATUS_FAIL_HOST_ABORTED 0x89 #define IWN_TX_STATUS_FAIL_BT_RETRY 0x8a #define IWN_TX_STATUS_FAIL_STA_INVALID 0x8b #define IWN_TX_STATUS_FAIL_FRAG_DROPPED 0x8c #define IWN_TX_STATUS_FAIL_TID_DISABLE 0x8d #define IWN_TX_STATUS_FAIL_FIFO_FLUSHED 0x8e #define IWN_TX_STATUS_FAIL_INSUFFICIENT_CF_POLL 0x8f #define IWN_TX_STATUS_FAIL_PASSIVE_NO_RX 0x90 #define IWN_TX_STATUS_FAIL_NO_BEACON_ON_RADAR 0x91 struct iwn4965_tx_stat { uint8_t nframes; uint8_t btkillcnt; uint8_t rtsfailcnt; uint8_t ackfailcnt; uint8_t rate; uint8_t rflags; uint16_t xrflags; uint16_t duration; uint16_t reserved; uint32_t power[2]; union { uint32_t status; /* if nframes == 1 */ struct iwn_txagg_status agg_status[0]; /* nframes elements */ } stat; /* Followed by current scheduler SSN (uint32_t). */ } __packed; struct iwn5000_tx_stat { uint8_t nframes; uint8_t btkillcnt; uint8_t rtsfailcnt; uint8_t ackfailcnt; uint8_t rate; uint8_t rflags; uint16_t xrflags; uint16_t duration; uint16_t reserved; uint32_t power[2]; uint32_t info; uint16_t seq; uint16_t len; uint8_t tlc; uint8_t ratid; #define IWN_TX_RES_TID_SHIFT 0 #define IWN_TX_RES_TID 0x0f #define IWN_TX_RES_RA_SHIFT 4 #define IWN_TX_RES_RA 0xf0 uint8_t fc[2]; union { uint32_t status; /* if nframes == 1 */ struct iwn_txagg_status agg_status[0]; /* nframes elements */ } stat; /* Followed by current scheduler SSN (uint32_t). */ } __packed; /* Structure for IWN_BEACON_MISSED notification. */ struct iwn_beacon_missed { uint32_t consecutive; uint32_t total; uint32_t expected; uint32_t received; } __packed; /* Structure for IWN_MPDU_RX_DONE notification. */ struct iwn_rx_mpdu { uint16_t len; uint16_t reserved; } __packed; /* Structures for IWN_RX_DONE and IWN_MPDU_RX_DONE notifications. */ struct iwn4965_rx_phystat { uint16_t antenna; uint16_t agc; uint8_t rssi[6]; } __packed; struct iwn5000_rx_phystat { uint32_t reserved1; uint32_t agc; uint16_t rssi[3]; } __packed; struct iwn_rx_stat { uint8_t phy_len; uint8_t cfg_phy_len; #define IWN_STAT_MAXLEN 20 uint8_t id; uint8_t reserved1; uint64_t tstamp; uint32_t beacon; uint16_t flags; #define IWN_STAT_FLAG_24GHZ (1 << 0) #define IWN_STAT_FLAG_MOD_CCK (1 << 1) #define IWN_STAT_FLAG_SHPREAMBLE (1 << 2) #define IWN_STAT_FLAG_NARROW_BAND (1 << 3) #define IWN_STAT_FLAG_ANT(x) ((x) << 4) /* 3 bits */ #define IWN_STAT_FLAG_AGG (1 << 7) uint16_t chan; uint8_t phybuf[32]; uint8_t rate; uint8_t rflags; uint16_t xrflags; uint16_t len; uint16_t reserve3; } __packed; #define IWN_RSSI_TO_DBM 44 /* Structure for IWN_RX_COMPRESSED_BA notification. */ struct iwn_compressed_ba { uint8_t macaddr[IEEE80211_ADDR_LEN]; uint16_t reserved; uint8_t id; uint8_t tid; uint16_t seq; uint64_t bitmap; uint16_t qid; uint16_t ssn; uint8_t nframes_sent; uint8_t nframes_acked; uint16_t reserved2; } __packed; /* Structure for IWN_START_SCAN notification. */ struct iwn_start_scan { uint64_t tstamp; uint32_t tbeacon; uint8_t chan; uint8_t band; uint16_t reserved; uint32_t status; } __packed; /* Structure for IWN_STOP_SCAN notification. */ struct iwn_stop_scan { uint8_t nchan; uint8_t status; uint8_t reserved; uint8_t chan; uint64_t tsf; } __packed; /* Structure for IWN_SPECTRUM_MEASUREMENT notification. */ struct iwn_spectrum_notif { uint8_t id; uint8_t token; uint8_t idx; uint8_t state; #define IWN_MEASUREMENT_START 0 #define IWN_MEASUREMENT_STOP 1 uint32_t start; uint8_t band; uint8_t chan; uint8_t type; uint8_t reserved1; uint32_t cca_ofdm; uint32_t cca_cck; uint32_t cca_time; uint8_t basic; uint8_t reserved2[3]; uint32_t ofdm[8]; uint32_t cck[8]; uint32_t stop; uint32_t status; #define IWN_MEASUREMENT_OK 0 #define IWN_MEASUREMENT_CONCURRENT 1 #define IWN_MEASUREMENT_CSA_CONFLICT 2 #define IWN_MEASUREMENT_TGH_CONFLICT 3 #define IWN_MEASUREMENT_STOPPED 6 #define IWN_MEASUREMENT_TIMEOUT 7 #define IWN_MEASUREMENT_FAILED 8 } __packed; /* Structures for IWN_{RX,BEACON}_STATISTICS notification. */ struct iwn_rx_phy_stats { uint32_t ina; uint32_t fina; uint32_t bad_plcp; uint32_t bad_crc32; uint32_t overrun; uint32_t eoverrun; uint32_t good_crc32; uint32_t fa; uint32_t bad_fina_sync; uint32_t sfd_timeout; uint32_t fina_timeout; uint32_t no_rts_ack; uint32_t rxe_limit; uint32_t ack; uint32_t cts; uint32_t ba_resp; uint32_t dsp_kill; uint32_t bad_mh; uint32_t rssi_sum; uint32_t reserved; } __packed; struct iwn_rx_general_stats { uint32_t bad_cts; uint32_t bad_ack; uint32_t not_bss; uint32_t filtered; uint32_t bad_chan; uint32_t beacons; uint32_t missed_beacons; uint32_t adc_saturated; /* time in 0.8us */ uint32_t ina_searched; /* time in 0.8us */ uint32_t noise[3]; uint32_t flags; uint32_t load; uint32_t fa; uint32_t rssi[3]; uint32_t energy[3]; } __packed; struct iwn_rx_ht_phy_stats { uint32_t bad_plcp; uint32_t overrun; uint32_t eoverrun; uint32_t good_crc32; uint32_t bad_crc32; uint32_t bad_mh; uint32_t good_ampdu_crc32; uint32_t ampdu; uint32_t fragment; uint32_t reserved; } __packed; struct iwn_rx_stats { struct iwn_rx_phy_stats ofdm; struct iwn_rx_phy_stats cck; struct iwn_rx_general_stats general; struct iwn_rx_ht_phy_stats ht; } __packed; struct iwn_tx_stats { uint32_t preamble; uint32_t rx_detected; uint32_t bt_defer; uint32_t bt_kill; uint32_t short_len; uint32_t cts_timeout; uint32_t ack_timeout; uint32_t exp_ack; uint32_t ack; uint32_t msdu; uint32_t busrt_err1; uint32_t burst_err2; uint32_t cts_collision; uint32_t ack_collision; uint32_t ba_timeout; uint32_t ba_resched; uint32_t query_ampdu; uint32_t query; uint32_t query_ampdu_frag; uint32_t query_mismatch; uint32_t not_ready; uint32_t underrun; uint32_t bt_ht_kill; uint32_t rx_ba_resp; uint32_t reserved[2]; } __packed; struct iwn_general_stats { uint32_t temp; uint32_t temp_m; uint32_t burst_check; uint32_t burst; uint32_t reserved1[4]; uint32_t sleep; uint32_t slot_out; uint32_t slot_idle; uint32_t ttl_tstamp; uint32_t tx_ant_a; uint32_t tx_ant_b; uint32_t exec; uint32_t probe; uint32_t reserved2[2]; uint32_t rx_enabled; uint32_t reserved3[3]; } __packed; struct iwn_stats { uint32_t flags; #define IWN_STATS_FLAGS_BAND_24G 0x02 #define IWN_STATS_FLAGS_BAND_HT40 0x08 struct iwn_rx_stats rx; struct iwn_tx_stats tx; struct iwn_general_stats general; } __packed; /* Firmware error dump. */ struct iwn_fw_dump { uint32_t valid; uint32_t id; uint32_t pc; uint32_t branch_link[2]; uint32_t interrupt_link[2]; uint32_t error_data[2]; uint32_t src_line; uint32_t tsf; uint32_t time[2]; } __packed; /* TLV firmware header. */ struct iwn_fw_tlv_hdr { uint32_t zero; /* Always 0, to differentiate from legacy. */ uint32_t signature; #define IWN_FW_SIGNATURE 0x0a4c5749 /* "IWL\n" */ uint8_t descr[64]; uint32_t rev; #define IWN_FW_API(x) (((x) >> 8) & 0xff) uint32_t build; uint64_t altmask; } __packed; /* TLV header. */ struct iwn_fw_tlv { uint16_t type; #define IWN_FW_TLV_MAIN_TEXT 1 #define IWN_FW_TLV_MAIN_DATA 2 #define IWN_FW_TLV_INIT_TEXT 3 #define IWN_FW_TLV_INIT_DATA 4 #define IWN_FW_TLV_BOOT_TEXT 5 #define IWN_FW_TLV_PBREQ_MAXLEN 6 #define IWN_FW_TLV_ENH_SENS 14 #define IWN_FW_TLV_PHY_CALIB 15 #define IWN_FW_TLV_FLAGS 18 uint16_t alt; uint32_t len; } __packed; #define IWN4965_FW_TEXT_MAXSZ ( 96 * 1024) #define IWN4965_FW_DATA_MAXSZ ( 40 * 1024) #define IWN5000_FW_TEXT_MAXSZ (256 * 1024) #define IWN5000_FW_DATA_MAXSZ ( 80 * 1024) #define IWN_FW_BOOT_TEXT_MAXSZ 1024 #define IWN4965_FWSZ (IWN4965_FW_TEXT_MAXSZ + IWN4965_FW_DATA_MAXSZ) #define IWN5000_FWSZ IWN5000_FW_TEXT_MAXSZ /* * Microcode flags TLV (18.) */ /** * enum iwn_ucode_tlv_flag - ucode API flags * @IWN_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * was a separate TLV but moved here to save space. * @IWN_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, * treats good CRC threshold as a boolean * @IWN_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). * @IWN_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. * @IWN_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS * @IWN_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD * @IWN_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan * offload profile config command. * @IWN_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api * @IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API. * @IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six * (rather than two) IPv6 addresses * @IWN_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API * @IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element * from the probe request template. * @IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping * connection when going back to D0 * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) * @IWN_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan. * @IWN_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API * @IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command * containing CAM (Continuous Active Mode) indication. */ enum iwn_ucode_tlv_flag { IWN_UCODE_TLV_FLAGS_PAN = (1 << 0), IWN_UCODE_TLV_FLAGS_NEWSCAN = (1 << 1), IWN_UCODE_TLV_FLAGS_MFP = (1 << 2), IWN_UCODE_TLV_FLAGS_P2P = (1 << 3), IWN_UCODE_TLV_FLAGS_DW_BC_TABLE = (1 << 4), IWN_UCODE_TLV_FLAGS_NEWBT_COEX = (1 << 5), IWN_UCODE_TLV_FLAGS_UAPSD = (1 << 6), IWN_UCODE_TLV_FLAGS_SHORT_BL = (1 << 7), IWN_UCODE_TLV_FLAGS_RX_ENERGY_API = (1 << 8), IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = (1 << 9), IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = (1 << 10), IWN_UCODE_TLV_FLAGS_BF_UPDATED = (1 << 11), IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID = (1 << 12), IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API = (1 << 14), IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = (1 << 15), IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = (1 << 16), IWN_UCODE_TLV_FLAGS_SCHED_SCAN = (1 << 17), IWN_UCODE_TLV_FLAGS_STA_KEY_CMD = (1 << 19), IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD = (1 << 20), }; /* * Offsets into EEPROM. */ #define IWN_EEPROM_MAC 0x015 #define IWN_EEPROM_SKU_CAP 0x045 #define IWN_EEPROM_RFCFG 0x048 #define IWN4965_EEPROM_DOMAIN 0x060 #define IWN4965_EEPROM_BAND1 0x063 #define IWN5000_EEPROM_REG 0x066 #define IWN5000_EEPROM_CAL 0x067 #define IWN4965_EEPROM_BAND2 0x072 #define IWN4965_EEPROM_BAND3 0x080 #define IWN4965_EEPROM_BAND4 0x08d #define IWN4965_EEPROM_BAND5 0x099 #define IWN4965_EEPROM_BAND6 0x0a0 #define IWN4965_EEPROM_BAND7 0x0a8 #define IWN4965_EEPROM_MAXPOW 0x0e8 #define IWN4965_EEPROM_VOLTAGE 0x0e9 #define IWN4965_EEPROM_BANDS 0x0ea /* Indirect offsets. */ #define IWN5000_EEPROM_DOMAIN 0x001 #define IWN5000_EEPROM_BAND1 0x004 #define IWN5000_EEPROM_BAND2 0x013 #define IWN5000_EEPROM_BAND3 0x021 #define IWN5000_EEPROM_BAND4 0x02e #define IWN5000_EEPROM_BAND5 0x03a #define IWN5000_EEPROM_BAND6 0x041 #define IWN5000_EEPROM_BAND7 0x049 #define IWN6000_EEPROM_ENHINFO 0x054 #define IWN5000_EEPROM_CRYSTAL 0x128 #define IWN5000_EEPROM_TEMP 0x12a #define IWN5000_EEPROM_VOLT 0x12b #define IWN2000_EEPROM_RAWTEMP 0x12b /* Possible flags for IWN_EEPROM_SKU_CAP. */ #define IWN_EEPROM_SKU_CAP_11N (1 << 6) #define IWN_EEPROM_SKU_CAP_AMT (1 << 7) #define IWN_EEPROM_SKU_CAP_IPAN (1 << 8) /* Possible flags for IWN_EEPROM_RFCFG. */ #define IWN_RFCFG_TYPE(x) (((x) >> 0) & 0x3) #define IWN_RFCFG_STEP(x) (((x) >> 2) & 0x3) #define IWN_RFCFG_DASH(x) (((x) >> 4) & 0x3) #define IWN_RFCFG_TXANTMSK(x) (((x) >> 8) & 0xf) #define IWN_RFCFG_RXANTMSK(x) (((x) >> 12) & 0xf) struct iwn_eeprom_chan { uint8_t flags; #define IWN_EEPROM_CHAN_VALID (1 << 0) #define IWN_EEPROM_CHAN_IBSS (1 << 1) #define IWN_EEPROM_CHAN_ACTIVE (1 << 3) #define IWN_EEPROM_CHAN_RADAR (1 << 4) int8_t maxpwr; } __packed; struct iwn_eeprom_enhinfo { uint8_t flags; #define IWN_TXP_VALID (1 << 0) #define IWN_TXP_BAND_52G (1 << 1) #define IWN_TXP_OFDM (1 << 2) #define IWN_TXP_40MHZ (1 << 3) #define IWN_TXP_HT_AP (1 << 4) #define IWN_TXP_RES1 (1 << 5) #define IWN_TXP_RES2 (1 << 6) #define IWN_TXP_COMMON_TYPE (1 << 7) uint8_t chan; int8_t chain[3]; /* max power in half-dBm */ uint8_t delta_20_in_40; int8_t mimo2; /* max power in half-dBm */ int8_t mimo3; /* max power in half-dBm */ } __packed; struct iwn5000_eeprom_calib_hdr { uint8_t version; uint8_t pa_type; uint16_t volt; } __packed; #define IWN_NSAMPLES 3 struct iwn4965_eeprom_chan_samples { uint8_t num; struct { uint8_t temp; uint8_t gain; uint8_t power; int8_t pa_det; } samples[2][IWN_NSAMPLES]; } __packed; #define IWN_NBANDS 8 struct iwn4965_eeprom_band { uint8_t lo; /* low channel number */ uint8_t hi; /* high channel number */ struct iwn4965_eeprom_chan_samples chans[2]; } __packed; /* * Offsets of channels descriptions in EEPROM. */ static const uint32_t iwn4965_regulatory_bands[IWN_NBANDS] = { IWN4965_EEPROM_BAND1, IWN4965_EEPROM_BAND2, IWN4965_EEPROM_BAND3, IWN4965_EEPROM_BAND4, IWN4965_EEPROM_BAND5, IWN4965_EEPROM_BAND6, IWN4965_EEPROM_BAND7 }; static const uint32_t iwn5000_regulatory_bands[IWN_NBANDS] = { IWN5000_EEPROM_BAND1, IWN5000_EEPROM_BAND2, IWN5000_EEPROM_BAND3, IWN5000_EEPROM_BAND4, IWN5000_EEPROM_BAND5, IWN5000_EEPROM_BAND6, IWN5000_EEPROM_BAND7 }; #define IWN_CHAN_BANDS_COUNT 7 #define IWN_MAX_CHAN_PER_BAND 14 static const struct iwn_chan_band { uint8_t nchan; uint8_t chan[IWN_MAX_CHAN_PER_BAND]; } iwn_bands[] = { /* 20MHz channels, 2GHz band. */ { 14, { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 } }, /* 20MHz channels, 5GHz band. */ { 13, { 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 } }, { 12, { 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 } }, { 11, { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 } }, { 6, { 145, 149, 153, 157, 161, 165 } }, /* 40MHz channels (primary channels), 2GHz band. */ { 7, { 1, 2, 3, 4, 5, 6, 7 } }, /* 40MHz channels (primary channels), 5GHz band. */ { 11, { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 } } }; #define IWN1000_OTP_NBLOCKS 3 #define IWN6000_OTP_NBLOCKS 4 #define IWN6050_OTP_NBLOCKS 7 /* fw API values for legacy bit rates, both OFDM and CCK */ #define IWN_RATE_6M_PLCP 13 #define IWN_RATE_9M_PLCP 15 #define IWN_RATE_12M_PLCP 5 #define IWN_RATE_18M_PLCP 7 #define IWN_RATE_24M_PLCP 9 #define IWN_RATE_36M_PLCP 11 #define IWN_RATE_48M_PLCP 1 #define IWN_RATE_54M_PLCP 3 #define IWN_RATE_1M_PLCP 10 #define IWN_RATE_2M_PLCP 20 #define IWN_RATE_5M_PLCP 55 #define IWN_RATE_11M_PLCP 110 #define IWN_RATE_INVM_PLCP 0xff /* uCode API values for HT/VHT bit rates */ #define IWN_RATE_HT_SISO_MCS_0_PLCP 0 #define IWN_RATE_HT_SISO_MCS_1_PLCP 1 #define IWN_RATE_HT_SISO_MCS_2_PLCP 2 #define IWN_RATE_HT_SISO_MCS_3_PLCP 3 #define IWN_RATE_HT_SISO_MCS_4_PLCP 4 #define IWN_RATE_HT_SISO_MCS_5_PLCP 5 #define IWN_RATE_HT_SISO_MCS_6_PLCP 6 #define IWN_RATE_HT_SISO_MCS_7_PLCP 7 #define IWN_RATE_HT_MIMO2_MCS_8_PLCP 0x8 #define IWN_RATE_HT_MIMO2_MCS_9_PLCP 0x9 #define IWN_RATE_HT_MIMO2_MCS_10_PLCP 0xA #define IWN_RATE_HT_MIMO2_MCS_11_PLCP 0xB #define IWN_RATE_HT_MIMO2_MCS_12_PLCP 0xC #define IWN_RATE_HT_MIMO2_MCS_13_PLCP 0xD #define IWN_RATE_HT_MIMO2_MCS_14_PLCP 0xE #define IWN_RATE_HT_MIMO2_MCS_15_PLCP 0xF #define IWN_RATE_HT_SISO_MCS_INV_PLCP 0x1A #define IWN_RATE_HT_MIMO2_MCS_INV_PLCP IWN_RATE_HT_SISO_MCS_INV_PLCP #define IWN_RATE_HT_SISO_MCS_8_PLCP IWN_RATE_HT_SISO_MCS_INV_PLCP #define IWN_RATE_HT_SISO_MCS_9_PLCP IWN_RATE_HT_SISO_MCS_INV_PLCP #define IWN_RATE_HT_MCS_RATE_CODE_MSK 0x7 #define IWN_RATE_HT_MCS_NSS_POS 3 #define IWN_RATE_HT_MCS_NSS_MSK (3 << IWN_RATE_HT_MCS_NSS_POS) /* * These serve as indexes into struct iwn_rate iwn_rates[IWN_RIDX_MAX]. */ enum { IWN_RATE_1M_INDEX = 0, IWN_FIRST_CCK_RATE = IWN_RATE_1M_INDEX, IWN_RATE_2M_INDEX, IWN_RATE_5M_INDEX, IWN_RATE_11M_INDEX, IWN_LAST_CCK_RATE = IWN_RATE_11M_INDEX, IWN_RATE_6M_INDEX, IWN_FIRST_OFDM_RATE = IWN_RATE_6M_INDEX, IWN_RATE_MCS_0_INDEX = IWN_RATE_6M_INDEX, IWN_FIRST_HT_RATE = IWN_RATE_MCS_0_INDEX, IWN_FIRST_VHT_RATE = IWN_RATE_MCS_0_INDEX, IWN_RATE_9M_INDEX, IWN_RATE_12M_INDEX, IWN_RATE_MCS_1_INDEX = IWN_RATE_12M_INDEX, IWN_RATE_MCS_8_INDEX, IWN_FIRST_HT_MIMO2_RATE = IWN_RATE_MCS_8_INDEX, IWN_RATE_18M_INDEX, IWN_RATE_MCS_2_INDEX = IWN_RATE_18M_INDEX, IWN_RATE_24M_INDEX, IWN_RATE_MCS_3_INDEX = IWN_RATE_24M_INDEX, IWN_RATE_MCS_9_INDEX, IWN_RATE_36M_INDEX, IWN_RATE_MCS_4_INDEX = IWN_RATE_36M_INDEX, IWN_RATE_MCS_10_INDEX, IWN_RATE_48M_INDEX, IWN_RATE_MCS_5_INDEX = IWN_RATE_48M_INDEX, IWN_RATE_MCS_11_INDEX, IWN_RATE_54M_INDEX, IWN_RATE_MCS_6_INDEX = IWN_RATE_54M_INDEX, IWN_LAST_NON_HT_RATE = IWN_RATE_54M_INDEX, IWN_RATE_MCS_7_INDEX, IWN_LAST_HT_SISO_RATE = IWN_RATE_MCS_7_INDEX, IWN_RATE_MCS_12_INDEX, IWN_RATE_MCS_13_INDEX, IWN_RATE_MCS_14_INDEX, IWN_RATE_MCS_15_INDEX, IWN_LAST_HT_RATE = IWN_RATE_MCS_15_INDEX, IWN_LAST_VHT_RATE = IWN_RATE_MCS_9_INDEX, IWN_RATE_COUNT_LEGACY = IWN_LAST_NON_HT_RATE + 1, IWN_RATE_COUNT = IWN_LAST_HT_RATE + 1, }; static const struct iwn_rate { uint16_t rate; uint8_t plcp; uint8_t ht_plcp; } iwn_rates[IWN_RIDX_MAX + 1] = { /* Legacy */ /* HT */ { 2, IWN_RATE_1M_PLCP, IWN_RATE_HT_SISO_MCS_INV_PLCP,}, // 0 { 4, IWN_RATE_2M_PLCP, IWN_RATE_HT_SISO_MCS_INV_PLCP,}, // 1 { 11, IWN_RATE_5M_PLCP, IWN_RATE_HT_SISO_MCS_INV_PLCP,}, // 2 { 22, IWN_RATE_11M_PLCP, IWN_RATE_HT_SISO_MCS_INV_PLCP,}, // 3 { 12, IWN_RATE_6M_PLCP, IWN_RATE_HT_SISO_MCS_0_PLCP, }, // 4 { 18, IWN_RATE_9M_PLCP, IWN_RATE_HT_SISO_MCS_INV_PLCP,}, // 5 { 24, IWN_RATE_12M_PLCP, IWN_RATE_HT_SISO_MCS_1_PLCP, }, // 6 { 26, IWN_RATE_INVM_PLCP, IWN_RATE_HT_MIMO2_MCS_8_PLCP, }, // 7 { 36, IWN_RATE_18M_PLCP, IWN_RATE_HT_SISO_MCS_2_PLCP, }, // 8 { 48, IWN_RATE_24M_PLCP, IWN_RATE_HT_SISO_MCS_3_PLCP, }, // 9 { 52, IWN_RATE_INVM_PLCP, IWN_RATE_HT_MIMO2_MCS_9_PLCP, }, // 10 { 72, IWN_RATE_36M_PLCP, IWN_RATE_HT_SISO_MCS_4_PLCP, }, // 11 { 78, IWN_RATE_INVM_PLCP, IWN_RATE_HT_MIMO2_MCS_10_PLCP,}, // 12 { 96, IWN_RATE_48M_PLCP, IWN_RATE_HT_SISO_MCS_5_PLCP, }, // 13 { 104, IWN_RATE_INVM_PLCP, IWN_RATE_HT_MIMO2_MCS_11_PLCP,}, // 14 { 108, IWN_RATE_54M_PLCP, IWN_RATE_HT_SISO_MCS_6_PLCP, }, // 15 { 128, IWN_RATE_INVM_PLCP, IWN_RATE_HT_SISO_MCS_7_PLCP, }, // 16 { 156, IWN_RATE_INVM_PLCP, IWN_RATE_HT_MIMO2_MCS_12_PLCP,}, // 17 { 208, IWN_RATE_INVM_PLCP, IWN_RATE_HT_MIMO2_MCS_13_PLCP,}, // 18 { 234, IWN_RATE_INVM_PLCP, IWN_RATE_HT_MIMO2_MCS_14_PLCP,}, // 19 { 260, IWN_RATE_INVM_PLCP, IWN_RATE_HT_MIMO2_MCS_15_PLCP,}, // 20 }; #define IWN_RIDX_CCK 0 #define IWN_RIDX_OFDM 4 #define IWN_RIDX_IS_CCK(_i_) ((_i_) < IWN_RIDX_OFDM) #define IWN_RIDX_IS_OFDM(_i_) ((_i_) >= IWN_RIDX_OFDM) #define IWN_RVAL_IS_OFDM(_i_) ((_i_) >= 12 && (_i_) != 22) /* Convert an MCS index into an iwn_rates[] index. */ const int iwn_mcs2ridx[] = { IWN_RATE_MCS_0_INDEX, IWN_RATE_MCS_1_INDEX, IWN_RATE_MCS_2_INDEX, IWN_RATE_MCS_3_INDEX, IWN_RATE_MCS_4_INDEX, IWN_RATE_MCS_5_INDEX, IWN_RATE_MCS_6_INDEX, IWN_RATE_MCS_7_INDEX, IWN_RATE_MCS_8_INDEX, IWN_RATE_MCS_9_INDEX, IWN_RATE_MCS_10_INDEX, IWN_RATE_MCS_11_INDEX, IWN_RATE_MCS_12_INDEX, IWN_RATE_MCS_13_INDEX, IWN_RATE_MCS_14_INDEX, IWN_RATE_MCS_15_INDEX, }; #define IWN4965_MAX_PWR_INDEX 107 /* * RF Tx gain values from highest to lowest power (values obtained from * the reference driver.) */ static const uint8_t iwn4965_rf_gain_2ghz[IWN4965_MAX_PWR_INDEX + 1] = { 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint8_t iwn4965_rf_gain_5ghz[IWN4965_MAX_PWR_INDEX + 1] = { 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x23, 0x23, 0x23, 0x22, 0x18, 0x18, 0x17, 0x17, 0x17, 0x16, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x08, 0x08, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* * DSP pre-DAC gain values from highest to lowest power (values obtained * from the reference driver.) */ static const uint8_t iwn4965_dsp_gain_2ghz[IWN4965_MAX_PWR_INDEX + 1] = { 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b }; static const uint8_t iwn4965_dsp_gain_5ghz[IWN4965_MAX_PWR_INDEX + 1] = { 0x7b, 0x75, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x6e, 0x68, 0x62, 0x5d, 0x58, 0x53, 0x4e }; /* * Power saving settings (values obtained from the reference driver.) */ #define IWN_NDTIMRANGES 3 #define IWN_NPOWERLEVELS 6 static const struct iwn_pmgt { uint32_t rxtimeout; uint32_t txtimeout; uint32_t intval[5]; int skip_dtim; } iwn_pmgt[IWN_NDTIMRANGES][IWN_NPOWERLEVELS] = { /* DTIM <= 2 */ { { 0, 0, { 0, 0, 0, 0, 0 }, 0 }, /* CAM */ { 200, 500, { 1, 2, 2, 2, (uint32_t)-1 }, 0 }, /* PS level 1 */ { 200, 300, { 1, 2, 2, 2, (uint32_t)-1 }, 0 }, /* PS level 2 */ { 50, 100, { 2, 2, 2, 2, (uint32_t)-1 }, 0 }, /* PS level 3 */ { 50, 25, { 2, 2, 4, 4, (uint32_t)-1 }, 1 }, /* PS level 4 */ { 25, 25, { 2, 2, 4, 6, (uint32_t)-1 }, 2 } /* PS level 5 */ }, /* 3 <= DTIM <= 10 */ { { 0, 0, { 0, 0, 0, 0, 0 }, 0 }, /* CAM */ { 200, 500, { 1, 2, 3, 4, 4 }, 0 }, /* PS level 1 */ { 200, 300, { 1, 2, 3, 4, 7 }, 0 }, /* PS level 2 */ { 50, 100, { 2, 4, 6, 7, 9 }, 0 }, /* PS level 3 */ { 50, 25, { 2, 4, 6, 9, 10 }, 1 }, /* PS level 4 */ { 25, 25, { 2, 4, 7, 10, 10 }, 2 } /* PS level 5 */ }, /* DTIM >= 11 */ { { 0, 0, { 0, 0, 0, 0, 0 }, 0 }, /* CAM */ { 200, 500, { 1, 2, 3, 4, (uint32_t)-1 }, 0 }, /* PS level 1 */ { 200, 300, { 2, 4, 6, 7, (uint32_t)-1 }, 0 }, /* PS level 2 */ { 50, 100, { 2, 7, 9, 9, (uint32_t)-1 }, 0 }, /* PS level 3 */ { 50, 25, { 2, 7, 9, 9, (uint32_t)-1 }, 0 }, /* PS level 4 */ { 25, 25, { 4, 7, 10, 10, (uint32_t)-1 }, 0 } /* PS level 5 */ } }; struct iwn_sensitivity_limits { uint32_t min_ofdm_x1; uint32_t max_ofdm_x1; uint32_t min_ofdm_mrc_x1; uint32_t max_ofdm_mrc_x1; uint32_t min_ofdm_x4; uint32_t max_ofdm_x4; uint32_t min_ofdm_mrc_x4; uint32_t max_ofdm_mrc_x4; uint32_t min_cck_x4; uint32_t max_cck_x4; uint32_t min_cck_mrc_x4; uint32_t max_cck_mrc_x4; uint32_t min_energy_cck; uint32_t energy_cck; uint32_t energy_ofdm; }; /* * RX sensitivity limits (values obtained from the reference driver.) */ static const struct iwn_sensitivity_limits iwn4965_sensitivity_limits = { 105, 140, 220, 270, 85, 120, 170, 210, 125, 200, 200, 400, 97, 100, 100 }; static const struct iwn_sensitivity_limits iwn5000_sensitivity_limits = { 120, 120, /* min = max for performance bug in DSP. */ 240, 240, /* min = max for performance bug in DSP. */ 90, 120, 170, 210, 125, 200, 170, 400, 95, 95, 95 }; static const struct iwn_sensitivity_limits iwn5150_sensitivity_limits = { 105, 105, /* min = max for performance bug in DSP. */ 220, 220, /* min = max for performance bug in DSP. */ 90, 120, 170, 210, 125, 200, 170, 400, 95, 95, 95 }; static const struct iwn_sensitivity_limits iwn1000_sensitivity_limits = { 120, 155, 240, 290, 90, 120, 170, 210, 125, 200, 170, 400, 95, 95, 95 }; static const struct iwn_sensitivity_limits iwn6000_sensitivity_limits = { 105, 110, 192, 232, 80, 145, 128, 232, 125, 175, 160, 310, 97, 97, 100 }; static const struct iwn_sensitivity_limits iwn2000_sensitivity_limits = { 105, 110, 192, 232, 80, 145, 128, 232, 125, 175, 160, 310, 97, 97, 100 }; /* Map TID to TX scheduler's FIFO. */ #define IWN_NUM_AMPDU_TID 8 #define IWN_NONQOS_TID IWN_NUM_AMPDU_TID #define IWN_TX_FIFO_BK 0 #define IWN_TX_FIFO_BE 1 #define IWN_TX_FIFO_VI 2 #define IWN_TX_FIFO_VO 3 static const uint8_t iwn_tid2fifo[IWN_NUM_AMPDU_TID] = { IWN_TX_FIFO_VO, IWN_TX_FIFO_VI, IWN_TX_FIFO_BE, IWN_TX_FIFO_BK, IWN_TX_FIFO_VO, IWN_TX_FIFO_VI, IWN_TX_FIFO_BE, IWN_TX_FIFO_BK }; /* WiFi/WiMAX coexist event priority table for 6050. */ static const struct iwn5000_wimax_event iwn6050_wimax_events[] = { { 0x04, 0x03, 0x00, 0x00 }, { 0x04, 0x03, 0x00, 0x03 }, { 0x04, 0x03, 0x00, 0x03 }, { 0x04, 0x03, 0x00, 0x03 }, { 0x04, 0x03, 0x00, 0x00 }, { 0x04, 0x03, 0x00, 0x07 }, { 0x04, 0x03, 0x00, 0x00 }, { 0x04, 0x03, 0x00, 0x03 }, { 0x04, 0x03, 0x00, 0x03 }, { 0x04, 0x03, 0x00, 0x00 }, { 0x06, 0x03, 0x00, 0x07 }, { 0x04, 0x03, 0x00, 0x00 }, { 0x06, 0x06, 0x00, 0x03 }, { 0x04, 0x03, 0x00, 0x07 }, { 0x04, 0x03, 0x00, 0x00 }, { 0x04, 0x03, 0x00, 0x00 } }; /* Firmware errors. */ static const char * const iwn_fw_errmsg[] = { "OK", "FAIL", "BAD_PARAM", "BAD_CHECKSUM", "NMI_INTERRUPT_WDG", "SYSASSERT", "FATAL_ERROR", "BAD_COMMAND", "HW_ERROR_TUNE_LOCK", "HW_ERROR_TEMPERATURE", "ILLEGAL_CHAN_FREQ", "VCC_NOT_STABLE", "FH_ERROR", "NMI_INTERRUPT_HOST", "NMI_INTERRUPT_ACTION_PT", "NMI_INTERRUPT_UNKNOWN", "UCODE_VERSION_MISMATCH", "HW_ERROR_ABS_LOCK", "HW_ERROR_CAL_LOCK_FAIL", "NMI_INTERRUPT_INST_ACTION_PT", "NMI_INTERRUPT_DATA_ACTION_PT", "NMI_TRM_HW_ER", "NMI_INTERRUPT_TRM", "NMI_INTERRUPT_BREAKPOINT", "DEBUG_0", "DEBUG_1", "DEBUG_2", "DEBUG_3", "ADVANCED_SYSASSERT" }; /* Find least significant bit that is set. */ #define IWN_LSB(x) ((((x) - 1) & (x)) ^ (x)) #define IWN_READ(sc, reg) \ bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg)) #define IWN_WRITE(sc, reg, val) \ bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val)) #define IWN_WRITE_1(sc, reg, val) \ bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val)) #define IWN_SETBITS(sc, reg, mask) \ IWN_WRITE(sc, reg, IWN_READ(sc, reg) | (mask)) #define IWN_CLRBITS(sc, reg, mask) \ IWN_WRITE(sc, reg, IWN_READ(sc, reg) & ~(mask)) #define IWN_BARRIER_WRITE(sc) \ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ BUS_SPACE_BARRIER_WRITE) #define IWN_BARRIER_READ_WRITE(sc) \ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) #define IWN_MIN_DBM -100 #define IWN_MAX_DBM -33 /* realistic guess */ ================================================ FILE: itlwm/hal_iwn/if_iwnvar.h ================================================ /* * Copyright (C) 2020 pigworlds * * 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. */ /* $OpenBSD: if_iwnvar.h,v 1.42 2021/11/12 11:41:04 stsp Exp $ */ /*- * Copyright (c) 2007, 2008 * Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include struct iwn_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; uint64_t wr_tsft; uint8_t wr_flags; uint8_t wr_rate; uint16_t wr_chan_freq; uint16_t wr_chan_flags; int8_t wr_dbm_antsignal; int8_t wr_dbm_antnoise; } __packed; #define IWN_RX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_TSFT) | \ (1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL) | \ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)) struct iwn_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; uint8_t wt_flags; uint8_t wt_rate; uint16_t wt_chan_freq; uint16_t wt_chan_flags; } __packed; #define IWN_TX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL)) struct iwn_dma_info { IOBufferMemoryDescriptor* buffer; bus_addr_t paddr; void *vaddr; bus_size_t size; IOBufferMemoryDescriptor *bmd; IODMACommand *cmd; }; struct iwn_tx_data { bus_dmamap_t map; bus_addr_t cmd_paddr; bus_addr_t scratch_paddr; mbuf_t m; struct ieee80211_node *ni; int totlen; /* A-MPDU subframes */ int ampdu_txmcs; int ampdu_nframes; }; struct iwn_tx_ring { struct iwn_dma_info desc_dma; struct iwn_dma_info cmd_dma; struct iwn_tx_desc *desc; struct iwn_tx_cmd *cmd; struct iwn_tx_data data[IWN_TX_RING_COUNT]; int qid; int queued; int cur; int read; }; struct iwn_softc; struct iwn_rx_data { mbuf_t m; bus_dmamap_t map; }; struct iwn_rx_ring { struct iwn_dma_info desc_dma; struct iwn_dma_info stat_dma; uint32_t *desc; struct iwn_rx_status *stat; struct iwn_rx_data data[IWN_RX_RING_COUNT]; int cur; }; struct iwn_node { struct ieee80211_node ni; /* must be the first */ struct ieee80211_amrr_node amn; struct ieee80211_ra_node rn; uint16_t disable_tid; uint8_t id; uint8_t ridx[IEEE80211_RATE_MAXSIZE]; uint32_t next_ampdu_id; int lq_rate_mismatch; }; struct iwn_calib_state { uint8_t state; #define IWN_CALIB_STATE_INIT 0 #define IWN_CALIB_STATE_ASSOC 1 #define IWN_CALIB_STATE_RUN 2 u_int nbeacons; uint32_t noise[3]; uint32_t rssi[3]; uint32_t ofdm_x1; uint32_t ofdm_mrc_x1; uint32_t ofdm_x4; uint32_t ofdm_mrc_x4; uint32_t cck_x4; uint32_t cck_mrc_x4; uint32_t bad_plcp_ofdm; uint32_t fa_ofdm; uint32_t bad_plcp_cck; uint32_t fa_cck; uint32_t low_fa; uint8_t cck_state; #define IWN_CCK_STATE_INIT 0 #define IWN_CCK_STATE_LOFA 1 #define IWN_CCK_STATE_HIFA 2 uint8_t noise_samples[20]; u_int cur_noise_sample; uint8_t noise_ref; uint32_t energy_samples[10]; u_int cur_energy_sample; uint32_t energy_cck; }; struct iwn_calib_info { uint8_t *buf; u_int len; }; struct iwn_fw_part { const uint8_t *text; uint32_t textsz; const uint8_t *data; uint32_t datasz; }; struct iwn_fw_info { u_char *data; size_t size; struct iwn_fw_part init; struct iwn_fw_part main; struct iwn_fw_part boot; }; struct iwn_ops { int (*load_firmware)(struct iwn_softc *); void (*read_eeprom)(struct iwn_softc *); int (*post_alive)(struct iwn_softc *); int (*nic_config)(struct iwn_softc *); void (*reset_sched)(struct iwn_softc *, int, int); void (*update_sched)(struct iwn_softc *, int, int, uint8_t, uint16_t); void (*update_rxon)(struct iwn_softc *); int (*get_temperature)(struct iwn_softc *); int (*get_rssi)(const struct iwn_rx_stat *); int (*set_txpower)(struct iwn_softc *, int); int (*init_gains)(struct iwn_softc *); int (*set_gains)(struct iwn_softc *); int (*add_node)(struct iwn_softc *, struct iwn_node_info *, int); void (*tx_done)(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); void (*ampdu_tx_start)(struct iwn_softc *, struct ieee80211_node *, uint8_t, uint16_t); void (*ampdu_tx_stop)(struct iwn_softc *, uint8_t, uint16_t); }; struct iwn_tx_ba { struct iwn_node * wn; }; struct iwn_softc { struct device sc_dev; struct ieee80211com sc_ic; int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int); pci_intr_handle_t ih; struct ieee80211_amrr amrr; uint8_t fixed_ridx; bus_dma_tag_t sc_dmat; // struct rwlock sc_rwlock; u_int sc_flags; #define IWN_FLAG_HAS_5GHZ (1 << 0) #define IWN_FLAG_HAS_OTPROM (1 << 1) #define IWN_FLAG_CALIB_DONE (1 << 2) #define IWN_FLAG_USE_ICT (1 << 3) #define IWN_FLAG_INTERNAL_PA (1 << 4) #define IWN_FLAG_HAS_11N (1 << 6) #define IWN_FLAG_ENH_SENS (1 << 7) #define IWN_FLAG_ADV_BT_COEX (1 << 8) #define IWN_FLAG_BGSCAN (1 << 9) #define IWN_FLAG_SCANNING (1 << 10) uint8_t hw_type; struct iwn_ops ops; const char *fwname; const struct iwn_sensitivity_limits *limits; int ntxqs; int first_agg_txq; int agg_queue_mask; int ndmachnls; uint8_t broadcast_id; int rxonsz; int schedsz; uint32_t fw_text_maxsz; uint32_t fw_data_maxsz; uint32_t fwsz; bus_size_t sched_txfact_addr; /* TX scheduler rings. */ struct iwn_dma_info sched_dma; uint16_t *sched; uint32_t sched_base; /* "Keep Warm" page. */ struct iwn_dma_info kw_dma; /* Firmware DMA transfer. */ struct iwn_dma_info fw_dma; /* ICT table. */ struct iwn_dma_info ict_dma; uint32_t *ict; int ict_cur; /* TX/RX rings. */ struct iwn_tx_ring txq[IWN5000_NTXQUEUES]; struct iwn_rx_ring rxq; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; IOInterruptEventSource *sc_ih; pci_chipset_tag_t sc_pct; pcitag_t sc_pcitag; bus_size_t sc_sz; int sc_cap_off; /* PCIe Capabilities. */ CTimeout * calib_to; int calib_cnt; struct iwn_calib_state calib; struct task init_task; struct iwn_fw_info fw; struct iwn_calib_info calibcmd[5]; uint32_t errptr; uint8_t bss_node_addr[IEEE80211_ADDR_LEN]; struct iwn_rx_stat last_rx_stat; int last_rx_valid; #define IWN_LAST_RX_VALID 0x01 #define IWN_LAST_RX_AMPDU 0x02 struct iwn_ucode_info ucode_info; struct iwn_rxon rxon; uint32_t rx_stats_flags; uint32_t rawtemp; int temp; int noise; uint32_t qfullmsk; uint32_t prom_base; struct iwn4965_eeprom_band bands[IWN_NBANDS]; uint16_t rfcfg; uint8_t calib_ver; char eeprom_domain[4]; uint32_t eeprom_crystal; int16_t eeprom_temp; int16_t eeprom_voltage; int16_t eeprom_rawtemp; int8_t maxpwr2GHz; int8_t maxpwr5GHz; int8_t maxpwr[IEEE80211_CHAN_MAX]; int8_t maxpwr40[IEEE80211_CHAN_MAX]; int8_t enh_maxpwr[35]; uint8_t reset_noise_gain; uint8_t noise_gain; uint32_t tlv_feature_flags; int32_t temp_off; uint32_t int_mask; uint8_t ntxchains; uint8_t nrxchains; uint8_t txchainmask; uint8_t rxchainmask; uint8_t chainmask; int sc_tx_timer; struct iwn_tx_ba sc_tx_ba[IEEE80211_NUM_TID]; #if NBPFILTER > 0 caddr_t sc_drvbpf; union { struct iwn_rx_radiotap_header th; uint8_t pad[IEEE80211_RADIOTAP_HDRLEN]; } sc_rxtapu; #define sc_rxtap sc_rxtapu.th int sc_rxtap_len; union { struct iwn_tx_radiotap_header th; uint8_t pad[IEEE80211_RADIOTAP_HDRLEN]; } sc_txtapu; #define sc_txtap sc_txtapu.th int sc_txtap_len; #endif }; ================================================ FILE: itlwm/hal_iwx/ItlIwx.cpp ================================================ /* * 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. */ /* $OpenBSD: if_iwx.c,v 1.45 2020/10/11 07:05:28 mpi Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * ****************************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***************************************************************************** */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ItlIwx.hpp" #include #include #include #include #include #include #include #include #include #include #include #define super ItlHalService OSDefineMetaClassAndStructors(ItlIwx, ItlHalService) #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) #define IC2IFP(_ic_) (&(_ic_)->ic_if) #define IWX_DEBUG #ifdef IWX_DEBUG #define DPRINTF(x) do { if (iwx_debug > 0) XYLog x; } while (0) #define DPRINTFN(n, x) do { if (iwx_debug >= (n)) XYLog x; } while (0) int iwx_debug = 1; #else #define DPRINTF(x) do { ; } while (0) #define DPRINTFN(n, x) do { ; } while (0) #endif bool ItlIwx::attach(IOPCIDevice *device) { pci.pa_tag = device; pci.workloop = getMainWorkLoop(); if (!iwx_attach(&com, &pci)) { detach(device); releaseAll(); return false; } return true; } void ItlIwx:: detach(IOPCIDevice *device) { struct _ifnet *ifp = &com.sc_ic.ic_ac.ac_if; struct iwx_softc *sc = &com; for (int txq_i = 0; txq_i < nitems(sc->txq); txq_i++) iwx_free_tx_ring(sc, &sc->txq[txq_i]); iwx_free_rx_ring(sc, &sc->rxq); iwx_dma_contig_free(&sc->ict_dma); iwx_dma_contig_free(&com.ctxt_info_dma); ieee80211_ifdetach(ifp); taskq_destroy(systq); taskq_destroy(com.sc_nswq); releaseAll(); } void ItlIwx:: releaseAll() { pci_intr_handle *intrHandler = com.ih; if (intrHandler) { if (intrHandler->intr && intrHandler->workloop) { // intrHandler->intr->disable(); intrHandler->workloop->removeEventSource(intrHandler->intr); intrHandler->intr->release(); } intrHandler->intr = NULL; intrHandler->workloop = NULL; intrHandler->arg = NULL; intrHandler->dev = NULL; intrHandler->func = NULL; intrHandler->release(); com.ih = NULL; } pci.pa_tag = NULL; pci.workloop = NULL; } void ItlIwx::free() { XYLog("%s\n", __FUNCTION__); super::free(); } ItlDriverInfo *ItlIwx:: getDriverInfo() { return this; } ItlDriverController *ItlIwx:: getDriverController() { return this; } IOReturn ItlIwx::enable(IONetworkInterface *netif) { XYLog("%s\n", __PRETTY_FUNCTION__); struct _ifnet *ifp = &com.sc_ic.ic_ac.ac_if; if (ifp->if_flags & IFF_UP) { XYLog("%s already in activating state\n", __FUNCTION__); return kIOReturnSuccess; } ifp->if_flags |= IFF_UP; iwx_activate(&com, DVACT_RESUME); iwx_activate(&com, DVACT_WAKEUP); return kIOReturnSuccess; } IOReturn ItlIwx::disable(IONetworkInterface *netif) { XYLog("%s\n", __FUNCTION__); struct _ifnet *ifp = &com.sc_ic.ic_ac.ac_if; if (!(ifp->if_flags & IFF_UP)) { XYLog("%s already in diactivating state\n", __FUNCTION__); return kIOReturnSuccess; } ifp->if_flags &= ~IFF_UP; iwx_activate(&com, DVACT_QUIESCE); return kIOReturnSuccess; } void ItlIwx:: clearScanningFlags() { com.sc_flags &= ~(IWX_FLAG_SCANNING | IWX_FLAG_BGSCAN); } IOReturn ItlIwx:: setMulticastList(IOEthernetAddress *addr, int count) { struct ieee80211com *ic = &com.sc_ic; struct iwx_mcast_filter_cmd *cmd; int len; uint8_t addr_count; int err; if (ic->ic_state != IEEE80211_S_RUN || ic->ic_bss == NULL) return kIOReturnError; addr_count = count; if (count > IWX_MAX_MCAST_FILTERING_ADDRESSES) addr_count = 0; if (addr == NULL) addr_count = 0; len = roundup(sizeof(struct iwx_mcast_filter_cmd) + addr_count * ETHER_ADDR_LEN, 4); XYLog("%s multicast count=%d bssid=%s\n", __FUNCTION__, count, ether_sprintf(ic->ic_bss->ni_bssid)); cmd = (struct iwx_mcast_filter_cmd *)malloc(len, 0, 0); if (!cmd) return kIOReturnError; cmd->pass_all = addr_count == 0; cmd->count = addr_count; cmd->port_id = 0; IEEE80211_ADDR_COPY(cmd->bssid, ic->ic_bss->ni_bssid); if (addr_count > 0) memcpy(cmd->addr_list, addr->bytes, ETHER_ADDR_LEN * cmd->count); err = iwx_send_cmd_pdu(&com, IWX_MCAST_FILTER_CMD, IWX_CMD_ASYNC, len, cmd); ::free(cmd); return err ? kIOReturnError : kIOReturnSuccess; } const char *ItlIwx:: getFirmwareVersion() { return com.sc_fwver; } const char *ItlIwx:: getFirmwareName() { return com.sc_fwname; } UInt32 ItlIwx:: supportedFeatures() { return kIONetworkFeatureMultiPages; } const char *ItlIwx:: getFirmwareCountryCode() { return com.sc_fw_mcc; } uint32_t ItlIwx:: getTxQueueSize() { return com.sc_device_family >= IWX_DEVICE_FAMILY_AX210 ? IWX_TFD_QUEUE_SIZE_MAX_GEN3 : IWX_DEFAULT_QUEUE_SIZE; } int16_t ItlIwx:: getBSSNoise() { return com.sc_noise; } bool ItlIwx:: is5GBandSupport() { return com.sc_nvm.sku_cap_band_52GHz_enable; } int ItlIwx:: getTxNSS() { return iwx_mimo_enabled(&com) && (com.sc_ic.ic_bss != NULL && com.sc_ic.ic_bss->ni_rx_nss > 1) ? 2 : 1; } struct ieee80211com *ItlIwx:: get80211Controller() { return &com.sc_ic; } #define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) #define M_CANFAIL 0x0004 void *ItlIwx:: mallocarray(size_t nmemb, size_t size, int type, int flags) { if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 && SIZE_MAX / nmemb < size) { if (flags & M_CANFAIL) return (NULL); panic("mallocarray: overflow %zu * %zu", nmemb, size); } return (malloc(size * nmemb, type, flags)); } const uint8_t iwx_nvm_channels_8000[] = { /* 2.4 GHz */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 5 GHz */ 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, 177, 181 }; static const uint8_t iwx_nvm_channels_uhb[] = { /* 2.4 GHz */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 5 GHz */ 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, 177, 181, #ifdef notyet /* 6-7 GHz */ 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185, 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233 #endif }; #define IWX_NUM_2GHZ_CHANNELS 14 #define IWX_FIRST_2GHZ_HT_MINUS 5 #define IWX_LAST_2GHZ_HT_PLUS 9 const struct iwx_rate { uint16_t rate; uint8_t plcp; uint8_t ht_plcp; } iwx_rates[] = { /* Legacy */ /* HT */ { 2, IWX_RATE_1M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, { 4, IWX_RATE_2M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, { 11, IWX_RATE_5M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, { 22, IWX_RATE_11M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, { 12, IWX_RATE_6M_PLCP, IWX_RATE_HT_SISO_MCS_0_PLCP }, { 18, IWX_RATE_9M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, { 24, IWX_RATE_12M_PLCP, IWX_RATE_HT_SISO_MCS_1_PLCP }, { 26, IWX_RATE_12M_PLCP, IWX_RATE_HT_MIMO2_MCS_8_PLCP }, { 36, IWX_RATE_18M_PLCP, IWX_RATE_HT_SISO_MCS_2_PLCP }, { 48, IWX_RATE_24M_PLCP, IWX_RATE_HT_SISO_MCS_3_PLCP }, { 52, IWX_RATE_24M_PLCP, IWX_RATE_HT_MIMO2_MCS_9_PLCP }, { 72, IWX_RATE_36M_PLCP, IWX_RATE_HT_SISO_MCS_4_PLCP }, { 78, IWX_RATE_36M_PLCP, IWX_RATE_HT_MIMO2_MCS_10_PLCP }, { 96, IWX_RATE_48M_PLCP, IWX_RATE_HT_SISO_MCS_5_PLCP }, { 104, IWX_RATE_48M_PLCP, IWX_RATE_HT_MIMO2_MCS_11_PLCP }, { 108, IWX_RATE_54M_PLCP, IWX_RATE_HT_SISO_MCS_6_PLCP }, { 128, IWX_RATE_54M_PLCP, IWX_RATE_HT_SISO_MCS_7_PLCP }, { 156, IWX_RATE_54M_PLCP, IWX_RATE_HT_MIMO2_MCS_12_PLCP }, { 208, IWX_RATE_54M_PLCP, IWX_RATE_HT_MIMO2_MCS_13_PLCP }, { 234, IWX_RATE_54M_PLCP, IWX_RATE_HT_MIMO2_MCS_14_PLCP }, { 260, IWX_RATE_54M_PLCP, IWX_RATE_HT_MIMO2_MCS_15_PLCP }, }; #define IWX_RIDX_CCK 0 #define IWX_RIDX_OFDM 4 #define IWX_RIDX_MAX (nitems(iwx_rates)-1) #define IWX_RIDX_IS_CCK(_i_) ((_i_) < IWX_RIDX_OFDM) #define IWX_RIDX_IS_OFDM(_i_) ((_i_) >= IWX_RIDX_OFDM) #define IWX_RVAL_IS_OFDM(_i_) ((_i_) >= 12 && (_i_) != 22) /* Convert an MCS index into an iwx_rates[] index. */ const int iwx_mcs2ridx[] = { IWX_RATE_MCS_0_INDEX, IWX_RATE_MCS_1_INDEX, IWX_RATE_MCS_2_INDEX, IWX_RATE_MCS_3_INDEX, IWX_RATE_MCS_4_INDEX, IWX_RATE_MCS_5_INDEX, IWX_RATE_MCS_6_INDEX, IWX_RATE_MCS_7_INDEX, IWX_RATE_MCS_8_INDEX, IWX_RATE_MCS_9_INDEX, IWX_RATE_MCS_10_INDEX, IWX_RATE_MCS_11_INDEX, IWX_RATE_MCS_12_INDEX, IWX_RATE_MCS_13_INDEX, IWX_RATE_MCS_14_INDEX, IWX_RATE_MCS_15_INDEX, }; #define IWX_LAST_HE_RATE IWX_RATE_MCS_11_INDEX #define IWL_RATE_COUNT IWX_LAST_HE_RATE #define IWX_MAX_MCS_DISPLAY_SIZE 12 #define IWL_RATE_60M_PLCP 3 enum { IWX_RATE_INVM_INDEX = IWX_RATE_COUNT, IWX_RATE_INVALID = IWX_RATE_COUNT, }; struct iwx_rate_mcs_info { char mbps[IWX_MAX_MCS_DISPLAY_SIZE]; char mcs[IWX_MAX_MCS_DISPLAY_SIZE]; }; /* mbps, mcs */ static const struct iwx_rate_mcs_info iwx_rate_mcs[IWX_RATE_COUNT] = { { "1", "BPSK DSSS"}, { "2", "QPSK DSSS"}, {"5.5", "BPSK CCK"}, { "11", "QPSK CCK"}, { "6", "BPSK 1/2"}, { "9", "BPSK 1/2"}, { "12", "QPSK 1/2"}, { "18", "QPSK 3/4"}, { "24", "16QAM 1/2"}, { "36", "16QAM 3/4"}, { "48", "64QAM 2/3"}, { "54", "64QAM 3/4"}, { "60", "64QAM 5/6"}, }; #define IWX_MCS_INDEX_PER_STREAM (8) static const char *iwx_rs_pretty_ant(u8 ant) { static const char * const ant_name[] = { [IWX_ANT_NONE] = "None", [IWX_ANT_A] = "A", [IWX_ANT_B] = "B", [IWX_ANT_AB] = "AB", }; if (ant > ARRAY_SIZE(ant_name)) return "UNKNOWN"; return ant_name[ant]; } static const char *iwx_rs_pretty_bw(u8 bw) { static const char * const pretty_bw[] = { "20Mhz", "40Mhz", "80Mhz", "160 Mhz", "320Mhz", }; if (bw > ARRAY_SIZE(pretty_bw)) return "UNKNOWN"; return pretty_bw[bw]; } static uint8_t iwx_rs_extract_rate(uint32_t rate_n_flags) { /* also works for HT because bits 7:6 are zero there */ return (uint8_t)(rate_n_flags & IWX_RATE_LEGACY_RATE_MSK_V1); } static int iwx_hwrate_to_plcp_idx(uint32_t rate_n_flags) { int idx = 0; if (rate_n_flags & IWX_RATE_MCS_HT_MSK_V1) { idx = rate_n_flags & IWX_RATE_HT_MCS_RATE_CODE_MSK_V1; idx += IWX_RATE_MCS_0_INDEX; /* skip 9M not supported in HT*/ if (idx >= IWX_RATE_9M_INDEX) idx += 1; if ((idx >= IWX_FIRST_HT_RATE) && (idx <= IWX_LAST_HT_RATE)) return idx; } else if (rate_n_flags & IWX_RATE_MCS_VHT_MSK_V1 || rate_n_flags & IWX_RATE_MCS_HE_MSK_V1) { idx = rate_n_flags & IWX_RATE_VHT_MCS_RATE_CODE_MSK; idx += IWX_RATE_MCS_0_INDEX; /* skip 9M not supported in VHT*/ if (idx >= IWX_RATE_9M_INDEX) idx++; if ((idx >= IWX_FIRST_VHT_RATE) && (idx <= IWX_LAST_VHT_RATE)) return idx; if ((rate_n_flags & IWX_RATE_MCS_HE_MSK_V1) && (idx <= IWX_LAST_HE_RATE)) return idx; } else { /* legacy rate format, search for match in table */ uint8_t legacy_rate = iwx_rs_extract_rate(rate_n_flags); for (idx = 0; idx < ARRAY_SIZE(iwx_rates); idx++) if (iwx_rates[idx].plcp == legacy_rate) return idx; } return IWX_RATE_INVALID; } static int iwx_rs_pretty_print_rate_v1(char *buf, int bufsz, const u32 rate) { char *type; uint8_t mcs = 0, nss = 0; uint8_t ant = (rate & IWX_RATE_MCS_ANT_AB_MSK) >> IWX_RATE_MCS_ANT_POS; uint32_t bw = (rate & IWX_RATE_MCS_CHAN_WIDTH_MSK_V1) >> IWX_RATE_MCS_CHAN_WIDTH_POS; if (!(rate & IWX_RATE_MCS_HT_MSK_V1) && !(rate & IWX_RATE_MCS_VHT_MSK_V1) && !(rate & IWX_RATE_MCS_HE_MSK_V1)) { int index = iwx_hwrate_to_plcp_idx(rate); return snprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps", iwx_rs_pretty_ant(ant), index == IWX_RATE_INVALID ? "BAD" : iwx_rate_mcs[index].mbps); } if (rate & IWX_RATE_MCS_VHT_MSK_V1) { type = "VHT"; mcs = rate & IWX_RATE_VHT_MCS_RATE_CODE_MSK; nss = ((rate & IWX_RATE_VHT_MCS_NSS_MSK) >> IWX_RATE_VHT_MCS_NSS_POS) + 1; } else if (rate & IWX_RATE_MCS_HT_MSK_V1) { type = "HT"; mcs = rate & IWX_RATE_HT_MCS_INDEX_MSK_V1; nss = ((rate & IWX_RATE_HT_MCS_NSS_MSK_V1) >> IWX_RATE_HT_MCS_NSS_POS_V1) + 1; } else if (rate & IWX_RATE_MCS_HE_MSK_V1) { type = "HE"; mcs = rate & IWX_RATE_VHT_MCS_RATE_CODE_MSK; nss = ((rate & IWX_RATE_VHT_MCS_NSS_MSK) >> IWX_RATE_VHT_MCS_NSS_POS) + 1; } else { type = "Unknown"; /* shouldn't happen */ } return snprintf(buf, bufsz, "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s", rate, type, iwx_rs_pretty_ant(ant), iwx_rs_pretty_bw(bw), mcs, nss, (rate & IWX_RATE_MCS_SGI_MSK_V1) ? "SGI " : "NGI ", (rate & IWX_RATE_MCS_STBC_MSK) ? "STBC " : "", (rate & IWX_RATE_MCS_LDPC_MSK_V1) ? "LDPC " : "", (rate & IWX_RATE_HE_DUAL_CARRIER_MODE_MSK) ? "DCM " : "", (rate & IWX_RATE_MCS_BF_MSK) ? "BF " : ""); } static bool iwx_he_is_sgi(u32 rate_n_flags) { u32 type = rate_n_flags & IWX_RATE_MCS_HE_TYPE_MSK; u32 ltf_gi = rate_n_flags & IWX_RATE_MCS_HE_GI_LTF_MSK; if (type == IWX_RATE_MCS_HE_TYPE_SU || type == IWX_RATE_MCS_HE_TYPE_EXT_SU) return ltf_gi == IWX_RATE_MCS_HE_SU_4_LTF_08_GI; return false; } static int iwx_rs_pretty_print_rate(char *buf, int bufsz, const uint32_t rate) { char *type; u8 mcs = 0, nss = 0; u8 ant = (rate & IWX_RATE_MCS_ANT_AB_MSK) >> IWX_RATE_MCS_ANT_POS; u32 bw = (rate & IWX_RATE_MCS_CHAN_WIDTH_MSK) >> IWX_RATE_MCS_CHAN_WIDTH_POS; u32 format = rate & IWX_RATE_MCS_MOD_TYPE_MSK; bool sgi; if (format == IWX_RATE_MCS_CCK_MSK || format == IWX_RATE_MCS_LEGACY_OFDM_MSK) { int legacy_rate = rate & IWX_RATE_LEGACY_RATE_MSK; int index = format == IWX_RATE_MCS_CCK_MSK ? legacy_rate : legacy_rate + IWX_FIRST_OFDM_RATE; return snprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps", iwx_rs_pretty_ant(ant), index == IWX_RATE_INVALID ? "BAD" : iwx_rate_mcs[index].mbps); } if (format == IWX_RATE_MCS_VHT_MSK) type = "VHT"; else if (format == IWX_RATE_MCS_HT_MSK) type = "HT"; else if (format == IWX_RATE_MCS_HE_MSK) type = "HE"; else if (format == IWX_RATE_MCS_EHT_MSK) type = "EHT"; else type = "Unknown"; /* shouldn't happen */ mcs = format == IWX_RATE_MCS_HT_MSK ? IWX_RATE_HT_MCS_INDEX(rate) : rate & IWX_RATE_MCS_CODE_MSK; nss = ((rate & IWX_RATE_MCS_NSS_MSK) >> IWX_RATE_MCS_NSS_POS) + 1; sgi = format == IWX_RATE_MCS_HE_MSK ? iwx_he_is_sgi(rate) : rate & IWX_RATE_MCS_SGI_MSK; return snprintf(buf, bufsz, "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s", rate, type, iwx_rs_pretty_ant(ant), iwx_rs_pretty_bw(bw), mcs, nss, (sgi) ? "SGI " : "NGI ", (rate & IWX_RATE_MCS_STBC_MSK) ? "STBC " : "", (rate & IWX_RATE_MCS_LDPC_MSK) ? "LDPC " : "", (rate & IWX_RATE_HE_DUAL_CARRIER_MODE_MSK) ? "DCM " : "", (rate & IWX_RATE_MCS_BF_MSK) ? "BF " : ""); } #if NBPFILTER > 0 void iwx_radiotap_attach(struct iwx_softc *); #endif uint8_t ItlIwx:: iwx_lookup_cmd_ver(struct iwx_softc *sc, uint8_t grp, uint8_t cmd) { const struct iwx_fw_cmd_version *entry; int i; for (i = 0; i < sc->n_cmd_versions; i++) { entry = &sc->cmd_versions[i]; if (entry->group == grp && entry->cmd == cmd) return entry->cmd_ver; } return IWX_FW_CMD_VER_UNKNOWN; } uint8_t ItlIwx:: iwx_lookup_notif_ver(struct iwx_softc *sc, uint8_t grp, uint8_t cmd) { const struct iwx_fw_cmd_version *entry; int i; for (i = 0; i < sc->n_cmd_versions; i++) { entry = &sc->cmd_versions[i]; if (entry->group == grp && entry->cmd == cmd) return entry->notif_ver; } return IWX_FW_CMD_VER_UNKNOWN; } uint32_t ItlIwx:: iwx_lmac_id(struct iwx_softc *sc, ieee80211_channel *chan) { if (!isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_CDB_SUPPORT) || IEEE80211_IS_CHAN_2GHZ(chan)) return IWX_LMAC_24G_INDEX; return IWX_LMAC_5G_INDEX; } int ItlIwx:: iwx_store_cscheme(struct iwx_softc *sc, uint8_t *data, size_t dlen) { struct iwx_fw_cscheme_list *l = (struct iwx_fw_cscheme_list *)data; if (dlen < sizeof(*l) || dlen < sizeof(l->size) + l->size * sizeof(*l->cs)) return EINVAL; /* we don't actually store anything for now, always use s/w crypto */ return 0; } int ItlIwx:: iwx_ctxt_info_alloc_dma(struct iwx_softc *sc, const struct iwx_fw_onesect *sec, struct iwx_dma_info *dram) { int err = iwx_dma_contig_alloc(sc->sc_dmat, dram, sec->fws_len, 0); if (err) { XYLog("%s: could not allocate context info DMA memory\n", DEVNAME(sc)); return err; } memcpy(dram->vaddr, sec->fws_data, sec->fws_len); return 0; } void ItlIwx:: iwx_ctxt_info_free_paging(struct iwx_softc *sc) { struct iwx_self_init_dram *dram = &sc->init_dram; int i; if (!dram->paging) return; /* free paging*/ for (i = 0; i < dram->paging_cnt; i++) iwx_dma_contig_free(&dram->paging[i]); IOFree(dram->paging, dram->paging_cnt * sizeof(*dram->paging)); dram->paging_cnt = 0; dram->paging = NULL; } int ItlIwx:: iwx_get_num_sections(const struct iwx_fw_sects *fws, int start) { int i = 0; while (start < fws->fw_count && fws->fw_sect[start].fws_devoff != IWX_CPU1_CPU2_SEPARATOR_SECTION && fws->fw_sect[start].fws_devoff != IWX_PAGING_SEPARATOR_SECTION) { start++; i++; } return i; } int ItlIwx:: iwx_init_fw_sec(struct iwx_softc *sc, const struct iwx_fw_sects *fws, struct iwx_context_info_dram *ctxt_dram) { struct iwx_self_init_dram *dram = &sc->init_dram; int i, ret, fw_cnt = 0; KASSERT(dram->paging == NULL, "dram->paging == NULL"); dram->lmac_cnt = iwx_get_num_sections(fws, 0); /* add 1 due to separator */ dram->umac_cnt = iwx_get_num_sections(fws, dram->lmac_cnt + 1); /* add 2 due to separators */ dram->paging_cnt = iwx_get_num_sections(fws, dram->lmac_cnt + dram->umac_cnt + 2); dram->fw = (struct iwx_dma_info *)kcalloc(dram->umac_cnt + dram->lmac_cnt, sizeof(*dram->fw)); if (!dram->fw) { XYLog("%s: could not allocate memory for firmware sections\n", DEVNAME(sc)); return ENOMEM; } dram->paging = (struct iwx_dma_info *)kcalloc(dram->paging_cnt, sizeof(*dram->paging)); if (!dram->paging) { XYLog("%s: could not allocate memory for firmware paging\n", DEVNAME(sc)); return ENOMEM; } /* initialize lmac sections */ for (i = 0; i < dram->lmac_cnt; i++) { ret = iwx_ctxt_info_alloc_dma(sc, &fws->fw_sect[i], &dram->fw[fw_cnt]); if (ret) return ret; ctxt_dram->lmac_img[i] = htole64(dram->fw[fw_cnt].paddr); DPRINTFN(3, ("%s: firmware LMAC section %d at 0x%llx size %lld\n", __func__, i, (unsigned long long)dram->fw[fw_cnt].paddr, (unsigned long long)dram->fw[fw_cnt].size)); fw_cnt++; } /* initialize umac sections */ for (i = 0; i < dram->umac_cnt; i++) { /* access FW with +1 to make up for lmac separator */ ret = iwx_ctxt_info_alloc_dma(sc, &fws->fw_sect[fw_cnt + 1], &dram->fw[fw_cnt]); if (ret) return ret; ctxt_dram->umac_img[i] = htole64(dram->fw[fw_cnt].paddr); DPRINTFN(3, ("%s: firmware UMAC section %d at 0x%llx size %lld\n", __func__, i, (unsigned long long)dram->fw[fw_cnt].paddr, (unsigned long long)dram->fw[fw_cnt].size)); fw_cnt++; } /* * Initialize paging. * Paging memory isn't stored in dram->fw as the umac and lmac - it is * stored separately. * This is since the timing of its release is different - * while fw memory can be released on alive, the paging memory can be * freed only when the device goes down. * Given that, the logic here in accessing the fw image is a bit * different - fw_cnt isn't changing so loop counter is added to it. */ for (i = 0; i < dram->paging_cnt; i++) { /* access FW with +2 to make up for lmac & umac separators */ int fw_idx = fw_cnt + i + 2; ret = iwx_ctxt_info_alloc_dma(sc, &fws->fw_sect[fw_idx], &dram->paging[i]); if (ret) return ret; ctxt_dram->virtual_img[i] = htole64(dram->paging[i].paddr); DPRINTFN(3, ("%s: firmware paging section %d at 0x%llx size %lld\n", __func__, i, (unsigned long long)dram->paging[i].paddr, (unsigned long long)dram->paging[i].size)); } return 0; } void ItlIwx:: iwx_fw_version_str(char *buf, size_t bufsize, uint32_t major, uint32_t minor, uint32_t api) { /* * Starting with major version 35 the Linux driver prints the minor * version in hexadecimal. */ if (major >= 35) snprintf(buf, bufsize, "%u.%08x.%u", major, minor, api); else snprintf(buf, bufsize, "%u.%u.%u", major, minor, api); } int ItlIwx:: iwx_alloc_fw_monitor_block(struct iwx_softc *sc, uint8_t max_power, uint8_t min_power) { struct iwx_dma_info *fw_mon = &sc->fw_mon; uint32_t size = 0; uint8_t power; int err = 0; if (fw_mon->size) return 0; for (power = max_power; power >= min_power; power--) { size = (1 << power); err = iwx_dma_contig_alloc(sc->sc_dmat, fw_mon, size, 0); if (err) continue; DPRINTF(("%s: allocated 0x%08x bytes for firmware monitor.\n", DEVNAME(sc), size)); break; } if (err) { fw_mon->size = 0; return err; } if (power != max_power) DPRINTF(("%s: Sorry - debug buffer is only %luK while you requested %luK\n", DEVNAME(sc), (unsigned long)(1 << (power - 10)), (unsigned long)(1 << (max_power - 10)))); return 0; } int ItlIwx:: iwx_alloc_fw_monitor(struct iwx_softc *sc, uint8_t max_power) { if (!max_power) { /* default max_power is maximum */ max_power = 26; } else { max_power += 11; } if (max_power > 26) { DPRINTF(("%s: External buffer size for monitor is too big %d, " "check the FW TLV\n", DEVNAME(sc), max_power)); return 0; } if (sc->fw_mon.size) return 0; return iwx_alloc_fw_monitor_block(sc, max_power, 11); } int ItlIwx:: iwx_apply_debug_destination(struct iwx_softc *sc) { struct iwx_fw_dbg_dest_tlv_v1 *dest_v1; int i, err; uint8_t mon_mode, size_power, base_shift, end_shift; uint32_t base_reg, end_reg; dest_v1 = sc->sc_fw.dbg_dest_tlv_v1; mon_mode = dest_v1->monitor_mode; size_power = dest_v1->size_power; base_reg = le32toh(dest_v1->base_reg); end_reg = le32toh(dest_v1->end_reg); base_shift = dest_v1->base_shift; end_shift = dest_v1->end_shift; DPRINTF(("%s: applying debug destination %d\n", DEVNAME(sc), mon_mode)); if (mon_mode == EXTERNAL_MODE) { err = iwx_alloc_fw_monitor(sc, size_power); if (err) return err; } if (!iwx_nic_lock(sc)) return EBUSY; for (i = 0; i < sc->sc_fw.n_dest_reg; i++) { uint32_t addr, val; uint8_t op; addr = le32toh(dest_v1->reg_ops[i].addr); val = le32toh(dest_v1->reg_ops[i].val); op = dest_v1->reg_ops[i].op; DPRINTF(("%s: op=%u addr=%u val=%u\n", __func__, op, addr, val)); switch (op) { case CSR_ASSIGN: IWX_WRITE(sc, addr, val); break; case CSR_SETBIT: IWX_SETBITS(sc, addr, (1 << val)); break; case CSR_CLEARBIT: IWX_CLRBITS(sc, addr, (1 << val)); break; case PRPH_ASSIGN: iwx_write_prph(sc, addr, val); break; case PRPH_SETBIT: iwx_set_bits_prph(sc, addr, (1 << val)); break; case PRPH_CLEARBIT: iwx_clear_bits_prph(sc, addr, (1 << val)); break; case PRPH_BLOCKBIT: if (iwx_read_prph(sc, addr) & (1 << val)) goto monitor; break; default: DPRINTF(("%s: FW debug - unknown OP %d\n", DEVNAME(sc), op)); break; } } monitor: if (mon_mode == EXTERNAL_MODE && sc->fw_mon.size) { iwx_write_prph(sc, le32toh(base_reg), sc->fw_mon.paddr >> base_shift); iwx_write_prph(sc, end_reg, (sc->fw_mon.paddr + sc->fw_mon.size - 256) >> end_shift); } iwx_nic_unlock(sc); return 0; } void ItlIwx:: iwx_set_ltr(struct iwx_softc *sc) { uint32_t ltr_val = IWX_CSR_LTR_LONG_VAL_AD_NO_SNOOP_REQ | u32_encode_bits(IWX_CSR_LTR_LONG_VAL_AD_SCALE_USEC, IWX_CSR_LTR_LONG_VAL_AD_NO_SNOOP_SCALE) | u32_encode_bits(250, IWX_CSR_LTR_LONG_VAL_AD_NO_SNOOP_VAL) | IWX_CSR_LTR_LONG_VAL_AD_SNOOP_REQ | u32_encode_bits(IWX_CSR_LTR_LONG_VAL_AD_SCALE_USEC, IWX_CSR_LTR_LONG_VAL_AD_SNOOP_SCALE) | u32_encode_bits(250, IWX_CSR_LTR_LONG_VAL_AD_SNOOP_VAL); /* * To workaround hardware latency issues during the boot process, * initialize the LTR to ~250 usec (see ltr_val above). * The firmware initializes this again later (to a smaller value). */ if ((sc->sc_device_family == IWX_DEVICE_FAMILY_AX210 || sc->sc_device_family == IWX_DEVICE_FAMILY_22000) && !sc->sc_integrated) { IWX_WRITE(sc, IWX_CSR_LTR_LONG_VAL_AD, ltr_val); } else if (sc->sc_integrated && sc->sc_device_family == IWX_DEVICE_FAMILY_22000) { if (iwx_nic_lock(sc)) { iwx_write_prph(sc, IWX_HPM_MAC_LTR_CSR, IWX_HPM_MAC_LRT_ENABLE_ALL); iwx_write_prph(sc, IWX_HPM_UMAC_LTR, ltr_val); iwx_nic_unlock(sc); } } } int ItlIwx:: iwx_ctxt_info_init(struct iwx_softc *sc, const struct iwx_fw_sects *fws) { XYLog("%s\n", __FUNCTION__); struct iwx_context_info *ctxt_info; struct iwx_context_info_rbd_cfg *rx_cfg; uint32_t control_flags = 0, rb_size; int err; ctxt_info = (struct iwx_context_info *)sc->ctxt_info_dma.vaddr; ctxt_info->version.version = 0; ctxt_info->version.mac_id = htole16((uint16_t)IWX_READ(sc, IWX_CSR_HW_REV)); /* size is in DWs */ ctxt_info->version.size = htole16(sizeof(*ctxt_info) / 4); rb_size = IWX_CTXT_INFO_RB_SIZE_4K; KASSERT(IWX_RX_QUEUE_CB_SIZE(IWX_MQ_RX_TABLE_SIZE) < 0xF, "IWX_RX_QUEUE_CB_SIZE(IWX_MQ_RX_TABLE_SIZE) < 0xF"); control_flags = IWX_CTXT_INFO_TFD_FORMAT_LONG | (IWX_RX_QUEUE_CB_SIZE(IWX_MQ_RX_TABLE_SIZE) << IWX_CTXT_INFO_RB_CB_SIZE_POS) | (rb_size << IWX_CTXT_INFO_RB_SIZE_POS); ctxt_info->control.control_flags = htole32(control_flags); /* initialize RX default queue */ rx_cfg = &ctxt_info->rbd_cfg; rx_cfg->free_rbd_addr = htole64(sc->rxq.free_desc_dma.paddr); rx_cfg->used_rbd_addr = htole64(sc->rxq.used_desc_dma.paddr); rx_cfg->status_wr_ptr = htole64(sc->rxq.stat_dma.paddr); /* initialize TX command queue */ ctxt_info->hcmd_cfg.cmd_queue_addr = htole64(sc->txq[IWX_DQA_CMD_QUEUE].desc_dma.paddr); ctxt_info->hcmd_cfg.cmd_queue_size = IWX_TFD_QUEUE_CB_SIZE(IWX_CMD_QUEUE_SIZE); /* allocate ucode sections in dram and set addresses */ err = iwx_init_fw_sec(sc, fws, &ctxt_info->dram); if (err) { iwx_ctxt_info_free_fw_img(sc); return err; } //zxystd: I don't know if it is necessary, but it is also works without the debug info, comment it to avoid DMA memory leak #if 0 /* Configure debug, if exists */ if (sc->sc_fw.dbg_dest_tlv_v1) { err = iwx_apply_debug_destination(sc); if (err) { iwx_ctxt_info_free_fw_img(sc); return err; } } #endif iwx_enable_fwload_interrupt(sc); IWX_WRITE64(sc, IWX_CSR_CTXT_INFO_BA, sc->ctxt_info_dma.paddr); iwx_set_ltr(sc); /* kick FW self load */ if (!iwx_nic_lock(sc)) { iwx_ctxt_info_free_fw_img(sc); return EBUSY; } iwx_write_prph(sc, IWX_UREG_CPU_INIT_RUN, 1); iwx_nic_unlock(sc); /* Context info will be released upon alive or failure to get one */ return 0; } int ItlIwx:: iwx_ctxt_info_gen3_init(struct iwx_softc *sc, const struct iwx_fw_sects *fws) { XYLog("%s\n", __FUNCTION__); struct iwx_context_info_gen3 *ctxt_info_gen3; struct iwx_prph_scratch *prph_scratch; struct iwx_prph_scratch_ctrl_cfg *prph_sc_ctrl; uint32_t control_flags = 0; int err; /* Allocate prph scratch. */ err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->prph_scratch_dma, sizeof(struct iwx_prph_scratch), 0); if (err) { XYLog("%s: could not allocate prph scratch\n", DEVNAME(sc)); return false; } prph_scratch = (struct iwx_prph_scratch *)sc->prph_scratch_dma.vaddr; prph_sc_ctrl = &prph_scratch->ctrl_cfg; prph_sc_ctrl->version.version = 0; prph_sc_ctrl->version.mac_id = htole16((uint16_t)IWX_READ(sc, IWX_CSR_HW_REV)); prph_sc_ctrl->version.size = htole16(sizeof(*prph_scratch) / 4); control_flags = IWX_PRPH_SCRATCH_RB_SIZE_4K; control_flags |= IWX_PRPH_SCRATCH_MTR_MODE; control_flags |= IWX_PRPH_MTR_FORMAT_256B & IWX_PRPH_SCRATCH_MTR_FORMAT; /* initialize RX default queue */ prph_sc_ctrl->rbd_cfg.free_rbd_addr = htole64(sc->rxq.free_desc_dma.paddr); prph_sc_ctrl->control.control_flags = htole32(control_flags); /* allocate ucode sections in dram and set addresses */ err = iwx_init_fw_sec(sc, fws, &prph_scratch->dram); if (err) { iwx_ctxt_info_free_fw_img(sc); return err; } /* Allocate prph information. */ err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->prph_info_dma, PAGE_SIZE, 0); if (err) { XYLog("%s: could not allocate prph information\n", DEVNAME(sc)); goto fail0; } ctxt_info_gen3 = (struct iwx_context_info_gen3 *)sc->ctxt_info_dma.vaddr; ctxt_info_gen3->prph_info_base_addr = htole64(sc->prph_info_dma.paddr); ctxt_info_gen3->prph_scratch_base_addr = htole64(sc->prph_scratch_dma.paddr); ctxt_info_gen3->prph_scratch_size = htole32(sizeof(*prph_scratch)); ctxt_info_gen3->cr_head_idx_arr_base_addr = htole64(sc->rxq.stat_dma.paddr); ctxt_info_gen3->tr_tail_idx_arr_base_addr = htole64((uint8_t *)sc->prph_info_dma.paddr + PAGE_SIZE / 2); ctxt_info_gen3->cr_tail_idx_arr_base_addr = htole64((uint8_t *)sc->prph_info_dma.paddr + 3 * PAGE_SIZE / 4); ctxt_info_gen3->mtr_base_addr = htole64(sc->txq[IWX_DQA_CMD_QUEUE].desc_dma.paddr); ctxt_info_gen3->mcr_base_addr = htole64(sc->rxq.used_desc_dma.paddr); ctxt_info_gen3->mtr_size = htole16(IWX_TFD_QUEUE_CB_SIZE(IWX_CMD_QUEUE_SIZE_GEN3)); ctxt_info_gen3->mcr_size = htole16(IWX_RX_QUEUE_CB_SIZE(IWX_RX_MQ_RING_COUNT)); /* Allocate IML. */ err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->iml_dma, IWX_IML_MAX_LEN, 0); if (err) { XYLog("%s: could not allocate IML\n", DEVNAME(sc)); goto fail1; } memcpy(sc->iml_dma.vaddr, sc->sc_iml, sc->sc_iml_len); iwx_enable_fwload_interrupt(sc); /* kick FW self load */ IWX_WRITE64(sc, IWX_CSR_CTXT_INFO_ADDR, sc->ctxt_info_dma.paddr); IWX_WRITE64(sc, IWX_CSR_IML_DATA_ADDR, sc->iml_dma.paddr); IWX_WRITE(sc, IWX_CSR_IML_SIZE_ADDR, sc->sc_iml_len); IWX_SETBITS(sc, IWX_CSR_CTXT_INFO_BOOT_CTRL, IWX_CSR_AUTO_FUNC_BOOT_ENA); iwx_set_ltr(sc); if (!iwx_nic_lock(sc)) return EBUSY; iwx_write_umac_prph(sc, IWX_UREG_CPU_INIT_RUN, 1); iwx_nic_unlock(sc); return 0; fail1: iwx_dma_contig_free(&sc->iml_dma); fail0: iwx_dma_contig_free(&sc->prph_info_dma); iwx_dma_contig_free(&sc->prph_scratch_dma); return ENOMEM; } void ItlIwx:: iwx_force_power_gating(struct iwx_softc *sc) { iwx_set_bits_prph(sc, IWX_HPM_HIPM_GEN_CFG, IWX_HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE); DELAY(20); iwx_set_bits_prph(sc, IWX_HPM_HIPM_GEN_CFG, IWX_HPM_HIPM_GEN_CFG_CR_PG_EN | IWX_HPM_HIPM_GEN_CFG_CR_SLP_EN); DELAY(20); iwx_clear_bits_prph(sc, IWX_HPM_HIPM_GEN_CFG, IWX_HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE); } void ItlIwx:: iwx_clear_persistence_bit(struct iwx_softc *sc) { uint32_t hpm, wprot; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) return; wprot = IWX_PREG_PRPH_WPROT_22000; hpm = iwx_read_prph_unlocked(sc, IWX_HPM_DEBUG); if (hpm != 0xa5a5a5a0 && (hpm & IWX_PERSISTENCE_BIT)) { uint32_t wprot_val = iwx_read_prph_unlocked(sc, wprot); if (wprot_val & IWX_PREG_WFPM_ACCESS) { XYLog("Error, can not clear persistence bit\n"); return; } iwx_write_prph_unlocked(sc, IWX_HPM_DEBUG, hpm & ~IWX_PERSISTENCE_BIT); } } void ItlIwx:: iwx_ctxt_info_free_fw_img(struct iwx_softc *sc) { struct iwx_self_init_dram *dram = &sc->init_dram; int i; if (!dram->fw) return; for (i = 0; i < dram->lmac_cnt + dram->umac_cnt; i++) iwx_dma_contig_free(&dram->fw[i]); IOFree(dram->fw, (dram->lmac_cnt + dram->umac_cnt) * sizeof(*dram->fw)); dram->lmac_cnt = 0; dram->umac_cnt = 0; dram->fw = NULL; } int ItlIwx:: iwx_firmware_store_section(struct iwx_softc *sc, enum iwx_ucode_type type, uint8_t *data, size_t dlen) { struct iwx_fw_sects *fws; struct iwx_fw_onesect *fwone; if (type >= IWX_UCODE_TYPE_MAX) return EINVAL; if (dlen < sizeof(uint32_t)) return EINVAL; fws = &sc->sc_fw.fw_sects[type]; DPRINTFN(3, ("%s: ucode type %d section %d\n", DEVNAME(sc), type, fws->fw_count)); if (fws->fw_count >= IWX_UCODE_SECT_MAX) return EINVAL; fwone = &fws->fw_sect[fws->fw_count]; /* first 32bit are device load offset */ memcpy(&fwone->fws_devoff, data, sizeof(uint32_t)); /* rest is data */ fwone->fws_data = data + sizeof(uint32_t); fwone->fws_len = dlen - sizeof(uint32_t); fws->fw_count++; fws->fw_totlen += fwone->fws_len; return 0; } #define IWX_DEFAULT_SCAN_CHANNELS 40 /* Newer firmware might support more channels. Raise this value if needed. */ #define IWX_MAX_SCAN_CHANNELS 256 /* as of 8265-34 firmware image */ #define IWX_STATION_COUNT_MAX 16 struct iwx_tlv_calib_data { uint32_t ucode_type; struct iwx_tlv_calib_ctrl calib; } __packed; int ItlIwx:: iwx_set_default_calib(struct iwx_softc *sc, const void *data) { const struct iwx_tlv_calib_data *def_calib = (const struct iwx_tlv_calib_data *)data; uint32_t ucode_type = le32toh(def_calib->ucode_type); if (ucode_type >= IWX_UCODE_TYPE_MAX) return EINVAL; sc->sc_default_calib[ucode_type].flow_trigger = def_calib->calib.flow_trigger; sc->sc_default_calib[ucode_type].event_trigger = def_calib->calib.event_trigger; return 0; } void ItlIwx:: iwx_fw_info_free(struct iwx_fw_info *fw) { ::free(fw->fw_rawdata); fw->fw_rawdata = NULL; fw->fw_rawsize = 0; /* don't touch fw->fw_status */ memset(fw->fw_sects, 0, sizeof(fw->fw_sects)); } void ItlIwx:: iwx_pnvm_free(struct iwx_fw_info *fw) { if (fw->pnvm_rawdata) { ::free(fw->pnvm_rawdata); fw->pnvm_rawdata = NULL; fw->pnvm_rawsize = 0; } } #define IWX_FW_ADDR_CACHE_CONTROL 0xC0000000 //void ItlIwx:: //onLoadFW(OSKextRequestTag requestTag, OSReturn result, const void *resourceData, uint32_t resourceDataLength, void *context) //{ // XYLog("onLoadFW callback ret=0x%08x length=%d", result, resourceDataLength); // ResourceCallbackContext *resourceContxt = (ResourceCallbackContext*)context; // IOLockLock(resourceContxt->context->_fwLoadLock); // if (resourceDataLength > 0) { // XYLog("onLoadFW return success"); // resourceContxt->resource = OSData::withBytes(resourceData, resourceDataLength); // } // IOLockUnlock(resourceContxt->context->_fwLoadLock); // IOLockWakeup(resourceContxt->context->_fwLoadLock, resourceContxt->context, false); // XYLog("onLoadFW wakeupOn"); //} int ItlIwx:: iwx_read_firmware(struct iwx_softc *sc) { struct iwx_fw_info *fw = &sc->sc_fw; struct iwx_tlv_ucode_header *uhdr; struct iwx_ucode_tlv tlv; uint32_t tlv_type = 0; uint8_t *data; int err = 0; size_t len; OSData *fwData = NULL; if (fw->fw_status == IWX_FW_STATUS_DONE) return 0; while (fw->fw_status == IWX_FW_STATUS_INPROGRESS) tsleep_nsec(&sc->sc_fw, 0, "iwxfwp", INFSLP); fw->fw_status = IWX_FW_STATUS_INPROGRESS; if (fw->fw_rawdata != NULL) iwx_fw_info_free(fw); // IOLockLock(_fwLoadLock); // ResourceCallbackContext context = // { // .context = this, // .resource = NULL // }; // // //here leaks // IOReturn ret = OSKextRequestResource(OSKextGetCurrentIdentifier(), sc->sc_fwname, onLoadFW, &context, NULL); // IOLockSleep(_fwLoadLock, this, 0); // IOLockUnlock(_fwLoadLock); // if (context.resource == NULL) { // XYLog("%s resource load fail.\n", sc->sc_fwname); // goto out; // } // fw->fw_rawdata = malloc(context.resource->getLength(), 1, 1); // memcpy(fw->fw_rawdata, context.resource->getBytesNoCopy(), context.resource->getLength()); // fw->fw_rawsize = context.resource->getLength(); fwData = getFWDescByName(sc->sc_fwname); if (fwData == NULL) { err = EINVAL; XYLog("%s resource load fail.\n", sc->sc_fwname); goto out; } fw->fw_rawsize = fwData->getLength() * 4; fw->fw_rawdata = malloc(fw->fw_rawsize, 1, 1); uncompressFirmware((u_char *)fw->fw_rawdata, (uint *)&fw->fw_rawsize, (u_char *)fwData->getBytesNoCopy(), fwData->getLength()); XYLog("load firmware %s done\n", sc->sc_fwname); sc->sc_capaflags = 0; sc->sc_capa_n_scan_channels = IWX_DEFAULT_SCAN_CHANNELS; memset(sc->sc_enabled_capa, 0, sizeof(sc->sc_enabled_capa)); memset(sc->sc_ucode_api, 0, sizeof(sc->sc_ucode_api)); sc->n_cmd_versions = 0; memcpy(sc->sc_fw_mcc, "ZZ", sizeof(sc->sc_fw_mcc)); sc->sc_fw_mcc_int = 0x3030; uhdr = (struct iwx_tlv_ucode_header *)fw->fw_rawdata; if (*(uint32_t *)fw->fw_rawdata != 0 || le32toh(uhdr->magic) != IWX_TLV_UCODE_MAGIC) { XYLog("%s: invalid firmware %s\n", DEVNAME(sc), sc->sc_fwname); err = EINVAL; goto out; } iwx_fw_version_str(sc->sc_fwver, sizeof(sc->sc_fwver), IWX_UCODE_MAJOR(le32toh(uhdr->ver)), IWX_UCODE_MINOR(le32toh(uhdr->ver)), IWX_UCODE_API(le32toh(uhdr->ver))); data = uhdr->data; len = fw->fw_rawsize - sizeof(*uhdr); XYLog("parsing firmware %s\n", sc->sc_fwname); while (len >= sizeof(tlv)) { size_t tlv_len; void *tlv_data; memcpy(&tlv, data, sizeof(tlv)); tlv_len = le32toh(tlv.length); tlv_type = le32toh(tlv.type); len -= sizeof(tlv); data += sizeof(tlv); tlv_data = data; if (len < tlv_len) { XYLog("%s: firmware too short: %zu bytes\n", DEVNAME(sc), len); err = EINVAL; goto parse_out; } switch (tlv_type) { case IWX_UCODE_TLV_PROBE_MAX_LEN: if (tlv_len < sizeof(uint32_t)) { err = EINVAL; goto parse_out; } sc->sc_capa_max_probe_len = le32toh(*(uint32_t *)tlv_data); if (sc->sc_capa_max_probe_len > IWX_SCAN_OFFLOAD_PROBE_REQ_SIZE) { err = EINVAL; goto parse_out; } break; case IWX_UCODE_TLV_PAN: if (tlv_len) { err = EINVAL; goto parse_out; } sc->sc_capaflags |= IWX_UCODE_TLV_FLAGS_PAN; break; case IWX_UCODE_TLV_FLAGS: if (tlv_len < sizeof(uint32_t)) { err = EINVAL; goto parse_out; } /* * Apparently there can be many flags, but Linux driver * parses only the first one, and so do we. * * XXX: why does this override IWX_UCODE_TLV_PAN? * Intentional or a bug? Observations from * current firmware file: * 1) TLV_PAN is parsed first * 2) TLV_FLAGS contains TLV_FLAGS_PAN * ==> this resets TLV_PAN to itself... hnnnk */ sc->sc_capaflags = le32toh(*(uint32_t *)tlv_data); break; case IWX_UCODE_TLV_CSCHEME: err = iwx_store_cscheme(sc, (uint8_t *)tlv_data, tlv_len); if (err) goto parse_out; break; case IWX_UCODE_TLV_NUM_OF_CPU: { uint32_t num_cpu; if (tlv_len != sizeof(uint32_t)) { err = EINVAL; goto parse_out; } num_cpu = le32toh(*(uint32_t *)tlv_data); if (num_cpu < 1 || num_cpu > 2) { err = EINVAL; goto parse_out; } break; } case IWX_UCODE_TLV_SEC_RT: err = iwx_firmware_store_section(sc, IWX_UCODE_TYPE_REGULAR, (uint8_t *)tlv_data, tlv_len); if (err) goto parse_out; break; case IWX_UCODE_TLV_SEC_INIT: err = iwx_firmware_store_section(sc, IWX_UCODE_TYPE_INIT, (uint8_t *)tlv_data, tlv_len); if (err) goto parse_out; break; case IWX_UCODE_TLV_SEC_WOWLAN: err = iwx_firmware_store_section(sc, IWX_UCODE_TYPE_WOW, (uint8_t *)tlv_data, tlv_len); if (err) goto parse_out; break; case IWX_UCODE_TLV_DEF_CALIB: if (tlv_len != sizeof(struct iwx_tlv_calib_data)) { err = EINVAL; goto parse_out; } err = iwx_set_default_calib(sc, tlv_data); if (err) goto parse_out; break; case IWX_UCODE_TLV_PHY_SKU: if (tlv_len != sizeof(uint32_t)) { err = EINVAL; goto parse_out; } sc->sc_fw_phy_config = le32toh(*(uint32_t *)tlv_data); break; case IWX_UCODE_TLV_API_CHANGES_SET: { struct iwx_ucode_api *api; int idx, i; if (tlv_len != sizeof(*api)) { err = EINVAL; goto parse_out; } api = (struct iwx_ucode_api *)tlv_data; idx = le32toh(api->api_index); if (idx >= howmany(IWX_NUM_UCODE_TLV_API, 32)) { err = EINVAL; goto parse_out; } for (i = 0; i < 32; i++) { if ((le32toh(api->api_flags) & (1 << i)) == 0) continue; setbit(sc->sc_ucode_api, i + (32 * idx)); } break; } case IWX_UCODE_TLV_ENABLED_CAPABILITIES: { struct iwx_ucode_capa *capa; int idx, i; if (tlv_len != sizeof(*capa)) { err = EINVAL; goto parse_out; } capa = (struct iwx_ucode_capa *)tlv_data; idx = le32toh(capa->api_index); if (idx >= howmany(IWX_NUM_UCODE_TLV_CAPA, 32)) { goto parse_out; } for (i = 0; i < 32; i++) { if ((le32toh(capa->api_capa) & (1 << i)) == 0) continue; setbit(sc->sc_enabled_capa, i + (32 * idx)); } break; } case IWX_UCODE_TLV_SDIO_ADMA_ADDR: case IWX_UCODE_TLV_FW_GSCAN_CAPA: /* ignore, not used by current driver */ break; case IWX_UCODE_TLV_SEC_RT_USNIFFER: err = iwx_firmware_store_section(sc, IWX_UCODE_TYPE_REGULAR_USNIFFER, (uint8_t *)tlv_data, tlv_len); if (err) goto parse_out; break; case IWX_UCODE_TLV_PAGING: if (tlv_len != sizeof(uint32_t)) { err = EINVAL; goto parse_out; } break; case IWX_UCODE_TLV_N_SCAN_CHANNELS: if (tlv_len != sizeof(uint32_t)) { err = EINVAL; goto parse_out; } sc->sc_capa_n_scan_channels = le32toh(*(uint32_t *)tlv_data); if (sc->sc_capa_n_scan_channels > IWX_MAX_SCAN_CHANNELS) { err = ERANGE; goto parse_out; } break; case IWX_UCODE_TLV_FW_VERSION: if (tlv_len != sizeof(uint32_t) * 3) { err = EINVAL; goto parse_out; } iwx_fw_version_str(sc->sc_fwver, sizeof(sc->sc_fwver), le32toh(((uint32_t *)tlv_data)[0]), le32toh(((uint32_t *)tlv_data)[1]), le32toh(((uint32_t *)tlv_data)[2])); break; case IWX_UCODE_TLV_FW_DBG_DEST: { struct iwx_fw_dbg_dest_tlv_v1 *dest_v1 = NULL; fw->dbg_dest_ver = (uint8_t *)tlv_data; if (*fw->dbg_dest_ver != 0) { err = EINVAL; goto parse_out; } if (fw->dbg_dest_tlv_init) break; fw->dbg_dest_tlv_init = true; dest_v1 = (struct iwx_fw_dbg_dest_tlv_v1 *)tlv_data; fw->dbg_dest_tlv_v1 = dest_v1; fw->n_dest_reg = tlv_len - offsetof(struct iwx_fw_dbg_dest_tlv_v1, reg_ops); fw->n_dest_reg /= sizeof(dest_v1->reg_ops[0]); DPRINTF(("%s: found debug dest; n_dest_reg=%d\n", __func__, fw->n_dest_reg)); break; } case IWX_UCODE_TLV_FW_DBG_CONF: { struct iwx_fw_dbg_conf_tlv *conf = (struct iwx_fw_dbg_conf_tlv *)tlv_data; if (!fw->dbg_dest_tlv_init || conf->id >= nitems(fw->dbg_conf_tlv) || fw->dbg_conf_tlv[conf->id] != NULL) break; DPRINTF(("Found debug configuration: %d\n", conf->id)); fw->dbg_conf_tlv[conf->id] = conf; fw->dbg_conf_tlv_len[conf->id] = tlv_len; break; } case IWX_UCODE_TLV_UMAC_DEBUG_ADDRS: { struct iwx_umac_debug_addrs *dbg_ptrs = (struct iwx_umac_debug_addrs *)tlv_data; if (tlv_len != sizeof(*dbg_ptrs)) { err = EINVAL; goto parse_out; } if (sc->sc_device_family < IWX_DEVICE_FAMILY_22000) break; sc->sc_uc.uc_umac_error_event_table = le32toh(dbg_ptrs->error_info_addr) & ~IWX_FW_ADDR_CACHE_CONTROL; sc->sc_uc.error_event_table_tlv_status |= IWX_ERROR_EVENT_TABLE_UMAC; break; } case IWX_UCODE_TLV_LMAC_DEBUG_ADDRS: { struct iwx_lmac_debug_addrs *dbg_ptrs = (struct iwx_lmac_debug_addrs *)tlv_data; if (tlv_len != sizeof(*dbg_ptrs)) { err = EINVAL; goto parse_out; } if (sc->sc_device_family < IWX_DEVICE_FAMILY_22000) break; sc->sc_uc.uc_lmac_error_event_table[0] = le32toh(dbg_ptrs->error_event_table_ptr) & ~IWX_FW_ADDR_CACHE_CONTROL; sc->sc_uc.error_event_table_tlv_status |= IWX_ERROR_EVENT_TABLE_LMAC1; break; } case IWX_UCODE_TLV_FW_MEM_SEG: break; case IWX_UCODE_TLV_IML: if (sizeof(sc->sc_iml) < tlv_len) { XYLog("IML max len mismatch. len1: %zu len2: %zu\n", sizeof(sc->sc_iml), tlv_len); err = EINVAL; goto parse_out; } sc->sc_iml_len = (uint32_t)tlv_len; memcpy(sc->sc_iml, tlv_data, sc->sc_iml_len); break; case IWX_UCODE_TLV_CMD_VERSIONS: if (tlv_len % sizeof(struct iwx_fw_cmd_version)) { tlv_len /= sizeof(struct iwx_fw_cmd_version); tlv_len *= sizeof(struct iwx_fw_cmd_version); } if (sc->n_cmd_versions != 0) { err = EINVAL; goto parse_out; } if (tlv_len > sizeof(sc->cmd_versions)) { err = EINVAL; goto parse_out; } memcpy(&sc->cmd_versions[0], tlv_data, tlv_len); sc->n_cmd_versions = tlv_len / sizeof(struct iwx_fw_cmd_version); break; case IWX_UCODE_TLV_FW_RECOVERY_INFO: break; case IWX_UCODE_TLV_FW_FSEQ_VERSION: { struct sfseq_ver { uint8_t version[32]; uint8_t sha1[20]; }; sfseq_ver *seq_ver = (sfseq_ver *)tlv_data; if (tlv_len != sizeof(struct sfseq_ver)) { err = EINVAL; goto parse_out; } XYLog("TLV_FW_FSEQ_VERSION: %s\n", seq_ver->version); } break; case IWX_UCODE_PHY_INTEGRATION_VERSION: break; case IWX_UCODE_TLV_FW_NUM_STATIONS: if (tlv_len != sizeof(uint32_t)) { err = EINVAL; goto parse_out; } sc->sc_capa_num_stations = le32toh(*(uint32_t *)tlv_data); if (sc->sc_capa_num_stations > IWX_STATION_COUNT_MAX) { XYLog("%d is an invalid number of station\n", sc->sc_capa_num_stations); err = EINVAL; goto parse_out; } break; /* undocumented TLVs found in iwx-cc-a0-48 image */ case 58: case 0x1000003: case 0x1000004: break; /* undocumented TLVs found in iwx-cc-a0-48 image */ case 0x1000000: case 0x1000002: case IWX_UCODE_TLV_TYPE_DEBUG_INFO: case IWX_UCODE_TLV_TYPE_BUFFER_ALLOCATION: case IWX_UCODE_TLV_TYPE_HCMD: case IWX_UCODE_TLV_TYPE_REGIONS: case IWX_UCODE_TLV_TYPE_TRIGGERS: case IWX_UCODE_TLV_TYPE_CONF_SET: break; /* undocumented TLV found in iwx-cc-a0-67 image */ case 0x100000b: break; default: // err = EINVAL; // goto parse_out; XYLog("%s unhandle section type= %d\n", __FUNCTION__, tlv_type); break; } /* * Check for size_t overflow and ignore missing padding at * end of firmware file. */ if (roundup(tlv_len, 4) > len) break; len -= roundup(tlv_len, 4); data += roundup(tlv_len, 4); } KASSERT(err == 0, "err == 0"); XYLog("firmware parse done\n"); parse_out: if (err) { XYLog("%s: firmware parse error %d, " "section type %d\n", DEVNAME(sc), err, tlv_type); } out: if (err) { fw->fw_status = IWX_FW_STATUS_NONE; if (fw->fw_rawdata != NULL) iwx_fw_info_free(fw); } else fw->fw_status = IWX_FW_STATUS_DONE; wakeupOn(&sc->sc_fw); OSSafeReleaseNULL(fwData); return err; } struct iwx_pnvm_section { uint32_t offset; const uint8_t data[]; } __packed; int ItlIwx:: iwx_pnvm_handle_section(struct iwx_softc *sc, const uint8_t *data, size_t len) { struct iwx_ucode_tlv *tlv; uint32_t sha1 = 0; uint16_t mac_type = 0, rf_id = 0; uint8_t *pnvm_data = NULL, *tmp; bool hw_match = false; uint32_t size = 0; int err = 0; struct iwx_prph_scratch_ctrl_cfg *prph_sc_ctrl; XYLog("Handling PNVM section\n"); while (len >= sizeof(*tlv)) { uint32_t tlv_len, tlv_type; len -= sizeof(*tlv); tlv = (struct iwx_ucode_tlv *)data; tlv_len = le32toh(tlv->length); tlv_type = le32toh(tlv->type); if (len < tlv_len) { XYLog("invalid TLV len: %zd/%u\n", len, tlv_len); err = -EINVAL; goto out; } data += sizeof(*tlv); switch (tlv_type) { case IWX_UCODE_TLV_PNVM_VERSION: if (tlv_len < sizeof(__le32)) { XYLog("Invalid size for IWL_UCODE_TLV_PNVM_VERSION (expected %zd, got %d)\n", sizeof(__le32), tlv_len); break; } sha1 = le32_to_cpup((__le32 *)data); XYLog("Got IWL_UCODE_TLV_PNVM_VERSION %0x\n", sha1); break; case IWX_UCODE_TLV_HW_TYPE: if (tlv_len < 2 * sizeof(__le16)) { XYLog("Invalid size for IWL_UCODE_TLV_HW_TYPE (expected %zd, got %d)\n", 2 * sizeof(__le16), tlv_len); break; } if (hw_match) break; mac_type = le16_to_cpup((__le16 *)data); rf_id = le16_to_cpup((__le16 *)(data + sizeof(__le16))); XYLog("Got IWL_UCODE_TLV_HW_TYPE mac_type 0x%0x rf_id 0x%0x\n", mac_type, rf_id); if (mac_type == CSR_HW_REV_TYPE(sc->sc_hw_rev) && rf_id == CSR_HW_RFID_TYPE(sc->sc_hw_rf_id)) hw_match = true; break; case IWX_UCODE_TLV_SEC_RT: { struct iwx_pnvm_section *section = (struct iwx_pnvm_section *)data; u32 data_len = tlv_len - sizeof(*section); XYLog("Got IWL_UCODE_TLV_SEC_RT len %d\n", tlv_len); /* TODO: remove, this is a deprecated separator */ if (le32_to_cpup((__le32 *)data) == 0xddddeeee) { XYLog("Ignoring separator.\n"); break; } XYLog("Adding data (size %d)\n", data_len); tmp = (uint8_t *)malloc(size + data_len, 0, 0); if (!tmp) { XYLog("Couldn't allocate (more) pnvm_data\n"); err = -ENOMEM; goto out; } if (pnvm_data && size > 0) { memcpy(tmp, pnvm_data, size); ::free(pnvm_data); } pnvm_data = tmp; memcpy(pnvm_data + size, section->data, data_len); size += data_len; break; } case IWX_UCODE_TLV_PNVM_SKU: XYLog("New PNVM section started, stop parsing.\n"); goto done; default: XYLog("Found TLV 0x%0x, len %d\n", tlv_type, tlv_len); break; } if (roundup(tlv_len, 4) > len) break; len -= roundup(tlv_len, 4); data += roundup(tlv_len, 4); } done: if (!hw_match) { XYLog("HW mismatch, skipping PNVM section (need mac_type 0x%x rf_id 0x%x)\n", CSR_HW_REV_TYPE(sc->sc_hw_rev), CSR_HW_RFID_TYPE(sc->sc_hw_rf_id)); err = -ENOENT; goto out; } if (!size) { XYLog("Empty PNVM, skipping.\n"); err = -ENOENT; goto out; } XYLog("loaded PNVM version %08x\n", sha1); prph_sc_ctrl = &((struct iwx_prph_scratch *)sc->prph_scratch_dma.vaddr)->ctrl_cfg; iwx_dma_contig_free(&sc->pnvm_dram); err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->pnvm_dram, size, 0); if (err) { XYLog("%s: could not allocate context info DMA memory\n", DEVNAME(sc)); goto out; } memcpy(sc->pnvm_dram.vaddr, pnvm_data, size); prph_sc_ctrl->pnvm_cfg.pnvm_base_addr = htole64(sc->pnvm_dram.paddr); prph_sc_ctrl->pnvm_cfg.pnvm_size = htole32(sc->pnvm_dram.size); out: ::free(pnvm_data); return err; } int ItlIwx:: iwx_read_pnvm(struct iwx_softc *sc) { int err = 0; OSData *fwData = NULL; struct iwx_fw_info *fw = &sc->sc_fw; char fwname_copy[64]; char pnvm_name[64]; struct iwx_ucode_tlv *tlv; uint8_t *data; size_t len; const char *find; if (fw->pnvm_rawdata != NULL) iwx_pnvm_free(fw); /* * The prefix unfortunately includes a hyphen at the end, so * don't add the dot here... */ memcpy(fwname_copy, sc->sc_fwname, sizeof(fwname_copy)); find = strrchr(sc->sc_fwname, '-'); if (!find) goto out; if (find - sc->sc_fwname - 1 <= 0) goto out; fwname_copy[find - sc->sc_fwname - 1] = '\0'; snprintf(pnvm_name, sizeof(pnvm_name), "%s.pnvm", fwname_copy); fwData = getFWDescByName(pnvm_name); if (fwData == NULL) { err = EINVAL; XYLog("%s resource load fail.\n", pnvm_name); goto out; } fw->pnvm_rawsize = fwData->getLength() * 20; fw->pnvm_rawdata = malloc(fw->pnvm_rawsize, 1, 1); uncompressFirmware((u_char *)fw->pnvm_rawdata, (uint *)&fw->pnvm_rawsize, (u_char *)fwData->getBytesNoCopy(), fwData->getLength()); XYLog("load firmware %s done %zu\n", pnvm_name, fw->pnvm_rawsize); XYLog("Parsing PNVM file\n"); data = (uint8_t *)fw->pnvm_rawdata; len = fw->pnvm_rawsize; while (len >= sizeof(*tlv)) { uint32_t tlv_len, tlv_type; len -= sizeof(*tlv); tlv = (struct iwx_ucode_tlv *)data; tlv_len = le32toh(tlv->length); tlv_type = le32toh(tlv->type); if (len < tlv_len || roundup(tlv_len, 4) > len) { XYLog("invalid TLV len: %zd/%u\n", len, tlv_len); err = -EINVAL; goto out; } if (tlv_type == IWX_UCODE_TLV_PNVM_SKU) { struct iwx_sku_id *sku_id = (struct iwx_sku_id *)(data + sizeof(*tlv)); XYLog("Got IWL_UCODE_TLV_PNVM_SKU len %d\n", tlv_len); XYLog("sku_id 0x%0x 0x%0x 0x%0x\n", le32toh(sku_id->data[0]), le32toh(sku_id->data[1]), le32toh(sku_id->data[2])); data += sizeof(*tlv) + roundup(tlv_len, 4); len -= roundup(tlv_len, 4); if (sc->sku_id[0] == le32toh(sku_id->data[0]) && sc->sku_id[1] == le32toh(sku_id->data[1]) && sc->sku_id[2] == le32toh(sku_id->data[2])) { err = iwx_pnvm_handle_section(sc, data, len); if (!err) goto out; } else { XYLog("SKU ID didn't match!\n"); } } else { data += sizeof(*tlv) + roundup(tlv_len, 4); len -= roundup(tlv_len, 4); } } XYLog("PNVM parse done\n"); out: OSSafeReleaseNULL(fwData); return err; } int ItlIwx:: iwx_load_pnvm(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); int err; /* if the SKU_ID is empty, there's nothing to do */ if (!sc->sku_id[0] && !sc->sku_id[1] && !sc->sku_id[2]) return 0; if (!iwx_read_pnvm(sc)) { goto out; }; out: /* kick the doorbell */ if (iwx_nic_lock(sc)) { iwx_write_umac_prph(sc, IWX_UREG_DOORBELL_TO_ISR6, IWX_UREG_DOORBELL_TO_ISR6_PNVM); iwx_nic_unlock(sc); } err = tsleep_nsec(&sc->sc_init_complete, 0, "iwxinit", SEC_TO_NSEC(2)); iwx_pnvm_free(&sc->sc_fw); return err; } static uint32_t iwx_prph_msk(struct iwx_softc *sc) { if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) return 0x00FFFFFF; else return 0x000FFFFF; } uint32_t ItlIwx:: iwx_read_prph_unlocked(struct iwx_softc *sc, uint32_t addr) { IWX_WRITE(sc, IWX_HBUS_TARG_PRPH_RADDR, ((addr & iwx_prph_msk(sc)) | (3 << 24))); IWX_BARRIER_READ_WRITE(sc); return IWX_READ(sc, IWX_HBUS_TARG_PRPH_RDAT); } uint32_t ItlIwx:: iwx_read_prph(struct iwx_softc *sc, uint32_t addr) { iwx_nic_assert_locked(sc); return iwx_read_prph_unlocked(sc, addr); } uint32_t ItlIwx:: iwx_read_umac_prph(struct iwx_softc *sc, uint32_t addr) { int off = 0; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) off = GEN3_UMAC_PRPH_OFFSET; return iwx_read_prph(sc, off + addr); } void ItlIwx:: iwx_write_prph_unlocked(struct iwx_softc *sc, uint32_t addr, uint32_t val) { IWX_WRITE(sc, IWX_HBUS_TARG_PRPH_WADDR, ((addr & iwx_prph_msk(sc)) | (3 << 24))); IWX_BARRIER_WRITE(sc); IWX_WRITE(sc, IWX_HBUS_TARG_PRPH_WDAT, val); } void ItlIwx:: iwx_write_umac_prph(struct iwx_softc *sc, uint32_t addr, uint32_t val) { int off = 0; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) off = GEN3_UMAC_PRPH_OFFSET; iwx_write_prph(sc, off + addr, val); } void ItlIwx:: iwx_write_prph(struct iwx_softc *sc, uint32_t addr, uint32_t val) { iwx_nic_assert_locked(sc); iwx_write_prph_unlocked(sc, addr, val); } void ItlIwx:: iwx_write_prph64(struct iwx_softc *sc, uint64_t addr, uint64_t val) { iwx_write_prph(sc, (uint32_t)addr, val & 0xffffffff); iwx_write_prph(sc, (uint32_t)addr + 4, val >> 32); } int ItlIwx:: iwx_read_mem(struct iwx_softc *sc, uint32_t addr, void *buf, int dwords) { int offs, err = 0; uint32_t *vals = (uint32_t *)buf; if (iwx_nic_lock(sc)) { IWX_WRITE(sc, IWX_HBUS_TARG_MEM_RADDR, addr); for (offs = 0; offs < dwords; offs++) vals[offs] = le32toh(IWX_READ(sc, IWX_HBUS_TARG_MEM_RDAT)); iwx_nic_unlock(sc); } else { err = EBUSY; } return err; } int ItlIwx:: iwx_write_mem(struct iwx_softc *sc, uint32_t addr, const void *buf, int dwords) { int offs; const uint32_t *vals = (const uint32_t *)buf; if (iwx_nic_lock(sc)) { IWX_WRITE(sc, IWX_HBUS_TARG_MEM_WADDR, addr); /* WADDR auto-increments */ for (offs = 0; offs < dwords; offs++) { uint32_t val = vals ? vals[offs] : 0; IWX_WRITE(sc, IWX_HBUS_TARG_MEM_WDAT, val); } iwx_nic_unlock(sc); } else { return EBUSY; } return 0; } int ItlIwx:: iwx_write_mem32(struct iwx_softc *sc, uint32_t addr, uint32_t val) { return iwx_write_mem(sc, addr, &val, 1); } int ItlIwx:: iwx_poll_bit(struct iwx_softc *sc, int reg, uint32_t bits, uint32_t mask, int timo) { for (;;) { if ((IWX_READ(sc, reg) & mask) == (bits & mask)) { return 1; } if (timo < 10) { return 0; } timo -= 10; DELAY(10); } } int ItlIwx:: iwx_nic_lock(struct iwx_softc *sc) { if (sc->sc_nic_locks > 0) { iwx_nic_assert_locked(sc); sc->sc_nic_locks++; return 1; /* already locked */ } IWX_SETBITS(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); DELAY(2); if (iwx_poll_bit(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, IWX_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | IWX_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP, 150000)) { sc->sc_nic_locks++; return 1; } XYLog("%s: acquiring device failed\n", DEVNAME(sc)); return 0; } void ItlIwx:: iwx_nic_assert_locked(struct iwx_softc *sc) { if (sc->sc_nic_locks <= 0) panic("%s: nic locks counter %d", DEVNAME(sc), sc->sc_nic_locks); } void ItlIwx:: iwx_nic_unlock(struct iwx_softc *sc) { if (sc->sc_nic_locks > 0) { if (--sc->sc_nic_locks == 0) IWX_CLRBITS(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } else XYLog("%s: NIC already unlocked\n", DEVNAME(sc)); } void ItlIwx:: iwx_set_bits_mask_prph(struct iwx_softc *sc, uint32_t reg, uint32_t bits, uint32_t mask) { uint32_t val; /* XXX: no error path? */ if (iwx_nic_lock(sc)) { val = iwx_read_prph(sc, reg) & mask; val |= bits; iwx_write_prph(sc, reg, val); iwx_nic_unlock(sc); } } void ItlIwx:: iwx_set_bits_prph(struct iwx_softc *sc, uint32_t reg, uint32_t bits) { iwx_set_bits_mask_prph(sc, reg, bits, ~0); } void ItlIwx:: iwx_clear_bits_prph(struct iwx_softc *sc, uint32_t reg, uint32_t bits) { iwx_set_bits_mask_prph(sc, reg, 0, ~bits); } bool allocDmaMemory2(struct iwx_dma_info *dma, size_t size, int alignment) { IOBufferMemoryDescriptor *bmd; IODMACommand::Segment64 seg; UInt64 ofs = 0; UInt32 numSegs = 1; bmd = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, kIODirectionInOut | kIOMemoryPhysicallyContiguous | kIOMapInhibitCache, size, DMA_BIT_MASK(64)); if (bmd == NULL) { XYLog("%s alloc DMA memory failed.\n", __FUNCTION__); return false; } if (bmd->prepare() != kIOReturnSuccess) { XYLog("%s prepare DMA memory failed.\n", __FUNCTION__); bmd->release(); bmd = NULL; return false; } IODMACommand *cmd = IODMACommand::withSpecification(kIODMACommandOutputHost64, 64, 0, IODMACommand::kMapped, 0, alignment); if (cmd == NULL) { XYLog("%s alloc IODMACommand memory failed.\n", __FUNCTION__); bmd->complete(); bmd->release(); return false; } if (cmd->setMemoryDescriptor(bmd) != kIOReturnSuccess || cmd->gen64IOVMSegments(&ofs, &seg, &numSegs) != kIOReturnSuccess) { cmd->release(); cmd = NULL; bmd->complete(); bmd->release(); bmd = NULL; return false; } dma->paddr = seg.fIOVMAddr; dma->vaddr = bmd->getBytesNoCopy(); dma->size = size; dma->buffer = bmd; dma->cmd = cmd; memset(dma->vaddr, 0, dma->size); return true; } int ItlIwx:: iwx_dma_contig_alloc(bus_dma_tag_t tag, struct iwx_dma_info *dma, bus_size_t size, bus_size_t alignment) { if (!allocDmaMemory2(dma, size, alignment)) { return 1; } return 0; } void ItlIwx:: iwx_dma_contig_free(struct iwx_dma_info *dma) { if (dma == NULL || dma->cmd == NULL) return; if (dma->vaddr == NULL) return; dma->cmd->clearMemoryDescriptor(); dma->cmd->release(); dma->cmd = NULL; dma->buffer->complete(); dma->buffer->release(); dma->buffer = NULL; dma->vaddr = NULL; } /** * struct iwl_rx_transfer_desc - transfer descriptor * @addr: ptr to free buffer start address * @rbid: unique tag of the buffer * @reserved: reserved */ struct iwx_rx_transfer_desc { uint16_t rbid; uint16_t reserved[3]; uint64_t addr; } __packed; int ItlIwx:: iwx_alloc_rx_ring(struct iwx_softc *sc, struct iwx_rx_ring *ring) { bus_size_t size; int i, err; int rb_stts_size = sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210 ? sizeof(uint16_t) : sizeof(iwx_rb_status); int rb_stts_align = sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210 ? 0 : 16; ring->cur = 0; /* Allocate RX descriptors (256-byte aligned). */ size = IWX_RX_MQ_RING_COUNT * (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210 ? sizeof(struct iwx_rx_transfer_desc) : sizeof(uint64_t)); err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->free_desc_dma, size, 256); if (err) { XYLog("%s: could not allocate RX ring DMA memory\n", DEVNAME(sc)); goto fail; } ring->desc = ring->free_desc_dma.vaddr; /* Allocate RX status area (16-byte aligned). */ err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->stat_dma, rb_stts_size, rb_stts_align); if (err) { XYLog("%s: could not allocate RX status DMA memory\n", DEVNAME(sc)); goto fail; } ring->stat = ring->stat_dma.vaddr; size = IWX_RX_MQ_RING_COUNT * (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210 ? sizeof(struct iwx_rx_completion_desc) : sizeof(uint32_t)); err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->used_desc_dma, size, 256); if (err) { XYLog("%s: could not allocate RX ring DMA memory\n", DEVNAME(sc)); goto fail; } for (i = 0; i < IWX_RX_MQ_RING_COUNT; i++) { struct iwx_rx_data *data = &ring->data[i]; memset(data, 0, sizeof(*data)); err = bus_dmamap_create(sc->sc_dmat, IWX_RBUF_SIZE, 1, IWX_RBUF_SIZE, 0, BUS_DMA_NOWAIT, &data->map); if (err) { XYLog("%s: could not create RX buf DMA map\n", DEVNAME(sc)); goto fail; } err = iwx_rx_addbuf(sc, IWX_RBUF_SIZE, i); if (err) goto fail; } return 0; fail: iwx_free_rx_ring(sc, ring); return err; } void ItlIwx:: iwx_disable_rx_dma(struct iwx_softc *sc) { int ntries; if (iwx_nic_lock(sc)) { if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) { iwx_write_umac_prph(sc, IWX_RFH_RXF_DMA_CFG_GEN3, 0); for (ntries = 0; ntries < 1000; ntries++) { if (iwx_read_umac_prph(sc, IWX_RFH_GEN_STATUS_GEN3) & IWX_RXF_DMA_IDLE) break; DELAY(10); } } else { iwx_write_prph(sc, IWX_RFH_RXF_DMA_CFG, 0); for (ntries = 0; ntries < 1000; ntries++) { if (iwx_read_prph(sc, IWX_RFH_GEN_STATUS) & IWX_RXF_DMA_IDLE) break; DELAY(10); } } iwx_nic_unlock(sc); } } void ItlIwx:: iwx_reset_rx_ring(struct iwx_softc *sc, struct iwx_rx_ring *ring) { ring->cur = 0; // bus_dmamap_sync(sc->sc_dmat, ring->stat_dma.map, 0, // ring->stat_dma.size, BUS_DMASYNC_PREWRITE); if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) memset(ring->stat, 0, sizeof(uint16_t)); else memset(ring->stat, 0, sizeof(struct iwx_rb_status)); // bus_dmamap_sync(sc->sc_dmat, ring->stat_dma.map, 0, // ring->stat_dma.size, BUS_DMASYNC_POSTWRITE); } void ItlIwx:: iwx_free_rx_ring(struct iwx_softc *sc, struct iwx_rx_ring *ring) { int i; iwx_dma_contig_free(&ring->free_desc_dma); iwx_dma_contig_free(&ring->stat_dma); iwx_dma_contig_free(&ring->used_desc_dma); for (i = 0; i < IWX_RX_MQ_RING_COUNT; i++) { struct iwx_rx_data *data = &ring->data[i]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } if (data->map != NULL) { bus_dmamap_destroy(sc->sc_dmat, data->map); data->map = NULL; } } } void ItlIwx:: iwx_tx_ring_init(struct iwx_softc *sc, struct iwx_tx_ring *ring, int size) { int low_mark, high_mark; ring->ring_count = size; low_mark = ring->ring_count / 4; if (low_mark < 4) low_mark = 4; ring->low_mark = ring->ring_count - low_mark; high_mark = ring->ring_count / 8; if (high_mark < 2) high_mark = 2; ring->hi_mark = ring->ring_count - high_mark; ring->queued = 0; ring->cur = 0; ring->tail = 0; } int ItlIwx:: iwx_alloc_tx_ring(struct iwx_softc *sc, struct iwx_tx_ring *ring, int qid) { bus_addr_t paddr; bus_size_t size; int i, err; /* 0:CMD 2:MGMT */ if (qid > IWX_QID_MGMT) { ring->qid = IWX_INVALID_QUEUE; return 0; } if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) { if (qid == IWX_DQA_CMD_QUEUE) size = IWX_CMD_QUEUE_SIZE_GEN3; else size = IWX_MIN_256_BA_QUEUE_SIZE_GEN3; } else { if (qid == IWX_DQA_CMD_QUEUE) size = IWX_CMD_QUEUE_SIZE; else size = IWX_DEFAULT_QUEUE_SIZE; } iwx_tx_ring_init(sc, ring, size); ring->qid = qid; /* Allocate TX descriptors (256-byte aligned). */ size = ring->ring_count * sizeof (struct iwx_tfh_tfd); err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, size, 256); if (err) { XYLog("%s: could not allocate TX ring DMA memory\n", DEVNAME(sc)); goto fail; } ring->desc = (struct iwx_tfh_tfd*)ring->desc_dma.vaddr; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->bc_tbl, sizeof(struct iwx_gen3_bc_tbl), 0); else err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->bc_tbl, sizeof(struct iwx_agn_scd_bc_tbl), 0); if (err) { XYLog("%s: could not allocate byte count table DMA memory\n", DEVNAME(sc)); goto fail; } size = ring->ring_count * sizeof(struct iwx_device_cmd); err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, size, IWX_FIRST_TB_SIZE_ALIGN); if (err) { XYLog("%s: could not allocate cmd DMA memory\n", DEVNAME(sc)); goto fail; } ring->cmd = (struct iwx_device_cmd*)ring->cmd_dma.vaddr; paddr = ring->cmd_dma.paddr; for (i = 0; i < ring->ring_count; i++) { struct iwx_tx_data *data = &ring->data[i]; size_t mapsize; data->cmd_paddr = paddr; paddr += sizeof(struct iwx_device_cmd); /* FW commands may require more mapped space than packets. */ if (qid == IWX_DQA_CMD_QUEUE) mapsize = (sizeof(struct iwx_cmd_header) + IWX_MAX_CMD_PAYLOAD_SIZE); else mapsize = MCLBYTES; err = bus_dmamap_create(sc->sc_dmat, mapsize, IWX_TFH_NUM_TBS - 2, mapsize, 0, BUS_DMA_NOWAIT, &data->map); if (err) { XYLog("%s: could not create TX buf DMA map\n", DEVNAME(sc)); goto fail; } } KASSERT(paddr == ring->cmd_dma.paddr + size, "paddr == ring->cmd_dma.paddr + size"); return 0; fail: iwx_free_tx_ring(sc, ring); return err; } void ItlIwx:: iwx_reset_tx_ring(struct iwx_softc *sc, struct iwx_tx_ring *ring) { int i; for (i = 0; i < ring->ring_count; i++) { struct iwx_tx_data *data = &ring->data[i]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } } if (ring->qid == IWX_INVALID_QUEUE || !ring->desc) { return; } /* Clear byte count table. */ memset(ring->bc_tbl.vaddr, 0, ring->bc_tbl.size); /* Clear TX descriptors. */ memset(ring->desc, 0, ring->desc_dma.size); // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, // ring->desc_dma.size, BUS_DMASYNC_PREWRITE); sc->qfullmsk &= ~(1 << ring->qid); ring->queued = 0; ring->cur = 0; ring->tail = 0; } void ItlIwx:: iwx_free_tx_ring(struct iwx_softc *sc, struct iwx_tx_ring *ring) { int i; iwx_dma_contig_free(&ring->desc_dma); iwx_dma_contig_free(&ring->cmd_dma); iwx_dma_contig_free(&ring->bc_tbl); for (i = 0; i < ring->ring_count; i++) { struct iwx_tx_data *data = &ring->data[i]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } if (data->map != NULL) { bus_dmamap_destroy(sc->sc_dmat, data->map); data->map = NULL; } } ring->qid = IWX_INVALID_QUEUE; ring->hi_mark = 0; ring->low_mark = 0; ring->ring_count = 0; } void ItlIwx:: iwx_enable_rfkill_int(struct iwx_softc *sc) { if (!sc->sc_msix) { sc->sc_intmask = IWX_CSR_INT_BIT_RF_KILL; IWX_WRITE(sc, IWX_CSR_INT_MASK, sc->sc_intmask); } else { IWX_WRITE(sc, IWX_CSR_MSIX_FH_INT_MASK_AD, sc->sc_fh_init_mask); IWX_WRITE(sc, IWX_CSR_MSIX_HW_INT_MASK_AD, ~IWX_MSIX_HW_INT_CAUSES_REG_RF_KILL); sc->sc_hw_mask = IWX_MSIX_HW_INT_CAUSES_REG_RF_KILL; } IWX_SETBITS(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); } int ItlIwx:: iwx_check_rfkill(struct iwx_softc *sc) { uint32_t v; int s; int rv; s = splnet(); /* * "documentation" is not really helpful here: * 27: HW_RF_KILL_SW * Indicates state of (platform's) hardware RF-Kill switch * * But apparently when it's off, it's on ... */ v = IWX_READ(sc, IWX_CSR_GP_CNTRL); rv = (v & IWX_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) == 0; if (rv) { sc->sc_flags |= IWX_FLAG_RFKILL; } else { sc->sc_flags &= ~IWX_FLAG_RFKILL; } XYLog("%s RF_KILL hw: %d\n", __FUNCTION__, rv); splx(s); return rv; } void ItlIwx:: iwx_enable_interrupts(struct iwx_softc *sc) { if (!sc->sc_msix) { sc->sc_intmask = IWX_CSR_INI_SET_MASK; IWX_WRITE(sc, IWX_CSR_INT_MASK, sc->sc_intmask); } else { /* * fh/hw_mask keeps all the unmasked causes. * Unlike msi, in msix cause is enabled when it is unset. */ sc->sc_hw_mask = sc->sc_hw_init_mask; sc->sc_fh_mask = sc->sc_fh_init_mask; IWX_WRITE(sc, IWX_CSR_MSIX_FH_INT_MASK_AD, ~sc->sc_fh_mask); IWX_WRITE(sc, IWX_CSR_MSIX_HW_INT_MASK_AD, ~sc->sc_hw_mask); } } void ItlIwx:: iwx_enable_fwload_interrupt(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); if (!sc->sc_msix) { sc->sc_intmask = IWX_CSR_INT_BIT_ALIVE | IWX_CSR_INT_BIT_FH_RX; IWX_WRITE(sc, IWX_CSR_INT_MASK, sc->sc_intmask); } else { IWX_WRITE(sc, IWX_CSR_MSIX_HW_INT_MASK_AD, ~IWX_MSIX_HW_INT_CAUSES_REG_ALIVE); sc->sc_hw_mask = IWX_MSIX_HW_INT_CAUSES_REG_ALIVE; /* * Leave all the FH causes enabled to get the ALIVE * notification. */ IWX_WRITE(sc, IWX_CSR_MSIX_FH_INT_MASK_AD, ~sc->sc_fh_init_mask); sc->sc_fh_mask = sc->sc_fh_init_mask; } } void ItlIwx:: iwx_restore_interrupts(struct iwx_softc *sc) { IWX_WRITE(sc, IWX_CSR_INT_MASK, sc->sc_intmask); } void ItlIwx:: iwx_disable_interrupts(struct iwx_softc *sc) { int s = splnet(); if (!sc->sc_msix) { IWX_WRITE(sc, IWX_CSR_INT_MASK, 0); /* acknowledge all interrupts */ IWX_WRITE(sc, IWX_CSR_INT, ~0); IWX_WRITE(sc, IWX_CSR_FH_INT_STATUS, ~0); } else { IWX_WRITE(sc, IWX_CSR_MSIX_FH_INT_MASK_AD, sc->sc_fh_init_mask); IWX_WRITE(sc, IWX_CSR_MSIX_HW_INT_MASK_AD, sc->sc_hw_init_mask); } splx(s); } void ItlIwx:: iwx_ict_reset(struct iwx_softc *sc) { iwx_disable_interrupts(sc); memset(sc->ict_dma.vaddr, 0, IWX_ICT_SIZE); sc->ict_cur = 0; /* Set physical address of ICT (4KB aligned). */ IWX_WRITE(sc, IWX_CSR_DRAM_INT_TBL_REG, IWX_CSR_DRAM_INT_TBL_ENABLE | IWX_CSR_DRAM_INIT_TBL_WRAP_CHECK | IWX_CSR_DRAM_INIT_TBL_WRITE_POINTER | sc->ict_dma.paddr >> IWX_ICT_PADDR_SHIFT); /* Switch to ICT interrupt mode in driver. */ sc->sc_flags |= IWX_FLAG_USE_ICT; IWX_WRITE(sc, IWX_CSR_INT, sc->sc_intmask); iwx_enable_interrupts(sc); } #define IWX_HW_READY_TIMEOUT 50 int ItlIwx:: iwx_set_hw_ready(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); int ready; IWX_SETBITS(sc, IWX_CSR_HW_IF_CONFIG_REG, IWX_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); ready = iwx_poll_bit(sc, IWX_CSR_HW_IF_CONFIG_REG, IWX_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, IWX_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, IWX_HW_READY_TIMEOUT); if (ready) IWX_SETBITS(sc, IWX_CSR_MBOX_SET_REG, IWX_CSR_MBOX_SET_REG_OS_ALIVE); return ready; } #undef IWX_HW_READY_TIMEOUT int ItlIwx:: iwx_prepare_card_hw(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); int t = 0; int ntries; if (iwx_set_hw_ready(sc)) return 0; IWX_SETBITS(sc, IWX_CSR_DBG_LINK_PWR_MGMT_REG, IWX_CSR_RESET_LINK_PWR_MGMT_DISABLED); DELAY(1000); for (ntries = 0; ntries < 10; ntries++) { /* If HW is not ready, prepare the conditions to check again */ IWX_SETBITS(sc, IWX_CSR_HW_IF_CONFIG_REG, IWX_CSR_HW_IF_CONFIG_REG_PREPARE); do { if (iwx_set_hw_ready(sc)) return 0; DELAY(200); t += 200; } while (t < 150000); DELAY(25000); } return ETIMEDOUT; } void ItlIwx:: iwx_apm_config(struct iwx_softc *sc) { pcireg_t lctl, cap; /* * L0S states have been found to be unstable with our devices * and in newer hardware they are not officially supported at * all, so we must always set the L0S_DISABLED bit. */ IWX_SETBITS(sc, IWX_CSR_GIO_REG, IWX_CSR_GIO_REG_VAL_L0S_DISABLED); lctl = pci_conf_read(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_LCSR); /* * Disable L0s and L1s in PCIE register because we don't support ASPM now. */ lctl &= ~(PCI_PCIE_LCSR_ASPM_L0S | PCI_PCIE_LCSR_ASPM_L1); pci_conf_write(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_LCSR, lctl); lctl = pci_conf_read(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_LCSR); cap = pci_conf_read(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_DCSR2); sc->sc_ltr_enabled = (cap & PCI_PCIE_DCSR2_LTREN) ? 1 : 0; DPRINTF(("%s: L1 %sabled - LTR %sabled\n", DEVNAME(sc), (lctl & PCI_PCIE_LCSR_ASPM_L1) ? "En" : "Dis", sc->sc_ltr_enabled ? "En" : "Dis")); } /* * Start up NIC's basic functionality after it has been reset * e.g. after platform boot or shutdown. * NOTE: This does not load uCode nor start the embedded processor */ int ItlIwx:: iwx_apm_init(struct iwx_softc *sc) { int err = 0; /* * Disable L0s without affecting L1; * don't wait for ICH L0s (ICH bug W/A) */ IWX_SETBITS(sc, IWX_CSR_GIO_CHICKEN_BITS, IWX_CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); /* Set FH wait threshold to maximum (HW error during stress W/A) */ IWX_SETBITS(sc, IWX_CSR_DBG_HPET_MEM_REG, IWX_CSR_DBG_HPET_MEM_REG_VAL); /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s */ IWX_SETBITS(sc, IWX_CSR_HW_IF_CONFIG_REG, IWX_CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); iwx_apm_config(sc); /* * Set "initialization complete" bit to move adapter from * D0U* --> D0A* (powered-up active) state. */ IWX_SETBITS(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* * Wait for clock stabilization; once stabilized, access to * device-internal resources is supported, e.g. iwx_write_prph() * and accesses to uCode SRAM. */ if (!iwx_poll_bit(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, IWX_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000)) { XYLog("%s: timeout waiting for clock stabilization\n", DEVNAME(sc)); err = ETIMEDOUT; goto out; } out: if (err) XYLog("%s: apm init error %d\n", DEVNAME(sc), err); return err; } void ItlIwx:: iwx_apm_stop(struct iwx_softc *sc) { IWX_SETBITS(sc, IWX_CSR_DBG_LINK_PWR_MGMT_REG, IWX_CSR_RESET_LINK_PWR_MGMT_DISABLED); IWX_SETBITS(sc, IWX_CSR_HW_IF_CONFIG_REG, IWX_CSR_HW_IF_CONFIG_REG_PREPARE | IWX_CSR_HW_IF_CONFIG_REG_ENABLE_PME); DELAY(1000); IWX_CLRBITS(sc, IWX_CSR_DBG_LINK_PWR_MGMT_REG, IWX_CSR_RESET_LINK_PWR_MGMT_DISABLED); DELAY(5000); /* stop device's busmaster DMA activity */ IWX_SETBITS(sc, IWX_CSR_RESET, IWX_CSR_RESET_REG_FLAG_STOP_MASTER); if (!iwx_poll_bit(sc, IWX_CSR_RESET, IWX_CSR_RESET_REG_FLAG_MASTER_DISABLED, IWX_CSR_RESET_REG_FLAG_MASTER_DISABLED, 100)) XYLog("%s: timeout waiting for master\n", DEVNAME(sc)); /* * Clear "initialization complete" bit to move adapter from * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ IWX_CLRBITS(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_FLAG_INIT_DONE); } void ItlIwx:: iwx_init_msix_hw(struct iwx_softc *sc) { iwx_conf_msix_hw(sc, 0); if (!sc->sc_msix) return; sc->sc_fh_init_mask = ~IWX_READ(sc, IWX_CSR_MSIX_FH_INT_MASK_AD); sc->sc_fh_mask = sc->sc_fh_init_mask; sc->sc_hw_init_mask = ~IWX_READ(sc, IWX_CSR_MSIX_HW_INT_MASK_AD); sc->sc_hw_mask = sc->sc_hw_init_mask; } void ItlIwx:: iwx_conf_msix_hw(struct iwx_softc *sc, int stopped) { int vector = 0; if (!sc->sc_msix) { /* Newer chips default to MSIX. */ if (!stopped && iwx_nic_lock(sc)) { iwx_write_umac_prph(sc, IWX_UREG_CHICK, IWX_UREG_CHICK_MSI_ENABLE); iwx_nic_unlock(sc); } return; } if (!stopped && iwx_nic_lock(sc)) { iwx_write_umac_prph(sc, IWX_UREG_CHICK, IWX_UREG_CHICK_MSIX_ENABLE); iwx_nic_unlock(sc); } /* Disable all interrupts */ IWX_WRITE(sc, IWX_CSR_MSIX_FH_INT_MASK_AD, ~0); IWX_WRITE(sc, IWX_CSR_MSIX_HW_INT_MASK_AD, ~0); /* Map fallback-queue (command/mgmt) to a single vector */ IWX_WRITE_1(sc, IWX_CSR_MSIX_RX_IVAR(0), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); /* Map RSS queue (data) to the same vector */ IWX_WRITE_1(sc, IWX_CSR_MSIX_RX_IVAR(1), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); /* Enable the RX queues cause interrupts */ IWX_CLRBITS(sc, IWX_CSR_MSIX_FH_INT_MASK_AD, IWX_MSIX_FH_INT_CAUSES_Q0 | IWX_MSIX_FH_INT_CAUSES_Q1); /* Map non-RX causes to the same vector */ IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_D2S_CH0_NUM), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_D2S_CH1_NUM), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_S2D), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_FH_ERR), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_ALIVE), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_WAKEUP), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_IML), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_CT_KILL), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_RF_KILL), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_PERIODIC), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_SW_ERR), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_SCD), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_FH_TX), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_HW_ERR), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); IWX_WRITE_1(sc, IWX_CSR_MSIX_IVAR(IWX_MSIX_IVAR_CAUSE_REG_HAP), vector | IWX_MSIX_NON_AUTO_CLEAR_CAUSE); /* Enable non-RX causes interrupts */ IWX_CLRBITS(sc, IWX_CSR_MSIX_FH_INT_MASK_AD, IWX_MSIX_FH_INT_CAUSES_D2S_CH0_NUM | IWX_MSIX_FH_INT_CAUSES_D2S_CH1_NUM | IWX_MSIX_FH_INT_CAUSES_S2D | IWX_MSIX_FH_INT_CAUSES_FH_ERR); IWX_CLRBITS(sc, IWX_CSR_MSIX_HW_INT_MASK_AD, IWX_MSIX_HW_INT_CAUSES_REG_ALIVE | IWX_MSIX_HW_INT_CAUSES_REG_WAKEUP | IWX_MSIX_HW_INT_CAUSES_REG_IML | IWX_MSIX_HW_INT_CAUSES_REG_CT_KILL | IWX_MSIX_HW_INT_CAUSES_REG_RF_KILL | IWX_MSIX_HW_INT_CAUSES_REG_PERIODIC | IWX_MSIX_HW_INT_CAUSES_REG_SW_ERR | IWX_MSIX_HW_INT_CAUSES_REG_SCD | IWX_MSIX_HW_INT_CAUSES_REG_FH_TX | IWX_MSIX_HW_INT_CAUSES_REG_HW_ERR | IWX_MSIX_HW_INT_CAUSES_REG_HAP); } int ItlIwx:: iwx_start_hw(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); int err; err = iwx_prepare_card_hw(sc); if (err) return err; iwx_clear_persistence_bit(sc); /* Reset the entire device */ IWX_SETBITS(sc, IWX_CSR_RESET, IWX_CSR_RESET_REG_FLAG_SW_RESET); DELAY(5000); if (sc->sc_device_family == IWX_DEVICE_FAMILY_22000 && sc->sc_integrated) { IWX_SETBITS(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_FLAG_INIT_DONE); DELAY(20); if (!iwx_poll_bit(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, IWX_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000)) { XYLog("%s: timeout waiting for clock stabilization\n", DEVNAME(sc)); return ETIMEDOUT; } iwx_force_power_gating(sc); /* Reset the entire device */ IWX_SETBITS(sc, IWX_CSR_RESET, IWX_CSR_RESET_REG_FLAG_SW_RESET); DELAY(5000); } err = iwx_apm_init(sc); if (err) return err; iwx_init_msix_hw(sc); iwx_enable_rfkill_int(sc); iwx_check_rfkill(sc); return 0; } void ItlIwx:: iwx_stop_device(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); int qid; iwx_disable_interrupts(sc); sc->sc_flags &= ~IWX_FLAG_USE_ICT; iwx_disable_rx_dma(sc); iwx_reset_rx_ring(sc, &sc->rxq); for (qid = 0; qid < nitems(sc->txq); qid++) iwx_reset_tx_ring(sc, &sc->txq[qid]); /* Make sure (redundant) we've released our request to stay awake */ IWX_CLRBITS(sc, IWX_CSR_GP_CNTRL, IWX_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); if (sc->sc_nic_locks > 0) XYLog("%s: %d active NIC locks forcefully cleared\n", DEVNAME(sc), sc->sc_nic_locks); sc->sc_nic_locks = 0; /* Stop the device, and put it in low power state */ iwx_apm_stop(sc); /* Reset the on-board processor. */ IWX_SETBITS(sc, IWX_CSR_RESET, IWX_CSR_RESET_REG_FLAG_SW_RESET); DELAY(5000); /* * Upon stop, the IVAR table gets erased, so msi-x won't * work. This causes a bug in RF-KILL flows, since the interrupt * that enables radio won't fire on the correct irq, and the * driver won't be able to handle the interrupt. * Configure the IVAR table again after reset. */ iwx_conf_msix_hw(sc, 1); /* * Upon stop, the APM issues an interrupt if HW RF kill is set. * Clear the interrupt again. */ iwx_disable_interrupts(sc); /* Even though we stop the HW we still want the RF kill interrupt. */ iwx_enable_rfkill_int(sc); iwx_check_rfkill(sc); iwx_prepare_card_hw(sc); iwx_ctxt_info_free_paging(sc); /* free gen3 devices related firmware DMA resource */ iwx_dma_contig_free(&sc->prph_info_dma); iwx_dma_contig_free(&sc->prph_scratch_dma); iwx_dma_contig_free(&sc->iml_dma); iwx_dma_contig_free(&sc->pnvm_dram); } void ItlIwx:: iwx_nic_config(struct iwx_softc *sc) { uint8_t radio_cfg_type, radio_cfg_step, radio_cfg_dash; uint32_t mask, val, reg_val = 0; radio_cfg_type = (sc->sc_fw_phy_config & IWX_FW_PHY_CFG_RADIO_TYPE) >> IWX_FW_PHY_CFG_RADIO_TYPE_POS; radio_cfg_step = (sc->sc_fw_phy_config & IWX_FW_PHY_CFG_RADIO_STEP) >> IWX_FW_PHY_CFG_RADIO_STEP_POS; radio_cfg_dash = (sc->sc_fw_phy_config & IWX_FW_PHY_CFG_RADIO_DASH) >> IWX_FW_PHY_CFG_RADIO_DASH_POS; reg_val |= IWX_CSR_HW_REV_STEP(sc->sc_hw_rev) << IWX_CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; reg_val |= IWX_CSR_HW_REV_DASH(sc->sc_hw_rev) << IWX_CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; /* radio configuration */ reg_val |= radio_cfg_type << IWX_CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; reg_val |= radio_cfg_step << IWX_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; reg_val |= radio_cfg_dash << IWX_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; mask = IWX_CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | IWX_CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | IWX_CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | IWX_CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | IWX_CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | IWX_CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | IWX_CSR_HW_IF_CONFIG_REG_BIT_MAC_SI; val = IWX_READ(sc, IWX_CSR_HW_IF_CONFIG_REG); val &= ~mask; val |= reg_val; IWX_WRITE(sc, IWX_CSR_HW_IF_CONFIG_REG, val); XYLog("%s Radio type=0x%x-0x%x-0x%x\n", __FUNCTION__, radio_cfg_type, radio_cfg_step, radio_cfg_dash); } int ItlIwx:: iwx_nic_rx_init(struct iwx_softc *sc) { IWX_WRITE_1(sc, IWX_CSR_INT_COALESCING, IWX_HOST_INT_TIMEOUT_DEF); /* * We don't configure the RFH; the firmware will do that. * Rx descriptors are set when firmware sends an ALIVE interrupt. */ return 0; } int ItlIwx:: iwx_nic_init(struct iwx_softc *sc) { int err; iwx_apm_init(sc); iwx_nic_config(sc); err = iwx_nic_rx_init(sc); if (err) return err; IWX_SETBITS(sc, IWX_CSR_MAC_SHADOW_REG_CTRL, 0x800fffff); return 0; } /* Map ieee80211_edca_ac categories to firmware Tx FIFO. */ const uint8_t iwx_ac_to_tx_fifo[] = { IWX_GEN2_EDCA_TX_FIFO_BE, IWX_GEN2_EDCA_TX_FIFO_BK, IWX_GEN2_EDCA_TX_FIFO_VI, IWX_GEN2_EDCA_TX_FIFO_VO, }; int ItlIwx:: iwx_enable_txq(struct iwx_softc *sc, int sta_id, int qid, int tid, int num_slots) { XYLog("%s\n", __FUNCTION__); struct iwx_tx_queue_cfg_cmd cmd; struct iwx_rx_packet *pkt; struct iwx_tx_queue_cfg_rsp *resp; struct iwx_host_cmd hcmd = { .id = IWX_SCD_QUEUE_CFG, .flags = IWX_CMD_WANT_RESP, .resp_pkt_len = sizeof(*pkt) + sizeof(*resp), }; struct iwx_tx_ring *ring = &sc->txq[qid]; int err, fwqid; uint32_t wr_idx; size_t resp_len; iwx_reset_tx_ring(sc, ring); memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = sta_id; cmd.tid = tid; cmd.flags = htole16(IWX_TX_QUEUE_CFG_ENABLE_QUEUE); cmd.cb_size = htole32(IWX_TFD_QUEUE_CB_SIZE(num_slots)); cmd.byte_cnt_addr = htole64(ring->bc_tbl.paddr); cmd.tfdq_addr = htole64(ring->desc_dma.paddr); hcmd.data[0] = &cmd; hcmd.len[0] = sizeof(cmd); err = iwx_send_cmd(sc, &hcmd); if (err) return err; pkt = hcmd.resp_pkt; if (!pkt || (pkt->hdr.group_id & IWX_CMD_FAILED_MSK)) { DPRINTF(("SCD_QUEUE_CFG command failed\n")); err = EIO; goto out; } resp_len = iwx_rx_packet_payload_len(pkt); if (resp_len != sizeof(*resp)) { DPRINTF(("SCD_QUEUE_CFG returned %zu bytes, expected %zu bytes\n", resp_len, sizeof(*resp))); err = EIO; goto out; } resp = (struct iwx_tx_queue_cfg_rsp *)pkt->data; fwqid = le16toh(resp->queue_number); wr_idx = le16toh(resp->write_pointer); /* Unlike iwlwifi, we do not support dynamic queue ID assignment. */ if (fwqid != qid) { DPRINTF(("requested qid %d but %d was assigned\n", qid, fwqid)); err = EIO; goto out; } if (wr_idx != ring->cur) { DPRINTF(("fw write index is %d but ring is %d\n", wr_idx, ring->cur)); err = EIO; goto out; } out: iwx_free_resp(sc, &hcmd); return err; } int ItlIwx:: iwx_tvqm_alloc_txq(struct iwx_softc *sc, int tid, int ssn) { int queue; //TODO: Here is a bug, for gen3 devices which support 256 frame aggregate into 1 A-MPDU like ax210, if the TfDs count larger than 256 than it would trigger system freeze on macOS, don't know why but Linux can do this. Still need to dig deep into the code or optimize the DMA memory allocation, here I just limit the size to 256 as the temporary solution. #ifdef notyet int size = sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210 ? IWX_MIN_256_BA_QUEUE_SIZE_GEN3 : IWX_DEFAULT_QUEUE_SIZE; #else int size = IWX_DEFAULT_QUEUE_SIZE; #endif do { queue = iwx_tvqm_enable_txq(sc, tid, ssn, size); if (queue < 0) XYLog("Failed allocating TXQ of size %d for sta %d tid %d, ret: %d\n", size, IWX_STATION_ID, tid, queue); size /= 2; } while (queue < 0 && size >= 16); if (queue < 0) return queue; sc->sc_tid_data[tid].qid = queue; return queue; } int ItlIwx:: iwx_tvqm_enable_txq(struct iwx_softc *sc, int tid, int ssn, uint32_t size) { int err = -1; int i = 0; bus_addr_t paddr; int fwqid; uint32_t wr_idx; size_t resp_len; struct iwx_tx_queue_cfg_cmd cmd = { .flags = htole16(IWX_TX_QUEUE_CFG_ENABLE_QUEUE), .sta_id = IWX_STATION_ID, .tid = (uint8_t)tid, }; struct iwx_rx_packet *pkt; struct iwx_tx_queue_cfg_rsp *resp; struct iwx_host_cmd hcmd = { .id = IWX_SCD_QUEUE_CFG, .flags = IWX_CMD_WANT_RESP, .resp_pkt_len = sizeof(*pkt) + sizeof(*resp), }; struct iwx_tx_ring *ring = &sc->sc_tvqm_ring; memset(ring, 0, sizeof(*ring)); iwx_tx_ring_init(sc, ring, size); /* Allocate TX descriptors (256-byte aligned). */ err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, ring->ring_count * sizeof (struct iwx_tfh_tfd), 256); if (err) { XYLog("%s: could not allocate TX ring DMA memory\n", DEVNAME(sc)); err = -ENOMEM; goto fail; } ring->desc = (struct iwx_tfh_tfd*)ring->desc_dma.vaddr; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->bc_tbl, sizeof(struct iwx_gen3_bc_tbl), 0); else err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->bc_tbl, sizeof(struct iwx_agn_scd_bc_tbl), 0); if (err) { XYLog("%s: could not allocate byte count table DMA memory\n", DEVNAME(sc)); err = -ENOMEM; goto fail; } err = iwx_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, ring->ring_count * sizeof(struct iwx_device_cmd), IWX_FIRST_TB_SIZE_ALIGN); if (err) { XYLog("%s: could not allocate cmd DMA memory\n", DEVNAME(sc)); err = -ENOMEM; goto fail; } ring->cmd = (struct iwx_device_cmd*)ring->cmd_dma.vaddr; paddr = ring->cmd_dma.paddr; for (i = 0; i < ring->ring_count; i++) { struct iwx_tx_data *data = &ring->data[i]; data->cmd_paddr = paddr; paddr += sizeof(struct iwx_device_cmd); err = bus_dmamap_create(sc->sc_dmat, MCLBYTES, IWX_TFH_NUM_TBS - 2, MCLBYTES, 0, BUS_DMA_NOWAIT, &data->map); if (err) { XYLog("%s: could not create TX buf DMA map\n", DEVNAME(sc)); err = -EIO; goto fail; } } cmd.cb_size = htole32(IWX_TFD_QUEUE_CB_SIZE(ring->ring_count)); cmd.byte_cnt_addr = htole64(ring->bc_tbl.paddr); cmd.tfdq_addr = htole64(ring->desc_dma.paddr); hcmd.data[0] = &cmd; hcmd.len[0] = sizeof(cmd); err = iwx_send_cmd(sc, &hcmd); if (err) return err; pkt = hcmd.resp_pkt; if (!pkt || (pkt->hdr.group_id & IWX_CMD_FAILED_MSK)) { XYLog("SCD_QUEUE_CFG command failed\n"); err = -EIO; goto fail; } resp_len = iwx_rx_packet_payload_len(pkt); if (resp_len != sizeof(*resp)) { XYLog("SCD_QUEUE_CFG returned %zu bytes, expected %zu bytes\n", resp_len, sizeof(*resp)); err = -EIO; goto fail; } resp = (struct iwx_tx_queue_cfg_rsp *)pkt->data; fwqid = le16toh(resp->queue_number); wr_idx = le16toh(resp->write_pointer); if (fwqid >= ARRAY_SIZE(sc->txq)) { XYLog("queue index %d unsupported", fwqid); err = -EIO; goto fail; } ring->cur = wr_idx; ring->qid = fwqid; iwx_reset_tx_ring(sc, &sc->txq[fwqid]); iwx_free_tx_ring(sc, &sc->txq[fwqid]); memcpy(&sc->txq[fwqid], ring, sizeof(*ring)); return fwqid; fail: iwx_reset_tx_ring(sc, ring); iwx_free_tx_ring(sc, ring); return err; } void ItlIwx:: iwx_post_alive(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); iwx_ict_reset(sc); /* * Re-enable all the interrupts, including the RF-Kill one, now that * the firmware is alive. */ iwx_enable_interrupts(sc); } /* * For the high priority TE use a time event type that has similar priority to * the FW's action scan priority. */ #define IWX_ROC_TE_TYPE_NORMAL IWX_TE_P2P_DEVICE_DISCOVERABLE #define IWX_ROC_TE_TYPE_MGMT_TX IWX_TE_P2P_CLIENT_ASSOC int ItlIwx:: iwx_send_time_event_cmd(struct iwx_softc *sc, const struct iwx_time_event_cmd *cmd) { struct iwx_rx_packet *pkt; struct iwx_time_event_resp *resp; struct iwx_host_cmd hcmd = { .id = IWX_TIME_EVENT_CMD, .flags = IWX_CMD_WANT_RESP, .resp_pkt_len = sizeof(*pkt) + sizeof(*resp), }; uint32_t resp_len; int err; hcmd.data[0] = cmd; hcmd.len[0] = sizeof(*cmd); err = iwx_send_cmd(sc, &hcmd); if (err) return err; pkt = hcmd.resp_pkt; if (!pkt || (pkt->hdr.group_id & IWX_CMD_FAILED_MSK)) { err = EIO; goto out; } resp_len = iwx_rx_packet_payload_len(pkt); if (resp_len != sizeof(*resp)) { err = EIO; goto out; } resp = (struct iwx_time_event_resp *)pkt->data; if (le32toh(resp->status) == 0) sc->sc_time_event_uid = le32toh(resp->unique_id); else err = EIO; out: iwx_free_resp(sc, &hcmd); return err; } void ItlIwx:: iwx_protect_session(struct iwx_softc *sc, struct iwx_node *in, uint32_t duration, uint32_t max_delay) { struct iwx_time_event_cmd time_cmd; /* Do nothing if a time event is already scheduled. */ if (sc->sc_flags & IWX_FLAG_TE_ACTIVE) return; memset(&time_cmd, 0, sizeof(time_cmd)); time_cmd.action = htole32(IWX_FW_CTXT_ACTION_ADD); time_cmd.id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); time_cmd.id = htole32(IWX_TE_BSS_STA_AGGRESSIVE_ASSOC); time_cmd.apply_time = htole32(0); time_cmd.max_frags = IWX_TE_V2_FRAG_NONE; time_cmd.max_delay = htole32(max_delay); /* TODO: why do we need to interval = bi if it is not periodic? */ time_cmd.interval = htole32(1); time_cmd.duration = htole32(duration); time_cmd.repeat = 1; time_cmd.policy = htole16(IWX_TE_V2_NOTIF_HOST_EVENT_START | IWX_TE_V2_NOTIF_HOST_EVENT_END | IWX_T2_V2_START_IMMEDIATELY); if (iwx_send_time_event_cmd(sc, &time_cmd) == 0) sc->sc_flags |= IWX_FLAG_TE_ACTIVE; DELAY(100); } int ItlIwx:: iwx_schedule_protect_session(struct iwx_softc *sc, struct iwx_node *in, uint32_t duration) { struct iwx_session_prot_cmd cmd = { .id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)), .action = htole32(IWX_FW_CTXT_ACTION_ADD), .duration_tu = htole32(duration * IEEE80211_DUR_TU), }; int err; cmd.conf_id = IWX_SESSION_PROTECT_CONF_ASSOC; DPRINTFN(1, ("Add new session protection, duration %d TU\n", htole32(cmd.duration_tu))); err = iwx_send_cmd_pdu(sc, iwx_cmd_id(IWX_SESSION_PROTECTION_CMD, IWX_MAC_CONF_GROUP, 0), 0, sizeof(cmd), &cmd); if (err) XYLog("Couldn't send the SESSION_PROTECTION_CMD %d\n", err); return err; } int ItlIwx:: iwx_cancel_session_protection(struct iwx_softc *sc, struct iwx_node *in) { struct iwx_session_prot_cmd cmd = { .id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)), .action = htole32(IWX_FW_CTXT_ACTION_REMOVE), .conf_id = IWX_SESSION_PROTECT_CONF_ASSOC, }; int err; DPRINTFN(1, ("Remove session protection\n")); err = iwx_send_cmd_pdu(sc, iwx_cmd_id(IWX_SESSION_PROTECTION_CMD, IWX_MAC_CONF_GROUP, 0), 0, sizeof(cmd), &cmd); if (err) XYLog("Couldn't send the Cancel SESSION_PROTECTION_CMD %d\n", err); return err; } void ItlIwx:: iwx_unprotect_session(struct iwx_softc *sc, struct iwx_node *in) { struct iwx_time_event_cmd time_cmd; /* Do nothing if the time event has already ended. */ if ((sc->sc_flags & IWX_FLAG_TE_ACTIVE) == 0) return; memset(&time_cmd, 0, sizeof(time_cmd)); time_cmd.action = htole32(IWX_FW_CTXT_ACTION_REMOVE); time_cmd.id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); time_cmd.id = htole32(sc->sc_time_event_uid); if (iwx_send_time_event_cmd(sc, &time_cmd) == 0) sc->sc_flags &= ~IWX_FLAG_TE_ACTIVE; DELAY(100); } /* * NVM read access and content parsing. We do not support * external NVM or writing NVM. */ uint8_t ItlIwx:: iwx_fw_valid_tx_ant(struct iwx_softc *sc) { uint8_t tx_ant; tx_ant = ((sc->sc_fw_phy_config & IWX_FW_PHY_CFG_TX_CHAIN) >> IWX_FW_PHY_CFG_TX_CHAIN_POS); if (sc->sc_nvm.valid_tx_ant) tx_ant &= sc->sc_nvm.valid_tx_ant; return tx_ant; } uint8_t ItlIwx:: iwx_fw_valid_rx_ant(struct iwx_softc *sc) { uint8_t rx_ant; rx_ant = ((sc->sc_fw_phy_config & IWX_FW_PHY_CFG_RX_CHAIN) >> IWX_FW_PHY_CFG_RX_CHAIN_POS); if (sc->sc_nvm.valid_rx_ant) rx_ant &= sc->sc_nvm.valid_rx_ant; return rx_ant; } void ItlIwx:: iwx_init_channel_map(struct iwx_softc *sc, uint16_t *channel_profile_v3, uint32_t *channel_profile_v4, int nchan_profile) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_nvm_data *data = &sc->sc_nvm; int ch_idx; struct ieee80211_channel *channel; uint32_t ch_flags; int is_5ghz; int flags, hw_value; int nchan; const uint8_t *nvm_channels; if (sc->sc_uhb_supported) { nchan = nitems(iwx_nvm_channels_uhb); nvm_channels = iwx_nvm_channels_uhb; } else { nchan = nitems(iwx_nvm_channels_8000); nvm_channels = iwx_nvm_channels_8000; } for (ch_idx = 0; ch_idx < nchan && ch_idx < nchan_profile; ch_idx++) { if (channel_profile_v4) ch_flags = le32_to_cpup(channel_profile_v4 + ch_idx); else ch_flags = le16_to_cpup(channel_profile_v3 + ch_idx); is_5ghz = ch_idx >= IWX_NUM_2GHZ_CHANNELS; if (is_5ghz && !data->sku_cap_band_52GHz_enable) ch_flags &= ~IWX_NVM_CHANNEL_VALID; if (ch_flags & IWX_NVM_CHANNEL_160MHZ) data->vht160_supported = true; hw_value = nvm_channels[ch_idx]; channel = &ic->ic_channels[hw_value]; if (!(ch_flags & IWX_NVM_CHANNEL_VALID)) { channel->ic_freq = 0; channel->ic_flags = 0; continue; } if (!is_5ghz) { flags = IEEE80211_CHAN_2GHZ; channel->ic_flags = IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; } else { flags = IEEE80211_CHAN_5GHZ; channel->ic_flags = IEEE80211_CHAN_A; } if (!(ch_flags & IWX_NVM_CHANNEL_ACTIVE)) channel->ic_flags |= IEEE80211_CHAN_PASSIVE; if (data->sku_cap_11n_enable) channel->ic_flags |= IEEE80211_CHAN_HT20; if (!is_5ghz && (ch_flags & IWX_NVM_CHANNEL_40MHZ)) { if (hw_value <= IWX_LAST_2GHZ_HT_PLUS) { channel->ic_flags |= IEEE80211_CHAN_HT40U; } if (hw_value >= IWX_FIRST_2GHZ_HT_MINUS) { channel->ic_flags |= IEEE80211_CHAN_HT40D; } } else if (ch_flags & IWX_NVM_CHANNEL_40MHZ) { if ((ch_idx - IWX_NUM_2GHZ_CHANNELS) % 2 == 0) { channel->ic_flags |= IEEE80211_CHAN_HT40U; } else { channel->ic_flags |= IEEE80211_CHAN_HT40D; } } if (data->sku_cap_11ac_enable) { if (ch_flags & IWX_NVM_CHANNEL_80MHZ) { channel->ic_flags |= IEEE80211_CHAN_VHT80; } if (ch_flags & IWX_NVM_CHANNEL_160MHZ) { channel->ic_flags |= IEEE80211_CHAN_VHT160; } } if (ch_flags & IWX_NVM_CHANNEL_DFS) { channel->ic_flags |= IEEE80211_CHAN_DFS; } channel->ic_freq = ieee80211_ieee2mhz(hw_value, flags); DPRINTFN(3, ("Ch. %d Flags %x [%sGHz] - No traffic\n", hw_value, channel->ic_flags, (!IEEE80211_IS_CHAN_2GHZ(channel)) ? "5.2" : "2.4")); } } int ItlIwx:: iwx_mimo_enabled(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; return !sc->sc_nvm.sku_cap_mimo_disable && (ic->ic_userflags & IEEE80211_F_NOMIMO) == 0; } void ItlIwx:: iwx_setup_ht_rates(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; uint8_t rx_ant; /* TX is supported with the same MCS as RX. */ ic->ic_tx_mcs_set = IEEE80211_TX_MCS_SET_DEFINED; memset(ic->ic_sup_mcs, 0, sizeof(ic->ic_sup_mcs)); ic->ic_sup_mcs[0] = 0xff; /* MCS 0-7 */ if (!iwx_mimo_enabled(sc)) return; rx_ant = iwx_fw_valid_rx_ant(sc); if ((rx_ant & IWX_ANT_AB) == IWX_ANT_AB || (rx_ant & IWX_ANT_BC) == IWX_ANT_BC) ic->ic_sup_mcs[1] = 0xff; /* MCS 8-15 */ } void ItlIwx:: iwx_init_reorder_buffer(struct iwx_reorder_buffer *reorder_buf, uint16_t ssn, uint16_t buf_size) { reorder_buf->head_sn = ssn; reorder_buf->num_stored = 0; reorder_buf->buf_size = buf_size; reorder_buf->last_amsdu = 0; reorder_buf->last_sub_index = 0; reorder_buf->removed = 0; reorder_buf->valid = 0; reorder_buf->consec_oldsn_drops = 0; reorder_buf->consec_oldsn_ampdu_gp2 = 0; reorder_buf->consec_oldsn_prev_drop = 0; } void ItlIwx:: iwx_clear_reorder_buffer(struct iwx_softc *sc, struct iwx_rxba_data *rxba) { int i; struct iwx_reorder_buffer *reorder_buf = &rxba->reorder_buf; struct iwx_reorder_buf_entry *entry; for (i = 0; i < reorder_buf->buf_size; i++) { entry = &rxba->entries[i]; ml_purge(&entry->frames); timerclear(&entry->reorder_time); } reorder_buf->removed = 1; timeout_del(&reorder_buf->reorder_timer); timeout_free(&reorder_buf->reorder_timer); timerclear(&rxba->last_rx); timeout_del(&rxba->session_timer); timeout_free(&rxba->session_timer); rxba->baid = IWX_RX_REORDER_DATA_INVALID_BAID; } #define RX_REORDER_BUF_TIMEOUT_MQ_USEC (100000ULL) void ItlIwx:: iwx_rx_ba_session_expired(void *arg) { XYLog("%s\n", __FUNCTION__); struct iwx_rxba_data *rxba = (struct iwx_rxba_data *)arg; struct iwx_softc *sc = rxba->sc; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; struct timeval now, timeout, expiry; int s; s = splnet(); if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0 && ic->ic_state == IEEE80211_S_RUN && rxba->baid != IWX_RX_REORDER_DATA_INVALID_BAID) { getmicrouptime(&now); USEC_TO_TIMEVAL(RX_REORDER_BUF_TIMEOUT_MQ_USEC, &timeout); timeradd(&rxba->last_rx, &timeout, &expiry); if (timercmp(&now, &expiry, <)) { timeout_add_usec(&rxba->session_timer, rxba->timeout); } else { ic->ic_stats.is_ht_rx_ba_timeout++; ieee80211_delba_request(ic, ni, IEEE80211_REASON_TIMEOUT, 0, rxba->tid); } } splx(s); } void ItlIwx:: iwx_reorder_timer_expired(void *arg) { XYLog("%s\n", __FUNCTION__); struct mbuf_list ml = MBUF_LIST_INITIALIZER(); struct iwx_reorder_buffer *buf = (struct iwx_reorder_buffer *)arg; struct iwx_rxba_data *rxba = iwx_rxba_data_from_reorder_buf(buf); struct iwx_reorder_buf_entry *entries = &rxba->entries[0]; struct iwx_softc *sc = rxba->sc; ItlIwx *that = container_of(sc, ItlIwx, com); struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; int i, s; uint16_t sn = 0, index = 0; int expired = 0; int cont = 0; struct timeval now, timeout, expiry; if (!buf->num_stored || buf->removed) return; s = splnet(); getmicrouptime(&now); USEC_TO_TIMEVAL(RX_REORDER_BUF_TIMEOUT_MQ_USEC, &timeout); for (i = 0; i < buf->buf_size ; i++) { index = (buf->head_sn + i) % buf->buf_size; if (ml_empty(&entries[index].frames)) { /* * If there is a hole and the next frame didn't expire * we want to break and not advance SN. */ cont = 0; continue; } timeradd(&entries[index].reorder_time, &timeout, &expiry); if (!cont && timercmp(&now, &expiry, <)) break; expired = 1; /* continue until next hole after this expired frame */ cont = 1; sn = (buf->head_sn + (i + 1)) & 0xfff; } if (expired) { /* SN is set to the last expired frame + 1 */ that->iwx_release_frames(sc, ni, rxba, buf, sn, &ml); if_input(&sc->sc_ic.ic_if, &ml); ic->ic_stats.is_ht_rx_ba_window_gap_timeout++; } else { /* * If no frame expired and there are stored frames, index is now * pointing to the first unexpired frame - modify reorder timeout * accordingly. */ timeout_add_usec(&buf->reorder_timer, RX_REORDER_BUF_TIMEOUT_MQ_USEC); } splx(s); } static inline uint8_t iwx_num_of_ant(uint8_t mask) { return !!((mask) & IWX_ANT_A) + !!((mask) & IWX_ANT_B) + !!((mask) & IWX_ANT_C); } void ItlIwx:: iwx_setup_vht_rates(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; uint8_t rx_ant, tx_ant; unsigned int max_ampdu_exponent = IEEE80211_VHTCAP_MAX_AMPDU_1024K; if (ic->ic_userflags & IEEE80211_F_NOVHT) return; /* enable 11ac support */ ic->ic_flags |= IEEE80211_F_VHTON; rx_ant = iwx_num_of_ant(iwx_fw_valid_rx_ant(sc)); tx_ant = iwx_num_of_ant(iwx_fw_valid_tx_ant(sc)); ic->ic_vhtcaps = IEEE80211_VHTCAP_SHORT_GI_80 | IEEE80211_VHTCAP_RXSTBC_1 | IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE | 3 << IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT | max_ampdu_exponent << IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT | IEEE80211_VHTCAP_MU_BEAMFORMEE_CAPABLE; if (sc->sc_nvm.vht160_supported) ic->ic_vhtcaps |= IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ | IEEE80211_VHTCAP_SHORT_GI_160; if (!iwx_mimo_enabled(sc)) { rx_ant = 1; tx_ant = 1; } ic->ic_vhtcaps |= IEEE80211_VHTCAP_RXLDPC; if (tx_ant > 1) ic->ic_vhtcaps |= IEEE80211_VHTCAP_TXSTBC; else ic->ic_vhtcaps |= IEEE80211_VHTCAP_TX_ANTENNA_PATTERN; ic->ic_vht_rx_mcs_map = htole16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); if (rx_ant == 1) { ic->ic_vhtcaps |= IEEE80211_VHTCAP_RX_ANTENNA_PATTERN; /* this works because NOT_SUPPORTED == 3 */ ic->ic_vht_rx_mcs_map |= htole16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2); } ic->ic_vht_tx_mcs_map = ic->ic_vht_rx_mcs_map; ic->ic_vht_tx_highest |= htole16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); ic->ic_vht_rx_highest = 0; memset(ic->ic_vht_sup_mcs, 0, sizeof(ic->ic_vht_sup_mcs)); ic->ic_vht_sup_mcs[0] = 0x03FF; /* MCS 0-9 */ if (!iwx_mimo_enabled(sc)) return; ic->ic_vht_sup_mcs[1] = 0x03FF; /* MCS 0-9 */ } void ItlIwx:: iwx_setup_he_rates(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; /* enable 11ax support */ // ic->ic_flags |= IEEE80211_F_HEON; ic->ic_he_cap_elem = { .mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE | IEEE80211_HE_MAC_CAP0_TWT_REQ, .mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, .mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP, .mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU | IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, .mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 | IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 | IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU | IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS | IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX, .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, .phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, .phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM | IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, .phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, .phy_cap_info[5] = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, .phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB | IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, .phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP7_MAX_NC_1, .phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996, .phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, }; /* * Set default Tx/Rx HE MCS NSS Support field. * Indicate support for up to 2 spatial streams and all * MCS, without any special cases */ ic->ic_he_mcs_nss_supp = { .rx_mcs_80 = htole16(0xfffa), .tx_mcs_80 = htole16(0xfffa), .rx_mcs_160 = htole16(0xfffa), .tx_mcs_160 = htole16(0xfffa), .rx_mcs_80p80 = htole16(0xffff), .tx_mcs_80p80 = htole16(0xffff), }; /* * Set default PPE thresholds, with PPET16 set to 0, * PPET8 set to 7 */ uint8_t ppe_thres[] = {0x61, 0x1c, 0xc7, 0x71}; memcpy(ic->ic_ppe_thres, ppe_thres, sizeof(ic->ic_ppe_thres)); } #define IWX_MAX_RX_BA_SESSIONS 16 void ItlIwx:: iwx_sta_rx_agg(struct iwx_softc *sc, struct ieee80211_node *ni, uint8_t tid, uint16_t ssn, uint16_t winsize, int timeout_val, int start) { XYLog("%s start=%d tid=%d ssn=%d winsize=%d\n", __FUNCTION__, start, tid, ssn, winsize); struct ieee80211com *ic = &sc->sc_ic; struct iwx_add_sta_cmd cmd; struct iwx_node *in = (struct iwx_node *)ni; int err, s; uint32_t status; struct iwx_rxba_data *rxba = NULL; uint8_t baid = 0; s = splnet(); if (start && sc->sc_rx_ba_sessions >= IWX_MAX_RX_BA_SESSIONS) { ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return; } memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = IWX_STATION_ID; cmd.mac_id_n_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); cmd.add_modify = IWX_STA_MODE_MODIFY; if (start) { cmd.add_immediate_ba_tid = (uint8_t)tid; cmd.add_immediate_ba_ssn = htole16(ssn); cmd.rx_ba_window = htole16(winsize); } else { cmd.remove_immediate_ba_tid = (uint8_t)tid; } cmd.modify_mask = start ? IWX_STA_MODIFY_ADD_BA_TID : IWX_STA_MODIFY_REMOVE_BA_TID; status = IWX_ADD_STA_SUCCESS; err = iwx_send_cmd_pdu_status(sc, IWX_ADD_STA, sizeof(cmd), &cmd, &status); if (err || (status & IWX_ADD_STA_STATUS_MASK) != IWX_ADD_STA_SUCCESS) { if (start) ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return; } /* Deaggregation is done in hardware. */ if (start) { if (!(status & IWX_ADD_STA_BAID_VALID_MASK)) { ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return; } baid = (status & IWX_ADD_STA_BAID_MASK) >> IWX_ADD_STA_BAID_SHIFT; if (baid == IWX_RX_REORDER_DATA_INVALID_BAID || baid >= nitems(sc->sc_rxba_data)) { ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return; } rxba = &sc->sc_rxba_data[baid]; if (rxba->baid != IWX_RX_REORDER_DATA_INVALID_BAID) { ieee80211_addba_req_refuse(ic, ni, tid); splx(s); return; } rxba->sta_id = IWX_STATION_ID; rxba->tid = tid; rxba->baid = baid; rxba->timeout = timeout_val; getmicrouptime(&rxba->last_rx); iwx_init_reorder_buffer(&rxba->reorder_buf, ssn, winsize); if (timeout_val != 0) { struct ieee80211_rx_ba *ba; timeout_add_usec(&rxba->session_timer, timeout_val); /* XXX disable net80211's BA timeout handler */ ba = &ni->ni_rx_ba[tid]; ba->ba_timeout_val = 0; } } else { int i; for (i = 0; i < nitems(sc->sc_rxba_data); i++) { rxba = &sc->sc_rxba_data[i]; if (rxba->baid == IWX_RX_REORDER_DATA_INVALID_BAID) continue; if (rxba->tid != tid) continue; iwx_clear_reorder_buffer(sc, rxba); break; } } if (start) { sc->sc_rx_ba_sessions++; ieee80211_addba_req_accept(ic, ni, tid); } else if (sc->sc_rx_ba_sessions > 0) sc->sc_rx_ba_sessions--; splx(s); } void ItlIwx:: iwx_mac_ctxt_task(void *arg) { struct iwx_softc *sc = (struct iwx_softc *)arg; struct ieee80211com *ic = &sc->sc_ic; ItlIwx *that = container_of(sc, ItlIwx, com); struct iwx_node *in = (struct iwx_node *)ic->ic_bss; int err, s = splnet(); if (sc->sc_flags & IWX_FLAG_SHUTDOWN || ic->ic_state != IEEE80211_S_RUN || in->in_phyctxt == NULL) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } err = that->iwx_mac_ctxt_cmd(sc, in, IWX_FW_CTXT_ACTION_MODIFY, 1); if (err) printf("%s: failed to update MAC\n", DEVNAME(sc)); if (!isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_SESSION_PROT_CMD)) that->iwx_unprotect_session(sc, in); // refcnt_rele_wake(&sc->task_refs); splx(s); } void ItlIwx:: iwx_chan_ctxt_task(void *arg) { struct iwx_softc *sc = (struct iwx_softc *)arg; struct ieee80211com *ic = &sc->sc_ic; ItlIwx *that = container_of(sc, ItlIwx, com); struct iwx_node *in = (struct iwx_node *)ic->ic_bss; int chains = that->iwx_mimo_enabled(sc) ? 2 : 1; int err, s = splnet(); if (sc->sc_flags & IWX_FLAG_SHUTDOWN || ic->ic_state != IEEE80211_S_RUN || in->in_phyctxt == NULL) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } err = that->iwx_phy_ctxt_update(sc, in->in_phyctxt, in->in_phyctxt->channel, chains, chains, 0); if (err) { XYLog("%s: failed to update PHY (error %d)\n", __FUNCTION__, err); // refcnt_rele_wake(&sc->task_refs); splx(s); return; } err = that->iwx_rs_init(sc, in, true); if (err) { XYLog("%s: could not update rate scaling (error %d)\n", __FUNCTION__, err); // refcnt_rele_wake(&sc->task_refs); splx(s); return; } // refcnt_rele_wake(&sc->task_refs); splx(s); } void ItlIwx:: iwx_update_chw(struct ieee80211com *ic) { struct iwx_softc *sc = (struct iwx_softc *)ic->ic_softc; ItlIwx *that = container_of(sc, ItlIwx, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWX_FLAG_STA_ACTIVE)) that->iwx_add_task(sc, systq, &sc->chan_ctxt_task); } void ItlIwx:: iwx_updateprot(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwx_softc *sc = (struct iwx_softc *)ic->ic_softc; ItlIwx *that = container_of(sc, ItlIwx, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWX_FLAG_STA_ACTIVE)) that->iwx_add_task(sc, systq, &sc->mac_ctxt_task); } void ItlIwx:: iwx_updateslot(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwx_softc *sc = (struct iwx_softc *)ic->ic_softc; ItlIwx *that = container_of(sc, ItlIwx, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWX_FLAG_STA_ACTIVE)) that->iwx_add_task(sc, systq, &sc->mac_ctxt_task); } void ItlIwx:: iwx_updateedca(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwx_softc *sc = (struct iwx_softc *)ic->ic_softc; ItlIwx *that = container_of(sc, ItlIwx, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWX_FLAG_STA_ACTIVE)) that->iwx_add_task(sc, systq, &sc->mac_ctxt_task); } void ItlIwx:: iwx_updatedtim(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwx_softc *sc = (struct iwx_softc *)ic->ic_softc; ItlIwx *that = container_of(sc, ItlIwx, com); if (ic->ic_state == IEEE80211_S_RUN && (sc->sc_flags & IWX_FLAG_STA_ACTIVE)) that->iwx_add_task(sc, systq, &sc->mac_ctxt_task); } void ItlIwx:: iwx_ba_task(void *arg) { struct iwx_softc *sc = (struct iwx_softc *)arg; struct ieee80211com *ic = &sc->sc_ic; ItlIwx *that = container_of(sc, ItlIwx, com); struct ieee80211_node *ni = ic->ic_bss; struct ieee80211_tx_ba *ba; struct iwx_tx_ring *ring; int s = splnet(); int err = 0; int qid = 0; int tid; if (sc->sc_flags & IWX_FLAG_SHUTDOWN) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } for (tid = 0; tid < IWX_MAX_TID_COUNT; tid++) { if (sc->sc_flags & IWX_FLAG_SHUTDOWN) break; if (sc->ba_rx.start_tidmask & (1 << tid)) { struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; XYLog("%s ba_rx_start tid=%d, ssn=%d\n", __FUNCTION__, tid, ba->ba_winstart); that->iwx_sta_rx_agg(sc, ni, tid, ba->ba_winstart, ba->ba_winsize, ba->ba_timeout_val, 1); sc->ba_rx.start_tidmask &= ~(1 << tid); } else if (sc->ba_rx.stop_tidmask & (1 << tid)) { that->iwx_sta_rx_agg(sc, ni, tid, 0, 0, 0, 0); sc->ba_rx.stop_tidmask &= ~(1 << tid); } } for (tid = 0; tid < IWX_MAX_TID_COUNT; tid++) { if (sc->sc_flags & IWX_FLAG_SHUTDOWN) break; if (sc->ba_tx.start_tidmask & (1 << tid)) { ba = &ni->ni_tx_ba[tid]; XYLog("%s ba_tx_start tid=%d, ssn=%d\n", __FUNCTION__, tid, ba->ba_winstart); if (!that->iwx_nic_lock(sc)) { err = -1; goto out; } if ((qid = that->iwx_tvqm_alloc_txq(sc, tid, ba->ba_winstart)) < 0) { err = -1; goto out; } ring = &sc->txq[qid]; ba->ba_winstart = IWX_AGG_SSN_TO_TXQ_IDX(ring->cur, ring->ring_count); ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; ba->ba_timeout_val = 0; ieee80211_addba_resp_accept(ic, ni, tid); XYLog("%s tx queue alloc succeed qid=%d ssn=%d\n", __FUNCTION__, qid, ba->ba_winstart); out: that->iwx_nic_unlock(sc); if (err) ieee80211_addba_resp_refuse(ic, ni, tid, IEEE80211_STATUS_UNSPECIFIED); sc->ba_tx.start_tidmask &= ~(1 << tid); } } // refcnt_rele_wake(&sc->task_refs); splx(s); } /* * This function is called by upper layer when an ADDBA request is received * from another STA and before the ADDBA response is sent. */ int ItlIwx:: iwx_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct iwx_softc *sc = (struct iwx_softc *)IC2IFP(ic)->if_softc; ItlIwx *that = container_of(sc, ItlIwx, com); if (sc->sc_rx_ba_sessions >= IWX_MAX_RX_BA_SESSIONS || tid >= IWX_MAX_TID_COUNT) return ENOSPC; if (ic->ic_state != IEEE80211_S_RUN) return ENOSPC; if (sc->ba_rx.start_tidmask & (1 << tid)) return EBUSY; sc->ba_rx.start_tidmask |= (1 << tid); that->iwx_add_task(sc, systq, &sc->ba_task); return EBUSY; } /* * This function is called by upper layer on teardown of an HT-immediate * Block Ack agreement (eg. upon receipt of a DELBA frame). */ void ItlIwx:: iwx_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct iwx_softc *sc = (struct iwx_softc *)IC2IFP(ic)->if_softc; ItlIwx *that = container_of(sc, ItlIwx, com); if (tid >= IWX_MAX_TID_COUNT || sc->ba_rx.stop_tidmask & (1 << tid)) return; if (ic->ic_state != IEEE80211_S_RUN) return; sc->ba_rx.stop_tidmask |= (1 << tid); that->iwx_add_task(sc, systq, &sc->ba_task); } int ItlIwx:: iwx_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; struct iwx_softc *sc = (struct iwx_softc *)ic->ic_softc; ItlIwx *that = container_of(sc, ItlIwx, com); XYLog("%s tid=%d ssn=%d\n", __FUNCTION__, tid, ba->ba_winstart); if (tid < 0 || tid >= IWX_MAX_TID_COUNT) { XYLog("%s tx agg refused. tid=%d\n", __FUNCTION__, tid); return ENOSPC; } if (sc->ba_tx.start_tidmask & (1 << tid)) { XYLog("%s tid %d is pending to agg\n", __FUNCTION__, tid); return EBUSY; } sc->ba_tx.start_tidmask |= (1 << tid); that->iwx_add_task(sc, systq, &sc->ba_task); return EBUSY; } void ItlIwx:: iwx_ampdu_tx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; struct iwx_softc *sc = (struct iwx_softc *)IC2IFP(ic)->if_softc; ItlIwx *that = container_of(sc, ItlIwx, com); XYLog("%s tid=%d\n", __FUNCTION__, tid); if (ba->ba_state != IEEE80211_BA_AGREED) { return; } sc->sc_tid_data[tid].qid = IWX_INVALID_QUEUE; ic->ic_stats.is_ht_tx_ba_agreements--; } static void iwx_flip_hw_address(uint32_t mac_addr0, uint32_t mac_addr1, uint8_t *dest) { const u8 *hw_addr; hw_addr = (const u8 *)&mac_addr0; dest[0] = hw_addr[3]; dest[1] = hw_addr[2]; dest[2] = hw_addr[1]; dest[3] = hw_addr[0]; hw_addr = (const u8 *)&mac_addr1; dest[4] = hw_addr[1]; dest[5] = hw_addr[0]; } int ItlIwx:: iwx_set_mac_addr_from_csr(struct iwx_softc *sc, struct iwx_nvm_data *data) { uint32_t mac_addr0, mac_addr1; if (!iwx_nic_lock(sc)) return EBUSY; mac_addr0 = htole32(IWX_READ(sc, IWX_CSR_MAC_ADDR0_STRAP)); mac_addr1 = htole32(IWX_READ(sc, IWX_CSR_MAC_ADDR1_STRAP)); iwx_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); /* * If the OEM fused a valid address, use it instead of the one in the * OTP */ if (iwx_is_valid_mac_addr(data->hw_addr)) goto done; mac_addr0 = htole32(IWX_READ(sc, IWX_CSR_MAC_ADDR0_OTP)); mac_addr1 = htole32(IWX_READ(sc, IWX_CSR_MAC_ADDR1_OTP)); iwx_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); done: iwx_nic_unlock(sc); return 0; } int ItlIwx:: iwx_is_valid_mac_addr(const uint8_t *addr) { return (memcmp(etherbroadcastaddr, addr, sizeof(etherbroadcastaddr)) != 0 && memcmp(etheranyaddr, addr, sizeof(etheranyaddr)) != 0 && !ETHER_IS_MULTICAST(addr)); } int ItlIwx:: iwx_nvm_get(struct iwx_softc *sc) { struct iwx_nvm_get_info cmd = {}; struct iwx_nvm_data *nvm = &sc->sc_nvm; struct iwx_host_cmd hcmd = { .flags = IWX_CMD_WANT_RESP | IWX_CMD_SEND_IN_RFKILL, .data = { &cmd, }, .len = { sizeof(cmd) }, .id = IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP, IWX_NVM_GET_INFO) }; int err; uint32_t mac_flags; /* * All the values in iwx_nvm_get_info_rsp v4 are the same as * in v3, except for the channel profile part of the * regulatory. So we can just access the new struct, with the * exception of the latter. */ struct iwx_nvm_get_info_rsp *rsp; struct iwx_nvm_get_info_rsp_v3 *rsp_v3; int v4 = isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_REGULATORY_NVM_INFO); size_t resp_len = v4 ? sizeof(*rsp) : sizeof(*rsp_v3); hcmd.resp_pkt_len = sizeof(struct iwx_rx_packet) + resp_len; err = iwx_send_cmd(sc, &hcmd); if (err) return err; if (iwx_rx_packet_payload_len(hcmd.resp_pkt) != resp_len) { err = EIO; goto out; } memset(nvm, 0, sizeof(*nvm)); iwx_set_mac_addr_from_csr(sc, nvm); if (!iwx_is_valid_mac_addr(nvm->hw_addr)) { XYLog("%s: no valid mac address was found\n", DEVNAME(sc)); err = EINVAL; goto out; } rsp = (struct iwx_nvm_get_info_rsp *)hcmd.resp_pkt->data; /* Initialize general data */ nvm->nvm_version = le16toh(rsp->general.nvm_version); nvm->n_hw_addrs = rsp->general.n_hw_addrs; /* Initialize MAC sku data */ mac_flags = le32toh(rsp->mac_sku.mac_sku_flags); nvm->sku_cap_11ac_enable = !!(mac_flags & IWX_NVM_MAC_SKU_FLAGS_802_11AC_ENABLED); nvm->sku_cap_11n_enable = !!(mac_flags & IWX_NVM_MAC_SKU_FLAGS_802_11N_ENABLED); nvm->sku_cap_11ax_enable = !!(mac_flags & IWX_NVM_MAC_SKU_FLAGS_802_11AX_ENABLED); nvm->sku_cap_band_24GHz_enable = !!(mac_flags & IWX_NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED); nvm->sku_cap_band_52GHz_enable = !!(mac_flags & IWX_NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); nvm->sku_cap_mimo_disable = !!(mac_flags & IWX_NVM_MAC_SKU_FLAGS_MIMO_DISABLED); /* Initialize PHY sku data */ nvm->valid_tx_ant = (uint8_t)le32toh(rsp->phy_sku.tx_chains); nvm->valid_rx_ant = (uint8_t)le32toh(rsp->phy_sku.rx_chains); if (le32toh(rsp->regulatory.lar_enabled) && isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_LAR_SUPPORT)) { nvm->lar_enabled = 1; } if (v4) { iwx_init_channel_map(sc, NULL, rsp->regulatory.channel_profile, IWX_NUM_CHANNELS); } else { rsp_v3 = (struct iwx_nvm_get_info_rsp_v3 *)rsp; iwx_init_channel_map(sc, rsp_v3->regulatory.channel_profile, NULL, IWX_NUM_CHANNELS_V1); } out: iwx_free_resp(sc, &hcmd); return err; } int ItlIwx:: iwx_load_firmware(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_fw_sects *fws; int err/*, w*/; sc->sc_uc.uc_intr = 0; fws = &sc->sc_fw.fw_sects[IWX_UCODE_TYPE_REGULAR]; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) err = iwx_ctxt_info_gen3_init(sc, fws); else err = iwx_ctxt_info_init(sc, fws); if (err) { XYLog("%s: could not init context info\n", DEVNAME(sc)); return err; } /* wait for the firmware to load */ // for (w = 0; !sc->sc_uc.uc_intr && w < 10; w++) { // err = tsleep_nsec(&sc->sc_uc, 0, "iwxuc", MSEC_TO_NSEC(100)); // } err = tsleep_nsec(&sc->sc_uc, 0, "iwxuc", SEC_TO_NSEC(1)); if (err || !sc->sc_uc.uc_ok) { if (iwx_nic_lock(sc)) { XYLog("SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", iwx_read_umac_prph(sc, IWX_UMAG_SB_CPU_1_STATUS), iwx_read_umac_prph(sc, IWX_UMAG_SB_CPU_2_STATUS)); XYLog("UMAC PC: 0x%x\n", iwx_read_umac_prph(sc, IWX_UREG_UMAC_CURRENT_PC)); XYLog("LMAC PC: 0x%x\n", iwx_read_umac_prph(sc, IWX_UREG_LMAC1_CURRENT_PC)); iwx_nic_unlock(sc); } iwx_ctxt_info_free_paging(sc); XYLog("%s: could not load firmware\n", DEVNAME(sc)); } iwx_ctxt_info_free_fw_img(sc); iwx_dma_contig_free(&sc->iml_dma); if (!sc->sc_uc.uc_ok) return EINVAL; XYLog("%s: load firmware ok\n", DEVNAME(sc)); return err; } int ItlIwx:: iwx_start_fw(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); int err; err = iwx_prepare_card_hw(sc); if (err) { XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); return err; } iwx_enable_rfkill_int(sc); IWX_WRITE(sc, IWX_CSR_INT, 0xFFFFFFFF); iwx_disable_interrupts(sc); /* make sure rfkill handshake bits are cleared */ IWX_WRITE(sc, IWX_CSR_UCODE_DRV_GP1_CLR, IWX_CSR_UCODE_SW_BIT_RFKILL); IWX_WRITE(sc, IWX_CSR_UCODE_DRV_GP1_CLR, IWX_CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); /* clear (again), then enable firwmare load interrupt */ IWX_WRITE(sc, IWX_CSR_INT, ~0); err = iwx_nic_init(sc); if (err) { XYLog("%s: unable to init nic\n", DEVNAME(sc)); return err; } return iwx_load_firmware(sc); } int ItlIwx:: iwx_send_tx_ant_cfg(struct iwx_softc *sc, uint8_t valid_tx_ant) { struct iwx_tx_ant_cfg_cmd tx_ant_cmd = { .valid = htole32(valid_tx_ant), }; XYLog("%s select valid tx ant: %u\n", __FUNCTION__, valid_tx_ant); return iwx_send_cmd_pdu(sc, IWX_TX_ANT_CONFIGURATION_CMD, 0, sizeof(tx_ant_cmd), &tx_ant_cmd); } int ItlIwx:: iwx_send_phy_cfg_cmd(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_phy_cfg_cmd_v3 phy_cfg_cmd; uint8_t cmdver; phy_cfg_cmd.phy_cfg = htole32(sc->sc_fw_phy_config); phy_cfg_cmd.calib_control.event_trigger = sc->sc_default_calib[IWX_UCODE_TYPE_REGULAR].event_trigger; phy_cfg_cmd.calib_control.flow_trigger = sc->sc_default_calib[IWX_UCODE_TYPE_REGULAR].flow_trigger; cmdver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_PHY_CONFIGURATION_CMD); return iwx_send_cmd_pdu(sc, IWX_PHY_CONFIGURATION_CMD, 0, (cmdver == 3) ? sizeof(struct iwx_phy_cfg_cmd_v3) : sizeof(struct iwx_phy_cfg_cmd_v1), &phy_cfg_cmd); } int ItlIwx:: iwx_send_dqa_cmd(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_dqa_enable_cmd dqa_cmd = { .cmd_queue = htole32(IWX_DQA_CMD_QUEUE), }; uint32_t cmd_id; cmd_id = iwx_cmd_id(IWX_DQA_ENABLE_CMD, IWX_DATA_PATH_GROUP, 0); return iwx_send_cmd_pdu(sc, cmd_id, 0, sizeof(dqa_cmd), &dqa_cmd); } int ItlIwx:: iwx_load_ucode_wait_alive(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); int err; err = iwx_read_firmware(sc); if (err) return err; err = iwx_start_fw(sc); if (err) return err; err = iwx_load_pnvm(sc); if (err) return err; iwx_post_alive(sc); return 0; } int ItlIwx:: iwx_run_init_mvm_ucode(struct iwx_softc *sc, int readnvm) { XYLog("%s\n", __FUNCTION__); const int wait_flags = IWX_INIT_COMPLETE; struct iwx_nvm_access_complete_cmd nvm_complete = {}; struct iwx_init_extended_cfg_cmd init_cfg = { .init_flags = htole32(IWX_INIT_NVM), }; int err; if ((sc->sc_flags & IWX_FLAG_RFKILL) && !readnvm) { XYLog("%s: radio is disabled by hardware switch\n", DEVNAME(sc)); return EPERM; } sc->sc_init_complete = 0; err = iwx_load_ucode_wait_alive(sc); if (err) { XYLog("%s: failed to load init firmware\n", DEVNAME(sc)); return err; } if (sc->sc_tx_with_siso_diversity) init_cfg.init_flags |= htole32(IWX_INIT_PHY); /* * Send init config command to mark that we are sending NVM * access commands */ err = iwx_send_cmd_pdu(sc, IWX_WIDE_ID(IWX_SYSTEM_GROUP, IWX_INIT_EXTENDED_CFG_CMD), IWX_CMD_SEND_IN_RFKILL, sizeof(init_cfg), &init_cfg); if (err) return err; err = iwx_send_cmd_pdu(sc, IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP, IWX_NVM_ACCESS_COMPLETE), IWX_CMD_SEND_IN_RFKILL, sizeof(nvm_complete), &nvm_complete); if (err) return err; /* Wait for the init complete notification from the firmware. */ // while ((sc->sc_init_complete & wait_flags) != wait_flags) { // err = tsleep_nsec(&sc->sc_init_complete, 0, "iwxinit", // SEC_TO_NSEC(2)); // if (err) // return err; // } err = tsleep_nsec(&sc->sc_init_complete, 0, "iwxinit", SEC_TO_NSEC(2)); if (err) { return err; } if (readnvm) { err = iwx_nvm_get(sc); if (err) { XYLog("%s: failed to read nvm\n", DEVNAME(sc)); return err; } if (IEEE80211_ADDR_EQ(etheranyaddr, sc->sc_ic.ic_myaddr)) IEEE80211_ADDR_COPY(sc->sc_ic.ic_myaddr, sc->sc_nvm.hw_addr); } return 0; } int ItlIwx:: iwx_config_ltr(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_ltr_config_cmd cmd = { .flags = htole32(IWX_LTR_CFG_FLAG_FEATURE_ENABLE), }; if (!sc->sc_ltr_enabled) return 0; return iwx_send_cmd_pdu(sc, IWX_LTR_CONFIG, 0, sizeof(cmd), &cmd); } void ItlIwx:: iwx_update_rx_desc(struct iwx_softc *sc, struct iwx_rx_ring *ring, int idx) { struct iwx_rx_data *data = &ring->data[idx]; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) { struct iwx_rx_transfer_desc *bd = (struct iwx_rx_transfer_desc *)ring->desc; bd[idx].addr = htole64(data->map->dm_segs[0].location); bd[idx].rbid = htole16(idx & 0x0fff); } else ((uint64_t *)ring->desc)[idx] = htole64(data->map->dm_segs[0].location | (idx & 0x0fff)); // bus_dmamap_sync(sc->sc_dmat, ring->free_desc_dma.map, // idx * sizeof(uint64_t), sizeof(uint64_t), // BUS_DMASYNC_PREWRITE); } int ItlIwx:: iwx_rx_addbuf(struct iwx_softc *sc, int size, int idx) { struct iwx_rx_ring *ring = &sc->rxq; struct iwx_rx_data *data = &ring->data[idx]; mbuf_t m; int err; int fatal = 0; m = getController()->allocatePacket(size); // m = m_gethdr(M_DONTWAIT, MT_DATA); // if (m == NULL) // return ENOBUFS; // // if (size <= MCLBYTES) { // MCLGET(m, M_DONTWAIT); // } else { // MCLGETI(m, M_DONTWAIT, NULL, IWX_RBUF_SIZE); // } // if ((m->m_flags & M_EXT) == 0) { // m_freem(m); // return ENOBUFS; // } // // if (data->m != NULL) { // bus_dmamap_unload(sc->sc_dmat, data->map); // fatal = 1; // } // // m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; // err = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m, // BUS_DMA_READ|BUS_DMA_NOWAIT); if (m == NULL) { XYLog("could not allocate RX mbuf\n"); return ENOMEM; } data->map->dm_nsegs = data->map->cursor->getPhysicalSegments(m, &data->map->dm_segs[0], 1); if (data->map->dm_nsegs == 0) { /* XXX */ if (fatal) panic("%s: could not load RX mbuf", DEVNAME(sc)); mbuf_freem(m); return ENOMEM; } data->m = m; // bus_dmamap_sync(sc->sc_dmat, data->map, 0, size, BUS_DMASYNC_PREREAD); /* Update RX descriptor. */ iwx_update_rx_desc(sc, ring, idx); return 0; } int ItlIwx:: iwx_rxmq_get_signal_strength(struct iwx_softc *sc, struct iwx_rx_mpdu_desc *desc) { int energy_a, energy_b; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) { energy_a = desc->v3.energy_a; energy_b = desc->v3.energy_b; } else { energy_a = desc->v1.energy_a; energy_b = desc->v1.energy_b; } energy_a = energy_a ? -energy_a : -256; energy_b = energy_b ? -energy_b : -256; return MAX(energy_a, energy_b); } void ItlIwx:: iwx_rx_rx_phy_cmd(struct iwx_softc *sc, struct iwx_rx_packet *pkt, struct iwx_rx_data *data) { struct iwx_rx_phy_info *phy_info = (struct iwx_rx_phy_info *)pkt->data; // bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*pkt), // sizeof(*phy_info), BUS_DMASYNC_POSTREAD); memcpy(&sc->sc_last_phy_info, phy_info, sizeof(sc->sc_last_phy_info)); } /* * Retrieve the average noise (in dBm) among receivers. */ int ItlIwx:: iwx_get_noise(const uint8_t *beacon_silence_rssi) { int i, total, nbant, noise; total = nbant = noise = 0; for (i = 0; i < 3; i++) { noise = letoh32(beacon_silence_rssi[i]) & 0xff; if (noise) { total += noise; nbant++; } } /* There should be at least one antenna but check anyway. */ return (nbant == 0) ? -127 : (total / nbant) - 107; } int ItlIwx:: iwx_ccmp_decap(struct iwx_softc *sc, mbuf_t m, struct ieee80211_node *ni, struct ieee80211_rxinfo *rxi) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_key *k; struct ieee80211_frame *wh; uint64_t pn, *prsc; uint8_t *ivp; uint8_t tid; int hdrlen, hasqos; wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); ivp = (uint8_t *)wh + hdrlen; /* find key for decryption */ k = ieee80211_get_rxkey(ic, m, ni); if (k == NULL || k->k_cipher != IEEE80211_CIPHER_CCMP) return 1; /* Check that ExtIV bit is be set. */ if (!(ivp[3] & IEEE80211_WEP_EXTIV)) return 1; hasqos = ieee80211_has_qos(wh); tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; prsc = &k->k_rsc[tid]; /* Extract the 48-bit PN from the CCMP header. */ pn = (uint64_t)ivp[0] | (uint64_t)ivp[1] << 8 | (uint64_t)ivp[4] << 16 | (uint64_t)ivp[5] << 24 | (uint64_t)ivp[6] << 32 | (uint64_t)ivp[7] << 40; if (rxi->rxi_flags & IEEE80211_RXI_HWDEC_SAME_PN) { if (pn < *prsc) { ic->ic_stats.is_ccmp_replays++; return 1; } } else if (pn <= *prsc) { ic->ic_stats.is_ccmp_replays++; return 1; } /* Last seen packet number is updated in ieee80211_inputm(). */ /* * Some firmware versions strip the MIC, and some don't. It is not * clear which of the capability flags could tell us what to expect. * For now, keep things simple and just leave the MIC in place if * it is present. * * The IV will be stripped by ieee80211_inputm(). */ return 0; } int ItlIwx:: iwx_rx_hwdecrypt(struct iwx_softc *sc, mbuf_t m, uint32_t rx_pkt_status, struct ieee80211_rxinfo *rxi) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); struct ieee80211_frame *wh; struct ieee80211_node *ni; int ret = 0; uint8_t type, subtype; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; if (type == IEEE80211_FC0_TYPE_CTL) return 0; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (ieee80211_has_qos(wh) && (subtype & IEEE80211_FC0_SUBTYPE_NODATA)) return 0; ni = ieee80211_find_rxnode(ic, wh); /* Handle hardware decryption. */ if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && (ni->ni_flags & IEEE80211_NODE_RXPROT) && ((!IEEE80211_IS_MULTICAST(wh->i_addr1) && ni->ni_rsncipher == IEEE80211_CIPHER_CCMP) || (IEEE80211_IS_MULTICAST(wh->i_addr1) && ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP))) { if ((rx_pkt_status & IWX_RX_MPDU_RES_STATUS_SEC_ENC_MSK) != IWX_RX_MPDU_RES_STATUS_SEC_CCM_ENC) { ic->ic_stats.is_ccmp_dec_errs++; ret = 1; goto out; } /* Check whether decryption was successful or not. */ if ((rx_pkt_status & (IWX_RX_MPDU_RES_STATUS_DEC_DONE | IWX_RX_MPDU_RES_STATUS_MIC_OK)) != (IWX_RX_MPDU_RES_STATUS_DEC_DONE | IWX_RX_MPDU_RES_STATUS_MIC_OK)) { ic->ic_stats.is_ccmp_dec_errs++; ret = 1; goto out; } rxi->rxi_flags |= IEEE80211_RXI_HWDEC; } out: if (ret) ifp->netStat->inputErrors++; ieee80211_release_node(ic, ni); return ret; } void ItlIwx:: iwx_rx_frame(struct iwx_softc *sc, mbuf_t m, int chanidx, uint32_t rx_pkt_status, int is_shortpre, int rate_n_flags, uint32_t device_timestamp, struct ieee80211_rxinfo *rxi, struct mbuf_list *ml) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_frame *wh; struct ieee80211_node *ni; struct _ifnet *ifp = IC2IFP(ic); if (chanidx < 0 || chanidx >= nitems(ic->ic_channels)) chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan); wh = mtod(m, struct ieee80211_frame *); ni = ieee80211_find_rxnode(ic, wh); if ((rxi->rxi_flags & IEEE80211_RXI_HWDEC) && iwx_ccmp_decap(sc, m, ni, rxi) != 0) { ifp->netStat->inputErrors++; mbuf_freem(m); ieee80211_release_node(ic, ni); return; } #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { struct iwx_rx_radiotap_header *tap = &sc->sc_rxtap; uint16_t chan_flags; tap->wr_flags = 0; if (is_shortpre) tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; tap->wr_chan_freq = htole16(ic->ic_channels[chanidx].ic_freq); chan_flags = ic->ic_channels[chanidx].ic_flags; if (ic->ic_curmode != IEEE80211_MODE_11N) chan_flags &= ~IEEE80211_CHAN_HT; tap->wr_chan_flags = htole16(chan_flags); tap->wr_dbm_antsignal = (int8_t)rxi->rxi_rssi; tap->wr_dbm_antnoise = (int8_t)sc->sc_noise; tap->wr_tsft = device_timestamp; if (rate_n_flags & IWX_RATE_MCS_HT_MSK) { uint8_t mcs = (rate_n_flags & (IWX_RATE_HT_MCS_RATE_CODE_MSK | IWX_RATE_HT_MCS_NSS_MSK)); tap->wr_rate = (0x80 | mcs); } else { uint8_t rate = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK); switch (rate) { /* CCK rates. */ case 10: tap->wr_rate = 2; break; case 20: tap->wr_rate = 4; break; case 55: tap->wr_rate = 11; break; case 110: tap->wr_rate = 22; break; /* OFDM rates. */ case 0xd: tap->wr_rate = 12; break; case 0xf: tap->wr_rate = 18; break; case 0x5: tap->wr_rate = 24; break; case 0x7: tap->wr_rate = 36; break; case 0x9: tap->wr_rate = 48; break; case 0xb: tap->wr_rate = 72; break; case 0x1: tap->wr_rate = 96; break; case 0x3: tap->wr_rate = 108; break; /* Unknown rate: should not happen. */ default: tap->wr_rate = 0; } } bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m, BPF_DIRECTION_IN); } #endif ieee80211_inputm(IC2IFP(ic), m, ni, rxi, ml); ieee80211_release_node(ic, ni); } void ItlIwx:: iwx_flip_address(uint8_t *addr) { int i; uint8_t mac_addr[ETHER_ADDR_LEN]; for (i = 0; i < ETHER_ADDR_LEN; i++) mac_addr[i] = addr[ETHER_ADDR_LEN - i - 1]; IEEE80211_ADDR_COPY(addr, mac_addr); } /* * Drop duplicate 802.11 retransmissions * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") * and handle pseudo-duplicate frames which result from deaggregation * of A-MSDU frames in hardware. */ int ItlIwx:: iwx_detect_duplicate(struct iwx_softc *sc, mbuf_t m, struct iwx_rx_mpdu_desc *desc, struct ieee80211_rxinfo *rxi) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_node *in = (struct iwx_node *)ic->ic_bss; struct iwx_rxq_dup_data *dup_data = &in->dup_data; uint8_t tid = IWX_MAX_TID_COUNT, subframe_idx; struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); uint8_t type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; int hasqos = ieee80211_has_qos(wh); uint16_t seq; if (type == IEEE80211_FC0_TYPE_CTL || (hasqos && (subtype & IEEE80211_FC0_SUBTYPE_NODATA)) || IEEE80211_IS_MULTICAST(wh->i_addr1)) return 0; if (hasqos) { tid = (ieee80211_get_qos(wh) & IEEE80211_QOS_TID); if (tid > IWX_MAX_TID_COUNT) tid = IWX_MAX_TID_COUNT; } /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */ subframe_idx = desc->amsdu_info & IWX_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; seq = letoh16(*(u_int16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT; if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && dup_data->last_seq[tid] == seq && dup_data->last_sub_frame[tid] >= subframe_idx) return 1; /* * Allow the same frame sequence number for all A-MSDU subframes * following the first subframe. * Otherwise these subframes would be discarded as replays. */ if (dup_data->last_seq[tid] == seq && subframe_idx > dup_data->last_sub_frame[tid] && (desc->mac_flags2 & IWX_RX_MPDU_MFLG2_AMSDU)) { rxi->rxi_flags |= IEEE80211_RXI_SAME_SEQ; } dup_data->last_seq[tid] = seq; dup_data->last_sub_frame[tid] = subframe_idx; return 0; } /* * Returns true if sn2 - buffer_size < sn1 < sn2. * To be used only in order to compare reorder buffer head with NSSN. * We fully trust NSSN unless it is behind us due to reorder timeout. * Reorder timeout can only bring us up to buffer_size SNs ahead of NSSN. */ int ItlIwx:: iwx_is_sn_less(uint16_t sn1, uint16_t sn2, uint16_t buffer_size) { return SEQ_LT(sn1, sn2) && !SEQ_LT(sn1, sn2 - buffer_size); } void ItlIwx:: iwx_release_frames(struct iwx_softc *sc, struct ieee80211_node *ni, struct iwx_rxba_data *rxba, struct iwx_reorder_buffer *reorder_buf, uint16_t nssn, struct mbuf_list *ml) { struct iwx_reorder_buf_entry *entries = &rxba->entries[0]; uint16_t ssn = reorder_buf->head_sn; /* ignore nssn smaller than head sn - this can happen due to timeout */ if (iwx_is_sn_less(nssn, ssn, reorder_buf->buf_size)) goto set_timer; while (iwx_is_sn_less(ssn, nssn, reorder_buf->buf_size)) { int index = ssn % reorder_buf->buf_size; mbuf_t m; int chanidx, is_shortpre; uint32_t rx_pkt_status, rate_n_flags, device_timestamp; struct ieee80211_rxinfo *rxi; /* This data is the same for all A-MSDU subframes. */ chanidx = entries[index].chanidx; rx_pkt_status = entries[index].rx_pkt_status; is_shortpre = entries[index].is_shortpre; rate_n_flags = entries[index].rate_n_flags; device_timestamp = entries[index].device_timestamp; rxi = &entries[index].rxi; /* * Empty the list. Will have more than one frame for A-MSDU. * Empty list is valid as well since nssn indicates frames were * received. */ while ((m = ml_dequeue(&entries[index].frames)) != NULL) { iwx_rx_frame(sc, m, chanidx, rx_pkt_status, is_shortpre, rate_n_flags, device_timestamp, rxi, ml); reorder_buf->num_stored--; /* * Allow the same frame sequence number and CCMP PN for * all A-MSDU subframes following the first subframe. * Otherwise they would be discarded as replays. */ rxi->rxi_flags |= IEEE80211_RXI_SAME_SEQ; rxi->rxi_flags |= IEEE80211_RXI_HWDEC_SAME_PN; } ssn = (ssn + 1) & 0xfff; } reorder_buf->head_sn = nssn; set_timer: if (reorder_buf->num_stored && !reorder_buf->removed) { timeout_add_usec(&reorder_buf->reorder_timer, RX_REORDER_BUF_TIMEOUT_MQ_USEC); } else timeout_del(&reorder_buf->reorder_timer); } int ItlIwx:: iwx_oldsn_workaround(struct iwx_softc *sc, struct ieee80211_node *ni, int tid, struct iwx_reorder_buffer *buffer, uint32_t reorder_data, uint32_t gp2) { struct ieee80211com *ic = &sc->sc_ic; if (gp2 != buffer->consec_oldsn_ampdu_gp2) { /* we have a new (A-)MPDU ... */ /* * reset counter to 0 if we didn't have any oldsn in * the last A-MPDU (as detected by GP2 being identical) */ if (!buffer->consec_oldsn_prev_drop) buffer->consec_oldsn_drops = 0; /* either way, update our tracking state */ buffer->consec_oldsn_ampdu_gp2 = gp2; } else if (buffer->consec_oldsn_prev_drop) { /* * tracking state didn't change, and we had an old SN * indication before - do nothing in this case, we * already noted this one down and are waiting for the * next A-MPDU (by GP2) */ return 0; } /* return unless this MPDU has old SN */ if (!(reorder_data & IWX_RX_MPDU_REORDER_BA_OLD_SN)) return 0; /* update state */ buffer->consec_oldsn_prev_drop = 1; buffer->consec_oldsn_drops++; /* if limit is reached, send del BA and reset state */ if (buffer->consec_oldsn_drops == IWX_AMPDU_CONSEC_DROPS_DELBA) { XYLog("reached %d old SN frames, stopping BA session on TID %d\n", IWX_AMPDU_CONSEC_DROPS_DELBA, tid); ieee80211_delba_request(ic, ni, IEEE80211_REASON_UNSPECIFIED, 0, tid); buffer->consec_oldsn_prev_drop = 0; buffer->consec_oldsn_drops = 0; return 1; } return 0; } /* * Handle re-ordering of frames which were de-aggregated in hardware. * Returns 1 if the MPDU was consumed (buffered or dropped). * Returns 0 if the MPDU should be passed to upper layer. */ int ItlIwx:: iwx_rx_reorder(struct iwx_softc *sc, mbuf_t m, int chanidx, struct iwx_rx_mpdu_desc *desc, int is_shortpre, int rate_n_flags, uint32_t device_timestamp, struct ieee80211_rxinfo *rxi, struct mbuf_list *ml) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_frame *wh; struct ieee80211_node *ni; struct iwx_rxba_data *rxba; struct iwx_reorder_buffer *buffer; uint32_t reorder_data = le32toh(desc->reorder_data); int is_amsdu = (desc->mac_flags2 & IWX_RX_MPDU_MFLG2_AMSDU); int last_subframe = (desc->amsdu_info & IWX_RX_MPDU_AMSDU_LAST_SUBFRAME); uint8_t tid; uint8_t subframe_idx = (desc->amsdu_info & IWX_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK); struct iwx_reorder_buf_entry *entries; int index; uint16_t nssn, sn; uint8_t baid, type, subtype; int hasqos; wh = mtod(m, struct ieee80211_frame *); hasqos = ieee80211_has_qos(wh); tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; /* * We are only interested in Block Ack requests and unicast QoS data. */ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) return 0; if (hasqos) { if (subtype & IEEE80211_FC0_SUBTYPE_NODATA) return 0; } else { if (type != IEEE80211_FC0_TYPE_CTL || subtype != IEEE80211_FC0_SUBTYPE_BAR) return 0; } baid = (reorder_data & IWX_RX_MPDU_REORDER_BAID_MASK) >> IWX_RX_MPDU_REORDER_BAID_SHIFT; if (baid == IWX_RX_REORDER_DATA_INVALID_BAID || baid >= nitems(sc->sc_rxba_data)) return 0; rxba = &sc->sc_rxba_data[baid]; if (rxba->reorder_buf.buf_size == 0 || tid != rxba->tid || rxba->sta_id != IWX_STATION_ID) return 0; if (rxba->timeout != 0) getmicrouptime(&rxba->last_rx); /* Bypass A-MPDU re-ordering in net80211. */ rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE; nssn = reorder_data & IWX_RX_MPDU_REORDER_NSSN_MASK; sn = (reorder_data & IWX_RX_MPDU_REORDER_SN_MASK) >> IWX_RX_MPDU_REORDER_SN_SHIFT; buffer = &rxba->reorder_buf; entries = &rxba->entries[0]; if (!buffer->valid) { if (reorder_data & IWX_RX_MPDU_REORDER_BA_OLD_SN) return 0; buffer->valid = 1; } ni = ieee80211_find_rxnode(ic, wh); if (type == IEEE80211_FC0_TYPE_CTL && subtype == IEEE80211_FC0_SUBTYPE_BAR) { iwx_release_frames(sc, ni, rxba, buffer, nssn, ml); goto drop; } /* * If there was a significant jump in the nssn - adjust. * If the SN is smaller than the NSSN it might need to first go into * the reorder buffer, in which case we just release up to it and the * rest of the function will take care of storing it and releasing up to * the nssn. */ if (!iwx_is_sn_less(nssn, buffer->head_sn + buffer->buf_size, buffer->buf_size) || !SEQ_LT(sn, buffer->head_sn + buffer->buf_size)) { uint16_t min_sn = SEQ_LT(sn, nssn) ? sn : nssn; ic->ic_stats.is_ht_rx_frame_above_ba_winend++; iwx_release_frames(sc, ni, rxba, buffer, min_sn, ml); } if (iwx_oldsn_workaround(sc, ni, tid, buffer, reorder_data, device_timestamp)) { /* BA session will be torn down. */ ic->ic_stats.is_ht_rx_ba_window_jump++; goto drop; } /* drop any outdated packets */ if (SEQ_LT(sn, buffer->head_sn)) { ic->ic_stats.is_ht_rx_frame_below_ba_winstart++; goto drop; } /* release immediately if allowed by nssn and no stored frames */ if (!buffer->num_stored && SEQ_LT(sn, nssn)) { if (iwx_is_sn_less(buffer->head_sn, nssn, buffer->buf_size) && (!is_amsdu || last_subframe)) buffer->head_sn = nssn; ieee80211_release_node(ic, ni); return 0; } /* * release immediately if there are no stored frames, and the sn is * equal to the head. * This can happen due to reorder timer, where NSSN is behind head_sn. * When we released everything, and we got the next frame in the * sequence, according to the NSSN we can't release immediately, * while technically there is no hole and we can move forward. */ if (!buffer->num_stored && sn == buffer->head_sn) { if (!is_amsdu || last_subframe) buffer->head_sn = (buffer->head_sn + 1) & 0xfff; ieee80211_release_node(ic, ni); return 0; } index = sn % buffer->buf_size; /* * Check if we already stored this frame * As AMSDU is either received or not as whole, logic is simple: * If we have frames in that position in the buffer and the last frame * originated from AMSDU had a different SN then it is a retransmission. * If it is the same SN then if the subframe index is incrementing it * is the same AMSDU - otherwise it is a retransmission. */ if (!ml_empty(&entries[index].frames)) { if (!is_amsdu) { ic->ic_stats.is_ht_rx_ba_no_buf++; goto drop; } else if (sn != buffer->last_amsdu || buffer->last_sub_index >= subframe_idx) { ic->ic_stats.is_ht_rx_ba_no_buf++; goto drop; } } else { /* This data is the same for all A-MSDU subframes. */ entries[index].chanidx = chanidx; entries[index].is_shortpre = is_shortpre; entries[index].rate_n_flags = rate_n_flags; entries[index].device_timestamp = device_timestamp; memcpy(&entries[index].rxi, rxi, sizeof(entries[index].rxi)); } /* put in reorder buffer */ ml_enqueue(&entries[index].frames, m); buffer->num_stored++; getmicrouptime(&entries[index].reorder_time); if (is_amsdu) { buffer->last_amsdu = sn; buffer->last_sub_index = subframe_idx; } /* * We cannot trust NSSN for AMSDU sub-frames that are not the last. * The reason is that NSSN advances on the first sub-frame, and may * cause the reorder buffer to advance before all the sub-frames arrive. * Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with * SN 1. NSSN for first sub frame will be 3 with the result of driver * releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is * already ahead and it will be dropped. * If the last sub-frame is not on this queue - we will get frame * release notification with up to date NSSN. */ if (!is_amsdu || last_subframe) iwx_release_frames(sc, ni, rxba, buffer, nssn, ml); ieee80211_release_node(ic, ni); return 1; drop: mbuf_freem(m); ieee80211_release_node(ic, ni); return 1; } void ItlIwx:: iwx_rx_mpdu_mq(struct iwx_softc *sc, mbuf_t m, void *pktdata, size_t maxlen, struct mbuf_list *ml) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_rxinfo rxi; struct iwx_rx_mpdu_desc *desc; uint32_t len, hdrlen, rate_n_flags, device_timestamp; int rssi; uint8_t chanidx; uint16_t phy_info; size_t desc_size; desc = (struct iwx_rx_mpdu_desc *)pktdata; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) desc_size = sizeof(struct iwx_rx_mpdu_desc); else desc_size = IWX_RX_DESC_SIZE_V1; if (!(desc->status & htole16(IWX_RX_MPDU_RES_STATUS_CRC_OK)) || !(desc->status & htole16(IWX_RX_MPDU_RES_STATUS_OVERRUN_OK))) { mbuf_freem(m); return; /* drop */ } len = le16toh(desc->mpdu_len); if (ic->ic_opmode == IEEE80211_M_MONITOR) { /* Allow control frames in monitor mode. */ if (len < sizeof(struct ieee80211_frame_cts)) { ic->ic_stats.is_rx_tooshort++; IC2IFP(ic)->netStat->inputErrors++; mbuf_freem(m); return; } } else if (len < sizeof(struct ieee80211_frame)) { ic->ic_stats.is_rx_tooshort++; IC2IFP(ic)->netStat->inputErrors++; mbuf_freem(m); return; } if (len > maxlen - desc_size) { IC2IFP(ic)->netStat->inputErrors++; mbuf_freem(m); return; } // m->m_data = pktdata + sizeof(*desc); // m->m_pkthdr.len = m->m_len = len; mbuf_setdata(m, (uint8_t*)pktdata + desc_size, len); mbuf_pkthdr_setlen(m, len); mbuf_setlen(m, len); /* Account for padding following the frame header. */ if (desc->mac_flags2 & IWX_RX_MPDU_MFLG2_PAD) { struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; if (type == IEEE80211_FC0_TYPE_CTL) { switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { case IEEE80211_FC0_SUBTYPE_CTS: hdrlen = sizeof(struct ieee80211_frame_cts); break; case IEEE80211_FC0_SUBTYPE_ACK: hdrlen = sizeof(struct ieee80211_frame_ack); break; default: hdrlen = sizeof(struct ieee80211_frame_min); break; } } else hdrlen = ieee80211_get_hdrlen(wh); if ((le16toh(desc->status) & IWX_RX_MPDU_RES_STATUS_SEC_ENC_MSK) == IWX_RX_MPDU_RES_STATUS_SEC_CCM_ENC) { /* Padding is inserted after the IV. */ hdrlen += IEEE80211_CCMP_HDRLEN; } // memmove(m->m_data + 2, m->m_data, hdrlen); memmove((uint8_t*)mbuf_data(m) + 2, mbuf_data(m), hdrlen); mbuf_adj(m, 2); } memset(&rxi, 0, sizeof(rxi)); /* * Hardware de-aggregates A-MSDUs and copies the same MAC header * in place for each subframe. But it leaves the 'A-MSDU present' * bit set in the frame header. We need to clear this bit ourselves. * (XXX This workaround is not required on AX200/AX201 devices that * have been tested by me, but it's unclear when this problem was * fixed in the hardware. It definitely affects the 9k generation. * Leaving this in place for now since some 9k/AX200 hybrids seem * to exist that we may eventually add support for.) * * And we must allow the same CCMP PN for subframes following the * first subframe. Otherwise they would be discarded as replays. */ if (desc->mac_flags2 & IWX_RX_MPDU_MFLG2_AMSDU) { struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); uint8_t subframe_idx = (desc->amsdu_info & IWX_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK); if (subframe_idx > 0) rxi.rxi_flags |= IEEE80211_RXI_HWDEC_SAME_PN; if (ieee80211_has_qos(wh) && ieee80211_has_addr4(wh) && mbuf_len(m) >= sizeof(struct ieee80211_qosframe_addr4)) { struct ieee80211_qosframe_addr4 *qwh4 = mtod(m, struct ieee80211_qosframe_addr4 *); qwh4->i_qos[0] &= htole16(~IEEE80211_QOS_AMSDU); } else if (ieee80211_has_qos(wh) && mbuf_len(m) >= sizeof(struct ieee80211_qosframe)) { struct ieee80211_qosframe *qwh = mtod(m, struct ieee80211_qosframe *); qwh->i_qos[0] &= htole16(~IEEE80211_QOS_AMSDU); } } /* * Verify decryption before duplicate detection. The latter uses * the TID supplied in QoS frame headers and this TID is implicitly * verified as part of the CCMP nonce. */ if (iwx_rx_hwdecrypt(sc, m, le16toh(desc->status), &rxi)) { mbuf_freem(m); return; } if (iwx_detect_duplicate(sc, m, desc, &rxi)) { mbuf_freem(m); return; } rssi = iwx_rxmq_get_signal_strength(sc, desc); rssi = (0 - IWX_MIN_DBM) + rssi; /* normalize */ rssi = MIN(rssi, ic->ic_max_rssi); /* clip to max. 100% */ rxi.rxi_rssi = rssi; phy_info = le16toh(desc->phy_info); if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) { rate_n_flags = le32toh(desc->v3.rate_n_flags); chanidx = desc->v3.channel; device_timestamp = desc->v3.gp2_on_air_rise; rxi.rxi_tstamp = (uint32_t)le64toh(desc->v3.tsf_on_air_rise); } else { rate_n_flags = le32toh(desc->v1.rate_n_flags); chanidx = desc->v1.channel; device_timestamp = desc->v1.gp2_on_air_rise; rxi.rxi_tstamp = (uint32_t)le64toh(desc->v1.tsf_on_air_rise); } rxi.rxi_chan = chanidx; if (iwx_rx_reorder(sc, m, chanidx, desc, (phy_info & IWX_RX_MPDU_PHY_SHORT_PREAMBLE), rate_n_flags, device_timestamp, &rxi, ml)) return; iwx_rx_frame(sc, m, chanidx, le16toh(desc->status), (phy_info & IWX_RX_MPDU_PHY_SHORT_PREAMBLE), rate_n_flags, device_timestamp, &rxi, ml); } void ItlIwx:: iwx_rx_tx_cmd_single(struct iwx_softc *sc, struct iwx_rx_packet *pkt, struct iwx_tx_data *txd) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); struct iwx_tx_resp *tx_resp = (struct iwx_tx_resp *)pkt->data; int status = le16toh(tx_resp->status.status) & IWX_TX_STATUS_MSK; int txfail; KASSERT(tx_resp->frame_count == 1, "tx_resp->frame_count == 1"); txfail = (status != IWX_TX_STATUS_SUCCESS); if (txfail) { XYLog("%s %d OUTPUT_ERROR type=%d status=%d\n", __FUNCTION__, __LINE__, txd->type, status); ifp->netStat->outputErrors++; if (txd->type == IEEE80211_FC0_TYPE_MGT) iwx_toggle_tx_ant(sc, &sc->sc_mgmt_last_antenna_idx); } } void iwx_clear_tx_desc(struct iwx_softc *sc, struct iwx_tx_ring *ring, int idx) { struct iwx_tfh_tfd *desc = &ring->desc[idx]; uint8_t num_tbs = le16toh(desc->num_tbs) & 0x1f; int i; /* First TB is never cleared - it is bidirectional DMA data. */ for (i = 1; i < num_tbs; i++) { struct iwx_tfh_tb *tb = &desc->tbs[i]; memset(tb, 0, sizeof(*tb)); } desc->num_tbs = 0; // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, // (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr, // sizeof(*desc), BUS_DMASYNC_PREWRITE); } void ItlIwx:: iwx_txd_done(struct iwx_softc *sc, struct iwx_tx_data *txd) { struct ieee80211com *ic = &sc->sc_ic; // bus_dmamap_sync(sc->sc_dmat, txd->map, 0, txd->map->dm_mapsize, // BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, txd->map); mbuf_freem(txd->m); txd->m = NULL; KASSERT(txd->in, "txd->in"); ieee80211_release_node(ic, &txd->in->in_ni); txd->in = NULL; } void ItlIwx:: iwx_clear_oactive(struct iwx_softc *sc, struct iwx_tx_ring *ring) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; if (ring->queued < ring->low_mark) { sc->qfullmsk &= ~(1 << ring->qid); if (sc->qfullmsk == 0 && ifq_is_oactive(&ifp->if_snd)) { ifq_clr_oactive(&ifp->if_snd); (*ifp->if_start)(ifp); } #ifdef __PRIVATE_SPI__ ifp->iface->signalOutputThread(); #endif } } void ItlIwx:: iwx_rx_tx_ba_notif(struct iwx_softc *sc, struct iwx_rx_packet *pkt, struct iwx_rx_data *data) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_compressed_ba_notif *ba_res = (struct iwx_compressed_ba_notif *)pkt->data; uint8_t tid; uint8_t qid; int i; struct iwx_tx_ring *ring; sc->sc_tx_timer = 0; if (le32toh(ba_res->flags) != IWX_BA_RESP_TX_BAR && le32toh(ba_res->flags) != IWX_BA_RESP_TX_AGG){ DPRINTFN(3, ("BA_NOTIFICATION flags %x, sent:%d, acked:%d, tfd_cnt:%d, query_frame_cnt:%d, retry_cnt:%d\n", le32toh(ba_res->flags), le16toh(ba_res->txed), le16toh(ba_res->done), le16toh(ba_res->tfd_cnt), ba_res->query_frame_cnt, ba_res->retry_cnt)); } if (ic->ic_state != IEEE80211_S_RUN) return; if (!le16toh(ba_res->tfd_cnt)) return; /* Free per TID */ for (i = 0; i < le16toh(ba_res->tfd_cnt); i++) { struct iwx_compressed_ba_tfd *ba_tfd = &ba_res->tfd[i]; tid = ba_tfd->tid; qid = le16toh(ba_tfd->q_num); ring = &sc->txq[qid]; sc->sc_tx_timer = 0; iwx_ampdu_txq_advance(sc, ring, IWX_AGG_SSN_TO_TXQ_IDX(le16toh(ba_tfd->tfd_index), ring->ring_count)); iwx_clear_oactive(sc, ring); } } void ItlIwx:: iwx_ampdu_txq_advance(struct iwx_softc *sc, struct iwx_tx_ring *ring, int idx) { struct iwx_tx_data *txd; while (ring->tail != idx) { txd = &ring->data[ring->tail]; if (txd->m != NULL) { iwx_txd_done(sc, txd); iwx_clear_tx_desc(sc, ring, ring->tail); ring->queued--; } ring->tail = (ring->tail + 1) % ring->ring_count; } } #define IWX_AGG_TX_STATE_(x) case IWX_AGG_TX_STATE_ ## x: return #x static const char *iwx_get_agg_tx_status(uint16_t status) { switch (status & IWX_AGG_TX_STATE_STATUS_MSK) { IWX_AGG_TX_STATE_(TRANSMITTED); IWX_AGG_TX_STATE_(UNDERRUN); IWX_AGG_TX_STATE_(BT_PRIO); IWX_AGG_TX_STATE_(FEW_BYTES); IWX_AGG_TX_STATE_(ABORT); IWX_AGG_TX_STATE_(TX_ON_AIR_DROP); IWX_AGG_TX_STATE_(LAST_SENT_TRY_CNT); IWX_AGG_TX_STATE_(LAST_SENT_BT_KILL); IWX_AGG_TX_STATE_(SCD_QUERY); IWX_AGG_TX_STATE_(TEST_BAD_CRC32); IWX_AGG_TX_STATE_(RESPONSE); IWX_AGG_TX_STATE_(DUMP_TX); IWX_AGG_TX_STATE_(DELAY_TX); } return "UNKNOWN"; } void ItlIwx:: iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_packet *pkt, struct iwx_rx_data *data) { uint32_t ssn; int idx; int tid; struct iwx_tx_resp *tx_resp = (struct iwx_tx_resp *)pkt->data; int qid = tx_resp->tx_queue; struct iwx_tx_ring *ring = &sc->txq[qid]; struct iwx_tx_data *txd; bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWX_RBUF_SIZE, BUS_DMASYNC_POSTREAD); sc->sc_tx_timer = 0; if (tx_resp->frame_count > 1) { for (int i = 0; i < tx_resp->frame_count; i++) { uint16_t fstatus = le16_to_cpu((&tx_resp->status)[i].status); XYLog("status %s (0x%04x), try-count (%d) qid (%d) seq (0x%x)\n", iwx_get_agg_tx_status(fstatus), fstatus & IWX_AGG_TX_STATE_STATUS_MSK, (fstatus & IWX_AGG_TX_STATE_TRY_CNT_MSK) >> IWX_AGG_TX_STATE_TRY_CNT_POS, qid, le16_to_cpu((&tx_resp->status)[i].sequence)); } } else { tid = tx_resp->ra_tid & 0x0f; memcpy(&ssn, &tx_resp->status + tx_resp->frame_count, sizeof(ssn)); ssn = le32toh(ssn) & 0xfff; idx = IWX_AGG_SSN_TO_TXQ_IDX(ssn, ring->ring_count); txd = &ring->data[idx]; iwx_rx_tx_cmd_single(sc, pkt, txd); DPRINTFN(3, ("%s tid=%d ssn=%d idx=%d\n", __FUNCTION__, tid, ssn, idx)); iwx_ampdu_txq_advance(sc, ring, idx); iwx_clear_oactive(sc, ring); } } void ItlIwx:: iwx_rx_bmiss(struct iwx_softc *sc, struct iwx_rx_packet *pkt, struct iwx_rx_data *data) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_missed_beacons_notif *mbn = (struct iwx_missed_beacons_notif *)pkt->data; uint32_t missed; if ((ic->ic_opmode != IEEE80211_M_STA) || (ic->ic_state != IEEE80211_S_RUN)) return; // bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*pkt), // sizeof(*mbn), BUS_DMASYNC_POSTREAD); missed = le32toh(mbn->consec_missed_beacons_since_last_rx); if (missed > ic->ic_bmissthres && ic->ic_mgt_timer == 0) { if (ic->ic_if.if_flags & IFF_DEBUG) { XYLog("%s: receiving no beacons from %s; checking if " "this AP is still responding to probe requests\n", DEVNAME(sc), ether_sprintf(ic->ic_bss->ni_macaddr)); /* Dump driver status (TX and RX rings) while we're here. */ XYLog("%s driver queue status:\n", __FUNCTION__); for (int i = 0; i < IWX_MAX_QUEUES; i++) { struct iwx_tx_ring *ring = &sc->txq[i]; XYLog(" tx ring %2d: qid=%-2d cur=%-3d " "queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); } XYLog(" rx ring: cur=%d\n", sc->rxq.cur); XYLog(" 802.11 state %s\n", ieee80211_state_name[sc->sc_ic.ic_state]); } /* * Rather than go directly to scan state, try to send a * directed probe request first. If that fails then the * state machine will drop us into scanning after timing * out waiting for a probe response. */ IEEE80211_SEND_MGMT(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); } } int ItlIwx:: iwx_binding_cmd(struct iwx_softc *sc, struct iwx_node *in, uint32_t action) { struct iwx_binding_cmd cmd; struct iwx_phy_ctxt *phyctxt = in->in_phyctxt; uint32_t mac_id = IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color); int i, err, active = (sc->sc_flags & IWX_FLAG_BINDING_ACTIVE); uint32_t status; if (action == IWX_FW_CTXT_ACTION_ADD && active) { XYLog("binding already added\n"); return 0; } if (action == IWX_FW_CTXT_ACTION_REMOVE && !active) { XYLog("binding already removed\n"); return 0; } if (phyctxt == NULL) /* XXX race with iwx_stop() */ return EINVAL; memset(&cmd, 0, sizeof(cmd)); cmd.id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color)); cmd.action = htole32(action); cmd.phy = htole32(IWX_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color)); cmd.macs[0] = htole32(mac_id); for (i = 1; i < IWX_MAX_MACS_IN_BINDING; i++) cmd.macs[i] = htole32(IWX_FW_CTXT_INVALID); if (IEEE80211_IS_CHAN_2GHZ(phyctxt->channel) || !isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_CDB_SUPPORT)) cmd.lmac_id = htole32(IWX_LMAC_24G_INDEX); else cmd.lmac_id = htole32(IWX_LMAC_5G_INDEX); status = 0; err = iwx_send_cmd_pdu_status(sc, IWX_BINDING_CONTEXT_CMD, sizeof(cmd), &cmd, &status); if (err == 0 && status != 0) err = EIO; return err; } static uint8_t iwx_get_channel_width(struct ieee80211com *ic, struct ieee80211_channel *c) { uint8_t ret = IWX_PHY_VHT_CHANNEL_MODE20; if (ic->ic_bss == NULL || ic->ic_state < IEEE80211_S_ASSOC) { return ret; } switch (ic->ic_bss->ni_chw) { case IEEE80211_CHAN_WIDTH_20_NOHT: case IEEE80211_CHAN_WIDTH_20: return IWX_PHY_VHT_CHANNEL_MODE20; case IEEE80211_CHAN_WIDTH_40: return IWX_PHY_VHT_CHANNEL_MODE40; case IEEE80211_CHAN_WIDTH_80: return IWX_PHY_VHT_CHANNEL_MODE80; case IEEE80211_CHAN_WIDTH_160: return IWX_PHY_VHT_CHANNEL_MODE160; default: XYLog("Invalid channel width=%u\n", ic->ic_bss->ni_chw); return ret; } } static uint8_t iwx_get_ctrl_pos(struct ieee80211com *ic, struct ieee80211_channel *c) { if (ic->ic_bss == NULL || ic->ic_state < IEEE80211_S_ASSOC || iwx_get_channel_width(ic, c) == IWX_PHY_VHT_CHANNEL_MODE20) return IWX_PHY_VHT_CTRL_POS_1_BELOW; signed int offset = ic->ic_bss->ni_chan->ic_freq - ic->ic_bss->ni_chan->ic_center_freq1; switch (offset) { case -70: return IWX_PHY_VHT_CTRL_POS_4_BELOW; case -50: return IWX_PHY_VHT_CTRL_POS_3_BELOW; case -30: return IWX_PHY_VHT_CTRL_POS_2_BELOW; case -10: return IWX_PHY_VHT_CTRL_POS_1_BELOW; case 10: return IWX_PHY_VHT_CTRL_POS_1_ABOVE; case 30: return IWX_PHY_VHT_CTRL_POS_2_ABOVE; case 50: return IWX_PHY_VHT_CTRL_POS_3_ABOVE; case 70: return IWX_PHY_VHT_CTRL_POS_4_ABOVE; default: XYLog("Invalid channel definition freq=%d %d\n", ic->ic_bss->ni_chan->ic_freq, offset); /* fall through */ case 0: /* * The FW is expected to check the control channel position only * when in HT/VHT and the channel width is not 20MHz. Return * this value as the default one. */ return IWX_PHY_VHT_CTRL_POS_1_BELOW; } } int ItlIwx:: iwx_phy_ctxt_cmd_v3(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt, uint8_t chains_static, uint8_t chains_dynamic, uint32_t action, uint32_t apply_time) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_phy_context_cmd cmd; uint8_t active_cnt, idle_cnt; struct ieee80211_channel *chan = ctxt->channel; memset(&cmd, 0, sizeof(cmd)); cmd.id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(ctxt->id, ctxt->color)); cmd.action = htole32(action); cmd.lmac_id = htole32(iwx_lmac_id(sc, chan)); cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ? IWX_PHY_BAND_24 : IWX_PHY_BAND_5; cmd.ci.channel = htole32(ieee80211_chan2ieee(ic, chan)); cmd.ci.width = iwx_get_channel_width(ic, chan); cmd.ci.ctrl_pos = iwx_get_ctrl_pos(ic, chan); XYLog("%s: 2ghz=%d, channel=%d, channel_width=%d pos=%d chains static=0x%x, dynamic=0x%x, " "rx_ant=0x%x, tx_ant=0x%x\n", __FUNCTION__, cmd.ci.band, cmd.ci.channel, cmd.ci.width, cmd.ci.ctrl_pos, chains_static, chains_dynamic, iwx_fw_valid_rx_ant(sc), iwx_fw_valid_tx_ant(sc)); idle_cnt = chains_static; active_cnt = chains_dynamic; /* In scenarios where we only ever use a single-stream rates, * i.e. legacy 11b/g/a associations, single-stream APs or even * static SMPS, enable both chains to get diversity, improving * the case where we're far enough from the AP that attenuation * between the two antennas is sufficiently different to impact * performance. */ if (active_cnt == 1 && iwx_num_of_ant(iwx_fw_valid_rx_ant(sc)) != 1) { idle_cnt = 2; active_cnt = 2; } cmd.rxchain_info = htole32(iwx_fw_valid_rx_ant(sc) << IWX_PHY_RX_CHAIN_VALID_POS); cmd.rxchain_info |= htole32(idle_cnt << IWX_PHY_RX_CHAIN_CNT_POS); cmd.rxchain_info |= htole32(active_cnt << IWX_PHY_RX_CHAIN_MIMO_CNT_POS); return iwx_send_cmd_pdu(sc, IWX_PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } int ItlIwx:: iwx_phy_ctxt_cmd_uhb(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt, uint8_t chains_static, uint8_t chains_dynamic, uint32_t action, uint32_t apply_time) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_phy_context_cmd_uhb cmd; uint8_t active_cnt, idle_cnt; struct ieee80211_channel *chan = ctxt->channel; memset(&cmd, 0, sizeof(cmd)); cmd.id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(ctxt->id, ctxt->color)); cmd.action = htole32(action); cmd.apply_time = htole32(apply_time); cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ? IWX_PHY_BAND_24 : IWX_PHY_BAND_5; cmd.ci.channel = htole32(ieee80211_chan2ieee(ic, chan)); cmd.ci.width = iwx_get_channel_width(ic, chan); cmd.ci.ctrl_pos = iwx_get_ctrl_pos(ic, chan); XYLog("%s: [%s:%s] 2ghz=%d, channel=%d, channel_width=%d pos=%d chains static=0x%x, dynamic=0x%x, " "rx_ant=0x%x, tx_ant=0x%x\n", __FUNCTION__, ic->ic_bss == NULL ? "" : (const char *)ic->ic_bss->ni_essid, ic->ic_bss == NULL ? "" : ether_sprintf(ic->ic_bss->ni_bssid), cmd.ci.band, cmd.ci.channel, cmd.ci.width, cmd.ci.ctrl_pos, chains_static, chains_dynamic, iwx_fw_valid_rx_ant(sc), iwx_fw_valid_tx_ant(sc)); idle_cnt = chains_static; active_cnt = chains_dynamic; cmd.rxchain_info = htole32(iwx_fw_valid_rx_ant(sc) << IWX_PHY_RX_CHAIN_VALID_POS); cmd.rxchain_info |= htole32(idle_cnt << IWX_PHY_RX_CHAIN_CNT_POS); cmd.rxchain_info |= htole32(active_cnt << IWX_PHY_RX_CHAIN_MIMO_CNT_POS); cmd.txchain_info = htole32(iwx_fw_valid_tx_ant(sc)); return iwx_send_cmd_pdu(sc, IWX_PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } int ItlIwx:: iwx_phy_ctxt_cmd(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt, uint8_t chains_static, uint8_t chains_dynamic, uint32_t action, uint32_t apply_time) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwx_phy_context_cmd_v1 cmd; uint8_t active_cnt, idle_cnt; struct ieee80211_channel *chan = ctxt->channel; if (iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_PHY_CONTEXT_CMD) == 3) return iwx_phy_ctxt_cmd_v3(sc, ctxt, chains_static, chains_dynamic, action, apply_time); /* * Intel increased the size of the fw_channel_info struct and neglected * to bump the phy_context_cmd struct, which contains an fw_channel_info * member in the middle. * To keep things simple we use a separate function to handle the larger * variant of the phy context command. */ if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS)) return iwx_phy_ctxt_cmd_uhb(sc, ctxt, chains_static, chains_dynamic, action, apply_time); memset(&cmd, 0, sizeof(cmd)); cmd.id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(ctxt->id, ctxt->color)); cmd.action = htole32(action); cmd.apply_time = htole32(apply_time); cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ? IWX_PHY_BAND_24 : IWX_PHY_BAND_5; cmd.ci.channel = ieee80211_chan2ieee(ic, chan); cmd.ci.width = iwx_get_channel_width(ic, chan); cmd.ci.ctrl_pos = iwx_get_ctrl_pos(ic, chan); idle_cnt = chains_static; active_cnt = chains_dynamic; cmd.rxchain_info = htole32(iwx_fw_valid_rx_ant(sc) << IWX_PHY_RX_CHAIN_VALID_POS); cmd.rxchain_info |= htole32(idle_cnt << IWX_PHY_RX_CHAIN_CNT_POS); cmd.rxchain_info |= htole32(active_cnt << IWX_PHY_RX_CHAIN_MIMO_CNT_POS); cmd.txchain_info = htole32(iwx_fw_valid_tx_ant(sc)); return iwx_send_cmd_pdu(sc, IWX_PHY_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } int ItlIwx:: iwx_send_cmd(struct iwx_softc *sc, struct iwx_host_cmd *hcmd) { struct iwx_tx_ring *ring = &sc->txq[IWX_DQA_CMD_QUEUE]; struct iwx_tfh_tfd *desc; struct iwx_tx_data *txdata; struct iwx_device_cmd *cmd; mbuf_t m; bus_addr_t paddr; uint64_t addr; int err = 0, i, paylen, off, s; int idx, code, async, group_id; size_t hdrlen, datasz; uint8_t *data; int generation = sc->sc_generation; unsigned int max_chunks = 1; IOPhysicalSegment seg; code = hcmd->id; async = hcmd->flags & IWX_CMD_ASYNC; idx = (ring->cur & (ring->ring_count - 1)); for (i = 0, paylen = 0; i < nitems(hcmd->len); i++) { paylen += hcmd->len[i]; } /* If this command waits for a response, allocate response buffer. */ hcmd->resp_pkt = NULL; if (hcmd->flags & IWX_CMD_WANT_RESP) { uint8_t *resp_buf; // KASSERT(!async); // KASSERT(hcmd->resp_pkt_len >= sizeof(struct iwx_rx_packet)); // KASSERT(hcmd->resp_pkt_len <= IWX_CMD_RESP_MAX); if (sc->sc_cmd_resp_pkt[idx] != NULL) return ENOSPC; resp_buf = (uint8_t *)malloc(hcmd->resp_pkt_len, 0, M_NOWAIT | M_ZERO); if (resp_buf == NULL) return ENOMEM; bzero(resp_buf, hcmd->resp_pkt_len); sc->sc_cmd_resp_pkt[idx] = resp_buf; sc->sc_cmd_resp_len[idx] = hcmd->resp_pkt_len; } else { sc->sc_cmd_resp_pkt[idx] = NULL; } s = splnet(); desc = &ring->desc[idx]; txdata = &ring->data[idx]; /* * XXX Intel inside (tm) * Firmware API versions >= 50 reject old-style commands in * group 0 with a "BAD_COMMAND" firmware error. We must pretend * that such commands were in the LONG_GROUP instead in order * for firmware to accept them. */ if (iwx_cmd_groupid(code) == 0) { code = IWX_WIDE_ID(IWX_LONG_GROUP, code); txdata->flags |= IWX_TXDATA_FLAG_CMD_IS_NARROW; } else txdata->flags &= ~IWX_TXDATA_FLAG_CMD_IS_NARROW; group_id = iwx_cmd_groupid(code); hdrlen = sizeof(cmd->hdr_wide); datasz = sizeof(cmd->data_wide); if (paylen > datasz) { /* Command is too large to fit in pre-allocated space. */ size_t totlen = hdrlen + paylen; if (paylen > IWX_MAX_CMD_PAYLOAD_SIZE) { XYLog("%s: firmware command too long (%zd bytes)\n", DEVNAME(sc), totlen); err = EINVAL; goto out; } mbuf_allocpacket(MBUF_WAITOK, totlen, &max_chunks, &m); if (m == NULL) { XYLog("%s: could not get fw cmd mbuf (%zd bytes)\n", DEVNAME(sc), totlen); err = ENOMEM; goto out; } mbuf_setlen(m, totlen); mbuf_pkthdr_setlen(m, totlen); cmd = mtod(m, struct iwx_device_cmd *); txdata->map->dm_nsegs = txdata->map->cursor->getPhysicalSegmentsWithCoalesce(m, &seg, 1); if (txdata->map->dm_nsegs == 0) { XYLog("%s: could not load fw cmd mbuf (%zd bytes)\n", DEVNAME(sc), totlen); mbuf_freem(m); goto out; } // XYLog("map fw cmd dm_nsegs=%d\n", txdata->map->dm_nsegs); txdata->m = m; /* mbuf will be freed in iwm_cmd_done() */ paddr = seg.location; } else { cmd = &ring->cmd[idx]; paddr = txdata->cmd_paddr; } cmd->hdr_wide.cmd = iwx_cmd_opcode(code); cmd->hdr_wide.group_id = group_id; cmd->hdr_wide.qid = ring->qid; cmd->hdr_wide.idx = idx; cmd->hdr_wide.length = htole16(paylen); cmd->hdr_wide.reserved = htole16(0); cmd->hdr_wide.version = iwx_cmd_version(code); data = cmd->data_wide; for (i = 0, off = 0; i < nitems(hcmd->data); i++) { if (hcmd->len[i] == 0) continue; memcpy(data + off, hcmd->data[i], hcmd->len[i]); off += hcmd->len[i]; } KASSERT(off == paylen, "off == paylen"); desc->tbs[0].tb_len = htole16(MIN(hdrlen + paylen, IWX_FIRST_TB_SIZE)); addr = htole64(paddr); memcpy(&desc->tbs[0].addr, &addr, sizeof(addr)); if (hdrlen + paylen > IWX_FIRST_TB_SIZE) { desc->tbs[1].tb_len = htole16(hdrlen + paylen - IWX_FIRST_TB_SIZE); addr = htole64(paddr + IWX_FIRST_TB_SIZE); memcpy(&desc->tbs[1].addr, &addr, sizeof(addr)); desc->num_tbs = htole16(2); } else desc->num_tbs = htole16(1); // if (paylen > datasz) { // bus_dmamap_sync(sc->sc_dmat, txdata->map, 0, // hdrlen + paylen, BUS_DMASYNC_PREWRITE); // } else { // bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map, // (char *)(void *)cmd - (char *)(void *)ring->cmd_dma.vaddr, // hdrlen + paylen, BUS_DMASYNC_PREWRITE); // } // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, // (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr, // sizeof (*desc), BUS_DMASYNC_PREWRITE); /* Kick command ring. */ DPRINTF(("%s: Sending command (%.2x.%.2x), %d bytes at [%d]:%d ver: %d\n", __func__, group_id, cmd->hdr.cmd, cmd->hdr_wide.length, cmd->hdr.idx, cmd->hdr.qid, cmd->hdr_wide.version)); ring->queued++; ring->cur = (ring->cur + 1) % getTxQueueSize(); IWX_WRITE(sc, IWX_HBUS_TARG_WRPTR, ring->qid << 16 | ring->cur); if (!async) { err = tsleep_nsec(desc, PCATCH, "iwxcmd", SEC_TO_NSEC(1)); if (err == 0) { /* if hardware is no longer up, return error */ if (generation != sc->sc_generation) { err = ENXIO; goto out; } /* Response buffer will be freed in iwx_free_resp(). */ hcmd->resp_pkt = (struct iwx_rx_packet *)sc->sc_cmd_resp_pkt[idx]; sc->sc_cmd_resp_pkt[idx] = NULL; } else if (generation == sc->sc_generation) { ::free(sc->sc_cmd_resp_pkt[idx]); sc->sc_cmd_resp_pkt[idx] = NULL; } } out: splx(s); return err; } int ItlIwx:: iwx_send_cmd_pdu(struct iwx_softc *sc, uint32_t id, uint32_t flags, uint16_t len, const void *data) { struct iwx_host_cmd cmd = { .id = id, .len = { len, }, .data = { data, }, .flags = flags, }; return iwx_send_cmd(sc, &cmd); } int ItlIwx:: iwx_send_cmd_status(struct iwx_softc *sc, struct iwx_host_cmd *cmd, uint32_t *status) { struct iwx_rx_packet *pkt; struct iwx_cmd_response *resp; int err, resp_len; KASSERT((cmd->flags & IWX_CMD_WANT_RESP) == 0, "(cmd->flags & IWX_CMD_WANT_RESP) == 0"); cmd->flags |= IWX_CMD_WANT_RESP; cmd->resp_pkt_len = sizeof(*pkt) + sizeof(*resp); err = iwx_send_cmd(sc, cmd); if (err) return err; pkt = cmd->resp_pkt; if (pkt == NULL || (pkt->hdr.group_id & IWX_CMD_FAILED_MSK)) return EIO; resp_len = iwx_rx_packet_payload_len(pkt); if (resp_len != sizeof(*resp)) { iwx_free_resp(sc, cmd); return EIO; } resp = (struct iwx_cmd_response *)pkt->data; *status = le32toh(resp->status); iwx_free_resp(sc, cmd); return err; } int ItlIwx:: iwx_send_cmd_pdu_status(struct iwx_softc *sc, uint32_t id, uint16_t len, const void *data, uint32_t *status) { struct iwx_host_cmd cmd = { .id = id, .len = { len, }, .data = { data, }, }; return iwx_send_cmd_status(sc, &cmd, status); } void ItlIwx:: iwx_free_resp(struct iwx_softc *sc, struct iwx_host_cmd *hcmd) { KASSERT((hcmd->flags & (IWX_CMD_WANT_RESP)) == IWX_CMD_WANT_RESP, "(hcmd->flags & (IWX_CMD_WANT_RESP)) == IWX_CMD_WANT_RESP"); ::free(hcmd->resp_pkt); hcmd->resp_pkt = NULL; } void ItlIwx:: iwx_cmd_done(struct iwx_softc *sc, int qid, int idx, int code) { struct iwx_tx_ring *ring = &sc->txq[IWX_DQA_CMD_QUEUE]; struct iwx_tx_data *data; if (qid != IWX_DQA_CMD_QUEUE) { return; /* Not a command ack. */ } data = &ring->data[idx]; if (data->m != NULL) { // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); // bus_dmamap_unload(sc->sc_dmat, data->map); mbuf_freem(data->m); data->m = NULL; } wakeupOn(&ring->desc[idx]); DPRINTF(("%s: command 0x%x done\n", __func__, code)); if (ring->queued == 0) { DPRINTF(("%s: unexpected firmware response to command 0x%x\n", DEVNAME(sc), code)); } else if (ring->queued > 0) ring->queued--; } uint32_t ItlIwx:: iwx_get_tx_ant(struct iwx_softc *sc, struct ieee80211_node *ni, const struct iwx_rate *rinfo, int type, struct ieee80211_frame *wh) { return ((1 << sc->sc_mgmt_last_antenna_idx) << IWX_RATE_MCS_ANT_POS); } void ItlIwx:: iwx_toggle_tx_ant(struct iwx_softc *sc, uint8_t *ant) { uint8_t valid = iwx_fw_valid_tx_ant(sc); int i; uint8_t ind = *ant; for (i = 0; i < IWX_RATE_MCS_ANT_NUM; i++) { ind = (ind + 1) % IWX_RATE_MCS_ANT_NUM; if (valid & (1 << ind)) { *ant = ind; break; } } } /* * Fill in various bit for management frames, and leave them * unfilled for data frames (firmware takes care of that). * Return the selected TX rate. */ const struct iwx_rate *ItlIwx:: iwx_tx_fill_cmd(struct iwx_softc *sc, struct iwx_node *in, struct ieee80211_frame *wh, uint32_t *flags, uint32_t *rate_n_flags) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = &in->in_ni; struct ieee80211_rateset *rs = &ni->ni_rates; const struct iwx_rate *rinfo; int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; int min_ridx = iwx_rval2ridx(ieee80211_min_basic_rate(ic)); int ridx, rate_flags; uint8_t cmdver; uint8_t hwrate; *flags = 0; if (IEEE80211_IS_MULTICAST(wh->i_addr1) || type != IEEE80211_FC0_TYPE_DATA) { /* for non-data, use the lowest supported rate */ ridx = min_ridx; *flags |= IWX_TX_FLAGS_CMD_RATE; } else if (ic->ic_fixed_mcs != -1) { ridx = sc->sc_fixed_ridx; *flags |= IWX_TX_FLAGS_CMD_RATE; } else if (ic->ic_fixed_rate != -1) { ridx = sc->sc_fixed_ridx; *flags |= IWX_TX_FLAGS_CMD_RATE; } else if (ni->ni_flags & IEEE80211_NODE_HT) { ridx = iwx_mcs2ridx[ni->ni_txmcs]; return &iwx_rates[ridx]; } else { uint8_t rval; rval = (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL); ridx = iwx_rval2ridx(rval); if (ridx < min_ridx) ridx = min_ridx; return &iwx_rates[ridx]; } rinfo = &iwx_rates[ridx]; rate_flags = iwx_get_tx_ant(sc, ni, rinfo, type, wh); hwrate = rinfo->plcp; cmdver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_TX_CMD); if (cmdver > 8 && cmdver != IWX_FW_CMD_VER_UNKNOWN) { if (IWX_RIDX_IS_CCK(ridx)) { rate_flags |= IWX_RATE_MCS_CCK_MSK; hwrate = ridx; } else { rate_flags |= IWX_RATE_MCS_LEGACY_OFDM_MSK; hwrate = iwx_rate2idx(iwx_ridx2rate(rs, ridx) & IEEE80211_RATE_VAL); } } else if (IWX_RIDX_IS_CCK(ridx)) rate_flags |= IWX_RATE_MCS_CCK_MSK_V1; XYLog("%s hwrate: %d ridx: %d rate: %d minrate: %d\n", __FUNCTION__, hwrate, ridx, iwx_ridx2rate(rs, ridx) & IEEE80211_RATE_VAL, ieee80211_min_basic_rate(ic)); *rate_n_flags = htole32(rate_flags | hwrate); return rinfo; } void ItlIwx:: iwx_tx_update_byte_tbl(struct iwx_softc *sc, struct iwx_tx_ring *txq, int idx, uint16_t byte_cnt, uint16_t num_tbs) { uint8_t filled_tfd_size, num_fetch_chunks; uint16_t len = byte_cnt; uint16_t bc_ent; filled_tfd_size = offsetof(struct iwx_tfh_tfd, tbs) + num_tbs * sizeof(struct iwx_tfh_tb); /* * filled_tfd_size contains the number of filled bytes in the TFD. * Dividing it by 64 will give the number of chunks to fetch * to SRAM- 0 for one chunk, 1 for 2 and so on. * If, for example, TFD contains only 3 TBs then 32 bytes * of the TFD are used, and only one chunk of 64 bytes should * be fetched */ num_fetch_chunks = howmany(filled_tfd_size, 64) - 1; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) { struct iwx_gen3_bc_tbl *scd_bc_tbl_gen3 = (struct iwx_gen3_bc_tbl *)txq->bc_tbl.vaddr; /* Starting from AX210, the HW expects bytes */ bc_ent = htole16(len | (num_fetch_chunks << 14)); scd_bc_tbl_gen3->tfd_offset[idx] = bc_ent; } else { struct iwx_agn_scd_bc_tbl *scd_bc_tbl = (struct iwx_agn_scd_bc_tbl *)txq->bc_tbl.vaddr; /* Before AX210, the HW expects DW */ len = howmany(len, 4); bc_ent = htole16(len | (num_fetch_chunks << 12)); scd_bc_tbl->tfd_offset[idx] = bc_ent; } } int ItlIwx:: iwx_tx(struct iwx_softc *sc, mbuf_t m, struct ieee80211_node *ni, int ac) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_node *in = (struct iwx_node *)ni; struct iwx_tx_ring *ring; struct iwx_tx_data *data; struct iwx_tfh_tfd *desc; struct iwx_device_cmd *cmd; struct iwx_tx_cmd_gen2 *tx_gen2; struct iwx_tx_cmd_gen3 *tx_gen3; struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; const struct iwx_rate *rinfo; uint64_t paddr; u_int hdrlen; IOPhysicalSegment *seg; IOPhysicalSegment segs[IWX_TFH_NUM_TBS - 2]; int nsegs = 0; uint32_t flags = 0, rate_n_flags = 0; uint16_t offload_assist = 0; uint16_t cmd_size = 0; uint16_t num_tbs; uint8_t tid, type, subtype; int i, totlen; int qid = IWX_INVALID_QUEUE; int idx; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; if (type == IEEE80211_FC0_TYPE_CTL) hdrlen = sizeof(struct ieee80211_frame_min); else hdrlen = ieee80211_get_hdrlen(wh); tid = IWX_MGMT_TID; qid = sc->first_data_qid; /* Put QoS frames on the data queue which maps to their TID. */ if (ieee80211_has_qos(wh)) { struct ieee80211_tx_ba *ba; uint16_t qos = ieee80211_get_qos(wh); uint8_t tid = qos & IEEE80211_QOS_TID; ba = &ni->ni_tx_ba[tid]; if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && type == IEEE80211_FC0_TYPE_DATA && subtype != IEEE80211_FC0_SUBTYPE_NODATA && sc->sc_tid_data[tid].qid != 0 && sc->sc_tid_data[tid].qid != IWX_INVALID_QUEUE && ba->ba_state == IEEE80211_BA_AGREED) { qid = sc->sc_tid_data[tid].qid; } } ring = &sc->txq[qid]; if (ring->ring_count == 0) { mbuf_freem(m); return EINVAL; } idx = (ring->cur & (ring->ring_count - 1)); desc = &ring->desc[idx]; memset(desc, 0, sizeof(*desc)); data = &ring->data[idx]; cmd = &ring->cmd[idx]; cmd->hdr.cmd = IWX_TX_CMD; cmd->hdr.group_id = 0; cmd->hdr.qid = ring->qid; cmd->hdr.idx = idx; rinfo = iwx_tx_fill_cmd(sc, in, wh, &flags, &rate_n_flags); #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { struct iwx_tx_radiotap_header *tap = &sc->sc_txtap; uint16_t chan_flags; tap->wt_flags = 0; tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); chan_flags = ni->ni_chan->ic_flags; if (ic->ic_curmode != IEEE80211_MODE_11N) chan_flags &= ~IEEE80211_CHAN_HT; tap->wt_chan_flags = htole16(chan_flags); if ((ni->ni_flags & IEEE80211_NODE_HT) && !IEEE80211_IS_MULTICAST(wh->i_addr1) && type == IEEE80211_FC0_TYPE_DATA && rinfo->ht_plcp != IWX_RATE_HT_SISO_MCS_INV_PLCP) { tap->wt_rate = (0x80 | rinfo->ht_plcp); } else tap->wt_rate = rinfo->rate; if ((ic->ic_flags & IEEE80211_F_WEPON) && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; bpf_mtap_hdr(sc->sc_drvbpf, tap, sc->sc_txtap_len, m, BPF_DIRECTION_OUT); } #endif if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_get_txkey(ic, wh, ni); if (k->k_cipher != IEEE80211_CIPHER_CCMP) { if ((m = ieee80211_encrypt(ic, m, k)) == NULL) return ENOBUFS; /* 802.11 header may have moved. */ wh = mtod(m, struct ieee80211_frame *); flags |= htole32(IWX_TX_FLAGS_ENCRYPT_DIS); } else { k->k_tsc++; /* Hardware increments PN internally and adds IV. */ } } else flags |= htole32(IWX_TX_FLAGS_ENCRYPT_DIS); // totlen = m->m_pkthdr.len; totlen = mbuf_pkthdr_len(m); if (hdrlen % 4) offload_assist |= IWX_TX_CMD_OFFLD_PAD; if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) { tx_gen3 = (struct iwx_tx_cmd_gen3 *)cmd->data; cmd_size = sizeof(*tx_gen3); memset(tx_gen3, 0, cmd_size); tx_gen3->len = htole16(totlen); tx_gen3->offload_assist = htole32(offload_assist); /* Copy 802.11 header in TX command. */ memcpy(((uint8_t *)tx_gen3) + sizeof(*tx_gen3), wh, hdrlen); tx_gen3->flags = htole16(flags); tx_gen3->rate_n_flags = htole32(rate_n_flags); } else { tx_gen2 = (struct iwx_tx_cmd_gen2 *)cmd->data; cmd_size = sizeof(*tx_gen2); memset(tx_gen2, 0, cmd_size); tx_gen2->len = htole16(totlen); tx_gen2->offload_assist = htole16(offload_assist); /* Copy 802.11 header in TX command. */ memcpy(((uint8_t *)tx_gen2) + sizeof(*tx_gen2), wh, hdrlen); tx_gen2->flags = htole32(flags); tx_gen2->rate_n_flags = htole32(rate_n_flags); } /* Trim 802.11 header. */ mbuf_adj(m, hdrlen); nsegs = data->map->cursor->getPhysicalSegmentsWithCoalesce(m, &segs[0], IWX_TFH_NUM_TBS - 2); if (nsegs == 0) { XYLog("%s: can't map mbuf (error %d)\n", DEVNAME(sc), nsegs); mbuf_freem(m); return ENOMEM; } data->m = m; data->in = in; data->type = type; DPRINTFN(3, ("sending data: 嘤嘤嘤 tid=%d qid=%d idx=%d queued=%d len=%d nsegs=%d flags=0x%08x rate_n_flags=0x%08x offload_assist=%u\n", tid, ring->qid, ring->cur, ring->queued, totlen, nsegs, le32toh(flags), le32toh(rate_n_flags), offload_assist)); /* Fill TX descriptor. */ num_tbs = 2 + nsegs; desc->num_tbs = htole16(num_tbs); desc->tbs[0].tb_len = htole16(IWX_FIRST_TB_SIZE); paddr = htole64(data->cmd_paddr); memcpy(&desc->tbs[0].addr, &paddr, sizeof(paddr)); if (data->cmd_paddr >> 32 != (data->cmd_paddr + le32toh(desc->tbs[0].tb_len)) >> 32) DPRINTF(("%s: TB0 crosses 32bit boundary\n", __func__)); desc->tbs[1].tb_len = htole16(_ALIGN(sizeof(struct iwx_cmd_header) + cmd_size + hdrlen - IWX_FIRST_TB_SIZE, 4)); paddr = htole64(data->cmd_paddr + IWX_FIRST_TB_SIZE); memcpy(&desc->tbs[1].addr, &paddr, sizeof(paddr)); if (data->cmd_paddr >> 32 != (data->cmd_paddr + le32toh(desc->tbs[1].tb_len)) >> 32) DPRINTF(("%s: TB1 crosses 32bit boundary\n", __func__)); /* Other DMA segments are for data payload. */ for (i = 0; i < nsegs; i++) { seg = &segs[i]; desc->tbs[i + 2].tb_len = htole16(seg->length); paddr = htole64(seg->location); memcpy(&desc->tbs[i + 2].addr, &paddr, sizeof(paddr)); if (data->cmd_paddr >> 32 != (data->cmd_paddr + le32toh(desc->tbs[i + 2].tb_len)) >> 32) DPRINTF(("%s: TB%d crosses 32bit boundary\n", __func__, i + 2)); // XYLog("DMA segments index=%d location=0x%llx length=%llu", i, seg->location, seg->length); } // bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, // BUS_DMASYNC_PREWRITE); // bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map, // (char *)(void *)cmd - (char *)(void *)ring->cmd_dma.vaddr, // sizeof (*cmd), BUS_DMASYNC_PREWRITE); // bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, // (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr, // sizeof (*desc), BUS_DMASYNC_PREWRITE); iwx_tx_update_byte_tbl(sc, ring, idx, totlen, num_tbs); /* Kick TX ring. */ ring->cur = (ring->cur + 1) % getTxQueueSize(); IWX_WRITE(sc, IWX_HBUS_TARG_WRPTR, ring->qid << 16 | ring->cur); /* Mark TX ring as full if we reach a certain threshold. */ if (++ring->queued > ring->hi_mark) { // XYLog("%s sc->qfullmsk is FULL qid=%d ring->cur=%d ring->queued=%d\n", __FUNCTION__, ring->qid, ring->cur, ring->queued); sc->qfullmsk |= 1 << ring->qid; } return 0; } int ItlIwx:: iwx_flush_sta_tids(struct iwx_softc *sc, int sta_id, uint16_t tids) { struct iwx_rx_packet *pkt; struct iwx_tx_path_flush_cmd_rsp *resp; struct iwx_tx_path_flush_cmd flush_cmd = { .sta_id = htole32(sta_id), .tid_mask = htole16(tids), }; struct iwx_host_cmd hcmd = { .id = IWX_TXPATH_FLUSH, .len = { sizeof(flush_cmd), }, .data = { &flush_cmd, }, .flags = IWX_CMD_WANT_RESP, .resp_pkt_len = sizeof(*pkt) + sizeof(*resp), }; int err, resp_len, i, num_flushed_queues; err = iwx_send_cmd(sc, &hcmd); if (err) return err; pkt = hcmd.resp_pkt; if (!pkt || (pkt->hdr.group_id & IWX_CMD_FAILED_MSK)) { err = EIO; goto out; } resp_len = iwx_rx_packet_payload_len(pkt); /* Some firmware versions don't provide a response. */ if (resp_len == 0) goto out; else if (resp_len != sizeof(*resp)) { err = EIO; goto out; } resp = (struct iwx_tx_path_flush_cmd_rsp *)pkt->data; if (le16toh(resp->sta_id) != sta_id) { err = EIO; goto out; } num_flushed_queues = le16toh(resp->num_flushed_queues); if (num_flushed_queues > IWX_TX_FLUSH_QUEUE_RSP) { err = EIO; goto out; } for (i = 0; i < num_flushed_queues; i++) { struct iwx_flush_queue_info *queue_info = &resp->queues[i]; uint16_t tid = le16toh(queue_info->tid); uint16_t read_after = le16toh(queue_info->read_after_flush); uint16_t qid = le16toh(queue_info->queue_num); struct iwx_tx_ring *txq; if (qid >= nitems(sc->txq)) continue; if (sc->sc_tid_data[tid].qid != qid) continue; txq = &sc->txq[qid]; iwx_ampdu_txq_advance(sc, txq, IWX_AGG_SSN_TO_TXQ_IDX(read_after, txq->ring_count)); } out: iwx_free_resp(sc, &hcmd); return err; } int ItlIwx:: iwx_flush_sta(struct iwx_softc *sc, struct iwx_node *in) { int err; splassert(IPL_NET); sc->sc_flags |= IWX_FLAG_TXFLUSH; err = iwx_drain_sta(sc, in, 1); if (err == ENXIO) goto done; err = iwx_flush_sta_tids(sc, IWX_STATION_ID, 0xffff); if (err) { XYLog("%s: could not flush Tx path (error %d)\n", __FUNCTION__, err); goto done; } err = iwx_drain_sta(sc, in, 0); if (err == ENXIO) goto done; else err = 0; done: sc->sc_flags &= ~IWX_FLAG_TXFLUSH; return err; } int ItlIwx:: iwx_drain_sta(struct iwx_softc *sc, struct iwx_node* in, int drain) { struct iwx_add_sta_cmd cmd; int err; uint32_t status; memset(&cmd, 0, sizeof(cmd)); cmd.mac_id_n_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); cmd.sta_id = IWX_STATION_ID; cmd.add_modify = IWX_STA_MODE_MODIFY; cmd.station_flags = drain ? htole32(IWX_STA_FLG_DRAIN_FLOW) : 0; cmd.station_flags_msk = htole32(IWX_STA_FLG_DRAIN_FLOW); status = IWX_ADD_STA_SUCCESS; err = iwx_send_cmd_pdu_status(sc, IWX_ADD_STA, sizeof(cmd), &cmd, &status); if (err) { printf("%s: could not update sta (error %d)\n", DEVNAME(sc), err); return err; } switch (status & IWX_ADD_STA_STATUS_MASK) { case IWX_ADD_STA_SUCCESS: break; default: err = EIO; printf("%s: Couldn't %s draining for station\n", DEVNAME(sc), drain ? "enable" : "disable"); break; } return err; } #define IWX_POWER_KEEP_ALIVE_PERIOD_SEC 25 int ItlIwx:: iwx_beacon_filter_send_cmd(struct iwx_softc *sc, struct iwx_beacon_filter_cmd *cmd) { size_t len; if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_BEACON_FILTER_V4)) len = sizeof(struct iwx_beacon_filter_cmd); else len = offsetof(struct iwx_beacon_filter_cmd, bf_threshold_absolute_low); return iwx_send_cmd_pdu(sc, IWX_REPLY_BEACON_FILTERING_CMD, 0, len, cmd); } int ItlIwx:: iwx_update_beacon_abort(struct iwx_softc *sc, struct iwx_node *in, int enable) { struct iwx_beacon_filter_cmd cmd = { IWX_BF_CMD_CONFIG_DEFAULTS, .bf_enable_beacon_filter = htole32(1), .ba_enable_beacon_abort = htole32(enable), }; if (!sc->sc_bf.bf_enabled) return 0; sc->sc_bf.ba_enabled = enable; return iwx_beacon_filter_send_cmd(sc, &cmd); } void ItlIwx:: iwx_power_build_cmd(struct iwx_softc *sc, struct iwx_node *in, struct iwx_mac_power_cmd *cmd) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = &in->in_ni; int dtim_period, dtim_msec, keep_alive; cmd->id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); if (ni->ni_dtimperiod) dtim_period = ni->ni_dtimperiod; else dtim_period = 1; /* * Regardless of power management state the driver must set * keep alive period. FW will use it for sending keep alive NDPs * immediately after association. Check that keep alive period * is at least 3 * DTIM. */ dtim_msec = dtim_period * ni->ni_intval; keep_alive = MAX(3 * dtim_msec, 1000 * IWX_POWER_KEEP_ALIVE_PERIOD_SEC); keep_alive = roundup(keep_alive, 1000) / 1000; cmd->keep_alive_seconds = htole16(keep_alive); if (ic->ic_opmode != IEEE80211_M_MONITOR) cmd->flags = htole16(IWX_POWER_FLAGS_POWER_SAVE_ENA_MSK); } int ItlIwx:: iwx_power_mac_update_mode(struct iwx_softc *sc, struct iwx_node *in) { int err; int ba_enable; struct iwx_mac_power_cmd cmd; memset(&cmd, 0, sizeof(cmd)); iwx_power_build_cmd(sc, in, &cmd); err = iwx_send_cmd_pdu(sc, IWX_MAC_PM_POWER_TABLE, 0, sizeof(cmd), &cmd); if (err != 0) return err; ba_enable = !!(cmd.flags & htole16(IWX_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); return iwx_update_beacon_abort(sc, in, ba_enable); } int ItlIwx:: iwx_power_update_device(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_device_power_cmd cmd = { }; struct ieee80211com *ic = &sc->sc_ic; if (ic->ic_opmode != IEEE80211_M_MONITOR) cmd.flags = htole16(IWX_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); return iwx_send_cmd_pdu(sc, IWX_POWER_TABLE_CMD, 0, sizeof(cmd), &cmd); } int ItlIwx:: iwx_enable_beacon_filter(struct iwx_softc *sc, struct iwx_node *in) { struct iwx_beacon_filter_cmd cmd = { IWX_BF_CMD_CONFIG_DEFAULTS, .bf_enable_beacon_filter = htole32(1), .ba_enable_beacon_abort = htole32(sc->sc_bf.ba_enabled), }; int err; err = iwx_beacon_filter_send_cmd(sc, &cmd); if (err == 0) sc->sc_bf.bf_enabled = 1; return err; } int ItlIwx:: iwx_disable_beacon_filter(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_beacon_filter_cmd cmd; int err; memset(&cmd, 0, sizeof(cmd)); err = iwx_beacon_filter_send_cmd(sc, &cmd); if (err == 0) sc->sc_bf.bf_enabled = 0; return err; } int ItlIwx:: iwx_add_sta_cmd(struct iwx_softc *sc, struct iwx_node *in, int update) { struct iwx_add_sta_cmd add_sta_cmd; int err; uint32_t status, agg_size = 0; uint32_t max_aggsize = (IWX_STA_FLG_MAX_AGG_SIZE_4M >> IWX_STA_FLG_MAX_AGG_SIZE_SHIFT); struct ieee80211com *ic = &sc->sc_ic; if (!update && (sc->sc_flags & IWX_FLAG_STA_ACTIVE)) { XYLog("STA already added\n"); return 0; } memset(&add_sta_cmd, 0, sizeof(add_sta_cmd)); if (ic->ic_opmode == IEEE80211_M_MONITOR) { add_sta_cmd.sta_id = IWX_MONITOR_STA_ID; add_sta_cmd.station_type = IWX_STA_GENERAL_PURPOSE; } else { add_sta_cmd.sta_id = IWX_STATION_ID; add_sta_cmd.station_type = IWX_STA_LINK; } add_sta_cmd.mac_id_n_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); if (!update) { if (ic->ic_opmode == IEEE80211_M_MONITOR) IEEE80211_ADDR_COPY(&add_sta_cmd.addr, etheranyaddr); else IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_macaddr); } add_sta_cmd.add_modify = update ? 1 : 0; add_sta_cmd.station_flags_msk |= htole32(IWX_STA_FLG_FAT_EN_MSK | IWX_STA_FLG_MIMO_EN_MSK); add_sta_cmd.tid_disable_tx = htole16(0xffff); if ((in->in_ni.ni_flags & IEEE80211_NODE_HT) || (in->in_ni.ni_flags & IEEE80211_NODE_VHT) || (in->in_ni.ni_flags & IEEE80211_NODE_HE)) { add_sta_cmd.station_flags_msk |= htole32(IWX_STA_FLG_MAX_AGG_SIZE_MSK | IWX_STA_FLG_AGG_MPDU_DENS_MSK); if (ic->ic_state >= IEEE80211_S_ASSOC) { switch (in->in_ni.ni_chw) { case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_FAT_EN_160MHZ); case IEEE80211_CHAN_WIDTH_80: add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_FAT_EN_80MHZ); case IEEE80211_CHAN_WIDTH_40: add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_FAT_EN_40MHZ); case IEEE80211_CHAN_WIDTH_20: default: add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_FAT_EN_20MHZ); break; } } if (iwx_mimo_enabled(sc) && ic->ic_bss->ni_rx_nss > 1) add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_MIMO_EN_MIMO2); else add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_MIMO_EN_SISO); if (in->in_ni.ni_flags & IEEE80211_NODE_HE) { agg_size = in->in_ni.ni_vhtcaps & IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; agg_size >>= IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; agg_size += u8_get_bits(in->in_ni.ni_he_cap_elem.mac_cap_info[3], IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK); add_sta_cmd.station_flags |= htole32(min(max_aggsize, agg_size) << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT); } else if (in->in_ni.ni_flags & IEEE80211_NODE_VHT) { agg_size = in->in_ni.ni_vhtcaps & IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; agg_size >>= IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; add_sta_cmd.station_flags |= htole32(min(max_aggsize, agg_size) << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT); } else if (in->in_ni.ni_flags & IEEE80211_NODE_HT) add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_MAX_AGG_SIZE_64K); switch (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_SS) { case IEEE80211_AMPDU_PARAM_SS_2: add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_AGG_MPDU_DENS_2US); break; case IEEE80211_AMPDU_PARAM_SS_4: add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_AGG_MPDU_DENS_4US); break; case IEEE80211_AMPDU_PARAM_SS_8: add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_AGG_MPDU_DENS_8US); break; case IEEE80211_AMPDU_PARAM_SS_16: add_sta_cmd.station_flags |= htole32(IWX_STA_FLG_AGG_MPDU_DENS_16US); break; default: break; } } status = IWX_ADD_STA_SUCCESS; err = iwx_send_cmd_pdu_status(sc, IWX_ADD_STA, sizeof(add_sta_cmd), &add_sta_cmd, &status); if (!err && (status & IWX_ADD_STA_STATUS_MASK) != IWX_ADD_STA_SUCCESS) err = EIO; else sc->sc_flags |= IWX_FLAG_STA_ACTIVE; return err; } int ItlIwx:: iwx_add_aux_sta(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_add_sta_cmd cmd; int err, qid = IWX_DQA_AUX_QUEUE; uint32_t status; uint8_t cmdver; /* * Add auxiliary station for scanning. * Newer versions of this command implies that the fw uses * internal aux station for all aux activities that don't * requires a dedicated data queue. * In old version the aux station uses mac id like other * station and not lmac id */ cmdver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_ADD_STA); if (cmdver != IWX_FW_CMD_VER_UNKNOWN && cmdver >= 12) return 0; memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = IWX_AUX_STA_ID; cmd.station_type = IWX_STA_AUX_ACTIVITY; cmd.mac_id_n_color = htole32(IWX_FW_CMD_ID_AND_COLOR(IWX_MAC_INDEX_AUX, 0)); cmd.tid_disable_tx = htole16(0xffff); status = IWX_ADD_STA_SUCCESS; err = iwx_send_cmd_pdu_status(sc, IWX_ADD_STA, sizeof(cmd), &cmd, &status); if (!err && (status & IWX_ADD_STA_STATUS_MASK) != IWX_ADD_STA_SUCCESS) return EIO; return iwx_enable_txq(sc, IWX_AUX_STA_ID, qid, IWX_MGMT_TID, sc->txq[qid].ring_count); return 0; } int ItlIwx:: iwx_rm_sta_cmd(struct iwx_softc *sc, struct iwx_node *in) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_rm_sta_cmd rm_sta_cmd; int err; if ((sc->sc_flags & IWX_FLAG_STA_ACTIVE) == 0) { XYLog("sta already removed\n"); return 0; } memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); if (ic->ic_opmode == IEEE80211_M_MONITOR) rm_sta_cmd.sta_id = IWX_MONITOR_STA_ID; else rm_sta_cmd.sta_id = IWX_STATION_ID; err = iwx_send_cmd_pdu(sc, IWX_REMOVE_STA, 0, sizeof(rm_sta_cmd), &rm_sta_cmd); sc->sc_flags &= ~IWX_FLAG_STA_ACTIVE; return err; } int ItlIwx:: iwx_rm_sta(struct iwx_softc *sc, struct iwx_node *in) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = &in->in_ni; int err, i; err = iwx_flush_sta(sc, in); if (err) { XYLog("%s: could not flush Tx path (error %d)\n", __FUNCTION__, err); return err; } err = iwx_rm_sta_cmd(sc, in); if (err) { printf("%s: could not remove STA (error %d)\n", DEVNAME(sc), err); return err; } sc->sc_rx_ba_sessions = 0; sc->ba_rx.start_tidmask = 0; sc->ba_rx.stop_tidmask = 0; sc->ba_tx.start_tidmask = 0; sc->ba_tx.stop_tidmask = 0; for (i = 0; i < IEEE80211_NUM_TID; i++) { struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[i]; if (ba->ba_state != IEEE80211_BA_AGREED) continue; ieee80211_delba_request(ic, ni, 0, 1, i); } return 0; } uint8_t ItlIwx:: iwx_umac_scan_fill_channels(struct iwx_softc *sc, struct iwx_scan_channel_cfg_umac *chan, int n_ssids, int bgscan) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_channel *c; uint8_t nchan; for (nchan = 0, c = &ic->ic_channels[1]; c <= &ic->ic_channels[IEEE80211_CHAN_MAX] && nchan < sc->sc_capa_n_scan_channels; c++) { uint8_t channel_num; if (c->ic_flags == 0) continue; channel_num = ieee80211_mhz2ieee(c->ic_freq, 0); if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_SCAN_EXT_CHAN_VER)) { chan->v2.channel_num = channel_num; if (IEEE80211_IS_CHAN_2GHZ(c)) chan->v2.band = IWX_PHY_BAND_24; else chan->v2.band = IWX_PHY_BAND_5; chan->v2.iter_count = 1; chan->v2.iter_interval = 0; } else { chan->v1.channel_num = channel_num; chan->v1.iter_count = 1; chan->v1.iter_interval = htole16(0); } if (n_ssids != 0 && !bgscan) chan->flags = htole32(1 << 0); /* select SSID 0 */ chan++; nchan++; } return nchan; } int ItlIwx:: iwx_fill_probe_req_v1(struct iwx_softc *sc, struct iwx_scan_probe_req_v1 *preq1) { XYLog("%s\n", __FUNCTION__); struct iwx_scan_probe_req preq2; int err, i; err = iwx_fill_probe_req(sc, &preq2); if (err) return err; preq1->mac_header = preq2.mac_header; for (i = 0; i < nitems(preq1->band_data); i++) preq1->band_data[i] = preq2.band_data[i]; preq1->common_data = preq2.common_data; memcpy(preq1->buf, preq2.buf, sizeof(preq1->buf)); return 0; } int ItlIwx:: iwx_fill_probe_req(struct iwx_softc *sc, struct iwx_scan_probe_req *preq) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf; struct ieee80211_rateset *rs; size_t remain = sizeof(preq->buf); uint8_t *frm, *pos; memset(preq, 0, sizeof(*preq)); if (remain < sizeof(*wh) + 2) return ENOBUFS; /* * Build a probe request frame. Most of the following code is a * copy & paste of what is done in net80211. */ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; // IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl)); IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr); *(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */ *(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */ frm = (uint8_t *)(wh + 1); *frm++ = IEEE80211_ELEMID_SSID; *frm++ = 0; /* hardware inserts SSID */ /* Tell the firmware where the MAC header is. */ preq->mac_header.offset = 0; preq->mac_header.len = htole16(frm - (uint8_t *)wh); remain -= frm - (uint8_t *)wh; /* Fill in 2GHz IEs and tell firmware where they are. */ rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; if (rs->rs_nrates > IEEE80211_RATE_SIZE) { if (remain < 4 + rs->rs_nrates) return ENOBUFS; } else if (remain < 2 + rs->rs_nrates) return ENOBUFS; preq->band_data[0].offset = htole16(frm - (uint8_t *)wh); pos = frm; frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); remain -= frm - pos; if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT)) { if (remain < 3) return ENOBUFS; *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = 0; remain -= 3; } preq->band_data[0].len = htole16(frm - pos); if (sc->sc_nvm.sku_cap_band_52GHz_enable) { /* Fill in 5GHz IEs. */ rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; if (rs->rs_nrates > IEEE80211_RATE_SIZE) { if (remain < 4 + rs->rs_nrates) return ENOBUFS; } else if (remain < 2 + rs->rs_nrates) return ENOBUFS; preq->band_data[1].offset = htole16(frm - (uint8_t *)wh); pos = frm; frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); preq->band_data[1].len = htole16(frm - pos); remain -= frm - pos; if (ic->ic_flags & IEEE80211_F_VHTON) { if (remain < sizeof(struct ieee80211_ie_vhtcap)) return ENOBUFS; frm = ieee80211_add_vhtcaps(frm, ic); remain -= frm - pos; } } /* Send 11n IEs on both 2GHz and 5GHz bands. */ preq->common_data.offset = htole16(frm - (uint8_t *)wh); pos = frm; if (ic->ic_flags & IEEE80211_F_HTON) { if (remain < sizeof(struct ieee80211_ie_htcap)) return ENOBUFS; frm = ieee80211_add_htcaps(frm, ic); /* XXX add WME info? */ } preq->common_data.len = htole16(frm - pos); return 0; } int ItlIwx:: iwx_config_umac_scan(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_scan_config *scan_config; int err; size_t cmd_size; struct iwx_host_cmd hcmd = { .id = iwx_cmd_id(IWX_SCAN_CFG_CMD, IWX_LONG_GROUP, 0), .flags = 0, }; uint8_t cmdver; if (!isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_REDUCED_SCAN_CONFIG)) return iwx_config_legacy_umac_scan(sc); cmd_size = sizeof(*scan_config); scan_config = (struct iwx_scan_config *)malloc(cmd_size, 0, M_ZERO); if (scan_config == NULL) return ENOMEM; scan_config->tx_chains = htole32(iwx_fw_valid_tx_ant(sc)); scan_config->rx_chains = htole32(iwx_fw_valid_rx_ant(sc)); cmdver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_ADD_STA); if (cmdver == IWX_FW_CMD_VER_UNKNOWN || cmdver < 12) scan_config->bcast_sta_id = IWX_AUX_STA_ID; else if (cmdver == IWX_FW_CMD_VER_UNKNOWN || cmdver < 5) scan_config->bcast_sta_id = 0xFF; hcmd.data[0] = scan_config; hcmd.len[0] = cmd_size; err = iwx_send_cmd(sc, &hcmd); ::free(scan_config); return err; } int ItlIwx:: iwx_config_legacy_umac_scan(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_scan_config_v2 *scan_config; struct ieee80211com *ic = &sc->sc_ic; int err, nchan; struct ieee80211_channel *c; size_t cmd_size; struct iwx_host_cmd hcmd = { .id = iwx_cmd_id(IWX_SCAN_CFG_CMD, IWX_LONG_GROUP, 0), .flags = 0, }; static const uint32_t rates = (IWX_SCAN_CONFIG_RATE_1M | IWX_SCAN_CONFIG_RATE_2M | IWX_SCAN_CONFIG_RATE_5M | IWX_SCAN_CONFIG_RATE_11M | IWX_SCAN_CONFIG_RATE_6M | IWX_SCAN_CONFIG_RATE_9M | IWX_SCAN_CONFIG_RATE_12M | IWX_SCAN_CONFIG_RATE_18M | IWX_SCAN_CONFIG_RATE_24M | IWX_SCAN_CONFIG_RATE_36M | IWX_SCAN_CONFIG_RATE_48M | IWX_SCAN_CONFIG_RATE_54M); cmd_size = sizeof(*scan_config) + sc->sc_capa_n_scan_channels; scan_config = (struct iwx_scan_config_v2 *)malloc(cmd_size, 0, M_ZERO); if (scan_config == NULL) return ENOMEM; scan_config->tx_chains = htole32(iwx_fw_valid_tx_ant(sc)); scan_config->rx_chains = htole32(iwx_fw_valid_rx_ant(sc)); scan_config->legacy_rates = htole32(rates | IWX_SCAN_CONFIG_SUPPORTED_RATE(rates)); /* These timings correspond to iwlwifi's UNASSOC scan. */ scan_config->dwell.active = 10; scan_config->dwell.passive = 110; scan_config->dwell.fragmented = 44; scan_config->dwell.extended = 90; scan_config->out_of_channel_time[IWX_SCAN_LB_LMAC_IDX] = htole32(0); scan_config->out_of_channel_time[IWX_SCAN_HB_LMAC_IDX] = htole32(0); scan_config->suspend_time[IWX_SCAN_LB_LMAC_IDX] = htole32(0); scan_config->suspend_time[IWX_SCAN_HB_LMAC_IDX] = htole32(0); IEEE80211_ADDR_COPY(scan_config->mac_addr, sc->sc_ic.ic_myaddr); scan_config->bcast_sta_id = IWX_AUX_STA_ID; scan_config->channel_flags = 0; for (c = &ic->ic_channels[1], nchan = 0; c <= &ic->ic_channels[IEEE80211_CHAN_MAX] && nchan < sc->sc_capa_n_scan_channels; c++) { if (c->ic_flags == 0) continue; scan_config->channel_array[nchan++] = ieee80211_mhz2ieee(c->ic_freq, 0); } scan_config->flags = htole32(IWX_SCAN_CONFIG_FLAG_ACTIVATE | IWX_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | IWX_SCAN_CONFIG_FLAG_SET_TX_CHAINS | IWX_SCAN_CONFIG_FLAG_SET_RX_CHAINS | IWX_SCAN_CONFIG_FLAG_SET_AUX_STA_ID | IWX_SCAN_CONFIG_FLAG_SET_ALL_TIMES | IWX_SCAN_CONFIG_FLAG_SET_LEGACY_RATES | IWX_SCAN_CONFIG_FLAG_SET_MAC_ADDR | IWX_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| IWX_SCAN_CONFIG_N_CHANNELS(nchan) | IWX_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED); scan_config->channel_flags = IWX_CHANNEL_FLAG_EBS | IWX_CHANNEL_FLAG_ACCURATE_EBS | IWX_CHANNEL_FLAG_EBS_ADD | IWX_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; hcmd.data[0] = scan_config; hcmd.len[0] = cmd_size; err = iwx_send_cmd(sc, &hcmd); ::free(scan_config); return err; } int ItlIwx:: iwx_umac_scan_size(struct iwx_softc *sc) { int base_size = IWX_SCAN_REQ_UMAC_SIZE_V1; int tail_size; uint8_t scan_ver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_SCAN_REQ_UMAC); if (scan_ver == 12) return sizeof(iwx_scan_req_umac_v12); else if (scan_ver == 14) return sizeof(iwx_scan_req_umac_v14); if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) base_size = IWX_SCAN_REQ_UMAC_SIZE_V8; else if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL)) base_size = IWX_SCAN_REQ_UMAC_SIZE_V7; else base_size = IWX_SCAN_REQ_UMAC_SIZE_V6; if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_SCAN_EXT_CHAN_VER)) tail_size = sizeof(struct iwx_scan_req_umac_tail_v2); else tail_size = sizeof(struct iwx_scan_req_umac_tail_v1); return base_size + sizeof(struct iwx_scan_channel_cfg_umac) * sc->sc_capa_n_scan_channels + tail_size; } struct iwx_scan_umac_chan_param *ItlIwx:: iwx_get_scan_req_umac_chan_param(struct iwx_softc *sc, struct iwx_scan_req_umac *req) { if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) return &req->v8.channel; if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL)) return &req->v7.channel; return &req->v6.channel; } void *ItlIwx:: iwx_get_scan_req_umac_data(struct iwx_softc *sc, struct iwx_scan_req_umac *req) { if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) return (void *)&req->v8.data; if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL)) return (void *)&req->v7.data; return (void *)&req->v6.data; } #define IWL_SCAN_DWELL_ACTIVE 10 #define IWL_SCAN_DWELL_PASSIVE 110 #define IWL_SCAN_DWELL_FRAGMENTED 44 #define IWL_SCAN_DWELL_EXTENDED 90 #define IWL_SCAN_NUM_OF_FRAGS 3 #define IWL_SCAN_LAST_2_4_CHN 14 /* adaptive dwell max budget time [TU] for full scan */ #define IWX_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300 /* adaptive dwell max budget time [TU] for directed scan */ #define IWX_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN 100 /* adaptive dwell default high band APs number */ #define IWX_SCAN_ADWELL_DEFAULT_HB_N_APS 8 /* adaptive dwell default low band APs number */ #define IWX_SCAN_ADWELL_DEFAULT_LB_N_APS 2 /* adaptive dwell default APs number in social channels (1, 6, 11) */ #define IWX_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 10 /* number of scan channels */ #define IWX_SCAN_NUM_CHANNELS 112 /* adaptive dwell number of APs override mask for p2p friendly GO */ #define IWX_SCAN_ADWELL_N_APS_GO_FRIENDLY_BIT (1 << 20) /* adaptive dwell number of APs override mask for social channels */ #define IWX_SCAN_ADWELL_N_APS_SOCIAL_CHS_BIT (1 << 21) /* adaptive dwell number of APs override for p2p friendly GO channels */ #define IWX_SCAN_ADWELL_N_APS_GO_FRIENDLY 10 /* adaptive dwell number of APs override for social channels */ #define IWX_SCAN_ADWELL_N_APS_SOCIAL_CHS 2 /* minimal number of 2GHz and 5GHz channels in the regular scan request */ #define IWX_MVM_6GHZ_PASSIVE_SCAN_MIN_CHANS 4 int ItlIwx:: iwx_umac_scan(struct iwx_softc *sc, int bgscan) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwx_host_cmd hcmd = { .id = iwx_cmd_id(IWX_SCAN_REQ_UMAC, IWX_LONG_GROUP, 0), .len = { 0, }, .data = { NULL, }, .flags = 0, }; struct iwx_scan_req_umac *req; void *cmd_data, *tail_data; struct iwx_scan_req_umac_tail_v2 *tail; struct iwx_scan_req_umac_tail_v1 *tailv1; struct iwx_scan_umac_chan_param *chanparam; size_t req_len; int err, async = bgscan; const uint32_t timeout = bgscan ? htole32(120) : htole32(0); uint8_t scan_ver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_SCAN_REQ_UMAC); if (scan_ver == 12) return iwx_umac_scan_v12(sc, bgscan); else if (scan_ver == 14) return iwx_umac_scan_v14(sc, bgscan); req_len = iwx_umac_scan_size(sc); if ((req_len < IWX_SCAN_REQ_UMAC_SIZE_V1 + sizeof(struct iwx_scan_req_umac_tail_v1)) || req_len > IWX_MAX_CMD_PAYLOAD_SIZE) return ERANGE; req = (struct iwx_scan_req_umac *)malloc(req_len, 0, (async ? M_NOWAIT : M_WAITOK) | M_ZERO); if (req == NULL) return ENOMEM; hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; hcmd.flags |= async ? IWX_CMD_ASYNC : 0; if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL)) { req->v7.adwell_default_n_aps_social = IWX_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; req->v7.adwell_default_n_aps = IWX_SCAN_ADWELL_DEFAULT_LB_N_APS; if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADWELL_HB_DEF_N_AP)) req->v9.adwell_default_hb_n_aps = IWX_SCAN_ADWELL_DEFAULT_HB_N_APS; if (ic->ic_des_esslen != 0 && !bgscan) req->v7.adwell_max_budget = htole16(IWX_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); else req->v7.adwell_max_budget = htole16(IWX_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); req->v7.scan_priority = htole32(IWX_SCAN_PRIORITY_EXT_6); req->v7.max_out_time[IWX_SCAN_LB_LMAC_IDX] = timeout; req->v7.suspend_time[IWX_SCAN_LB_LMAC_IDX] = timeout; if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_CDB_SUPPORT)) { req->v7.max_out_time[IWX_SCAN_HB_LMAC_IDX] = timeout; req->v7.suspend_time[IWX_SCAN_HB_LMAC_IDX] = timeout; } if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) { req->v8.active_dwell[IWX_SCAN_LB_LMAC_IDX] = IWL_SCAN_DWELL_ACTIVE; req->v8.passive_dwell[IWX_SCAN_LB_LMAC_IDX] = IWL_SCAN_DWELL_PASSIVE; if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_CDB_SUPPORT)) { req->v8.active_dwell[IWX_SCAN_HB_LMAC_IDX] = IWL_SCAN_DWELL_ACTIVE; req->v8.passive_dwell[IWX_SCAN_HB_LMAC_IDX] = IWL_SCAN_DWELL_PASSIVE; } } else { req->v7.active_dwell = IWL_SCAN_DWELL_ACTIVE; req->v7.passive_dwell = IWL_SCAN_DWELL_PASSIVE; req->v7.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; } } else { /* These timings correspond to iwlwifi's UNASSOC scan. */ req->v1.active_dwell = IWL_SCAN_DWELL_ACTIVE; req->v1.passive_dwell = IWL_SCAN_DWELL_PASSIVE; req->v1.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; req->v1.extended_dwell = IWL_SCAN_DWELL_EXTENDED; if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_CDB_SUPPORT)) { req->v6.max_out_time[IWX_SCAN_HB_LMAC_IDX] = timeout; req->v6.suspend_time[IWX_SCAN_HB_LMAC_IDX] = timeout; } req->v6.scan_priority = htole32(IWX_SCAN_PRIORITY_EXT_6); req->v6.max_out_time[IWX_SCAN_LB_LMAC_IDX] = timeout; req->v6.suspend_time[IWX_SCAN_LB_LMAC_IDX] = timeout; } req->ooc_priority = htole32(IWX_SCAN_PRIORITY_EXT_6); cmd_data = iwx_get_scan_req_umac_data(sc, req); chanparam = iwx_get_scan_req_umac_chan_param(sc, req); chanparam->count = iwx_umac_scan_fill_channels(sc, (struct iwx_scan_channel_cfg_umac *)cmd_data, ic->ic_des_esslen != 0, bgscan); chanparam->flags = 0; tail_data = (uint8_t*)cmd_data + sizeof(struct iwx_scan_channel_cfg_umac) * sc->sc_capa_n_scan_channels; tail = (struct iwx_scan_req_umac_tail_v2 *)tail_data; /* tail v1 layout differs in preq and direct_scan member fields. */ tailv1 = (struct iwx_scan_req_umac_tail_v1 *)tail_data; req->general_flags = htole32(IWX_UMAC_SCAN_GEN_FLAGS_PASS_ALL | IWX_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE); if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL_V2)) { req->v8.general_flags2 = IWX_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER; } /* Check if we're doing an active directed scan. */ if (ic->ic_des_esslen != 0 && !bgscan) { if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_SCAN_EXT_CHAN_VER)) { tail->direct_scan[0].id = IEEE80211_ELEMID_SSID; tail->direct_scan[0].len = ic->ic_des_esslen; memcpy(tail->direct_scan[0].ssid, ic->ic_des_essid, ic->ic_des_esslen); } else { tailv1->direct_scan[0].id = IEEE80211_ELEMID_SSID; tailv1->direct_scan[0].len = ic->ic_des_esslen; memcpy(tailv1->direct_scan[0].ssid, ic->ic_des_essid, ic->ic_des_esslen); } req->general_flags |= htole32(IWX_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT); } else req->general_flags |= htole32(IWX_UMAC_SCAN_GEN_FLAGS_PASSIVE); if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT) && isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)) req->general_flags |= htole32(IWX_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED); if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_ADAPTIVE_DWELL)) { req->general_flags |= htole32(IWX_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL); } else { req->general_flags |= htole32(IWX_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL); } if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_SCAN_EXT_CHAN_VER)) err = iwx_fill_probe_req(sc, &tail->preq); else err = iwx_fill_probe_req_v1(sc, &tailv1->preq); if (err) { ::free(req); return err; } /* Specify the scan plan: We'll do one iteration. */ tail->schedule[0].interval = 0; tail->schedule[0].iter_count = 1; err = iwx_send_cmd(sc, &hcmd); ::free(req); return err; } int ItlIwx:: iwx_umac_scan_v12(struct iwx_softc *sc, int bgscan) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; int err = 0, async = bgscan; struct iwx_scan_req_umac_v12 *req; size_t req_len; uint16_t gen_flags = 0; const uint32_t timeout = bgscan ? htole32(120) : htole32(0); struct iwx_scan_general_params_v10 *general_params; struct iwx_scan_channel_params_v4 *cp; struct iwx_host_cmd hcmd = { .id = iwx_cmd_id(IWX_SCAN_REQ_UMAC, IWX_LONG_GROUP, 0), .len = { 0, }, .data = { NULL, }, .flags = 0, }; req_len = iwx_umac_scan_size(sc); req = (struct iwx_scan_req_umac_v12 *)malloc(req_len, 0, (async ? M_NOWAIT : M_WAITOK) | M_ZERO); if (req == NULL) return ENOMEM; hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; hcmd.flags |= async ? IWX_CMD_ASYNC : 0; general_params = &req->scan_params.general_params; req->ooc_priority = htole32(IWX_SCAN_PRIORITY_EXT_6); if (ic->ic_des_esslen == 0 || bgscan) gen_flags |= IWX_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE; gen_flags |= IWX_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL | IWX_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL; req->scan_params.general_params.flags = gen_flags; general_params->adwell_default_social_chn = IWX_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; general_params->adwell_default_2g = IWX_SCAN_ADWELL_DEFAULT_LB_N_APS; general_params->adwell_default_5g = IWX_SCAN_ADWELL_DEFAULT_HB_N_APS; if (ic->ic_des_esslen != 0 && !bgscan) general_params->adwell_max_budget = cpu_to_le16(IWX_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); else general_params->adwell_max_budget = cpu_to_le16(IWX_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); general_params->scan_priority = htole32(IWX_SCAN_PRIORITY_EXT_6); general_params->max_out_of_time[IWX_SCAN_LB_LMAC_IDX] = timeout; general_params->suspend_time[IWX_SCAN_LB_LMAC_IDX] = timeout; general_params->max_out_of_time[IWX_SCAN_HB_LMAC_IDX] = timeout; general_params->suspend_time[IWX_SCAN_HB_LMAC_IDX] = timeout; general_params->active_dwell[IWX_SCAN_LB_LMAC_IDX] = IWL_SCAN_DWELL_ACTIVE; general_params->passive_dwell[IWX_SCAN_LB_LMAC_IDX] = IWL_SCAN_DWELL_PASSIVE; general_params->active_dwell[IWX_SCAN_HB_LMAC_IDX] = IWL_SCAN_DWELL_ACTIVE; general_params->passive_dwell[IWX_SCAN_HB_LMAC_IDX] = IWL_SCAN_DWELL_PASSIVE; /* Specify the scan plan: We'll do one iteration. */ req->scan_params.periodic_params.schedule[0].interval = 0; req->scan_params.periodic_params.schedule[0].iter_count = 1; err = iwx_fill_probe_req(sc, &req->scan_params.probe_params.preq); if (err) return err; if (ic->ic_des_esslen != 0 && !bgscan) { req->scan_params.probe_params.ssid_num = 1; req->scan_params.probe_params.direct_scan[0].id = IEEE80211_ELEMID_SSID; req->scan_params.probe_params.direct_scan[0].len = ic->ic_des_esslen; memcpy(req->scan_params.probe_params.direct_scan[0].ssid, ic->ic_des_essid, ic->ic_des_esslen); } else req->scan_params.probe_params.ssid_num = 0; cp = &req->scan_params.channel_params; cp->flags = IWX_SCAN_CHANNEL_FLAG_ENABLE_CHAN_ORDER; cp->count = iwx_umac_scan_fill_channels(sc, (struct iwx_scan_channel_cfg_umac *)cp->channel_config, ic->ic_des_esslen != 0, bgscan); cp->num_of_aps_override = IWX_SCAN_ADWELL_N_APS_GO_FRIENDLY; err = iwx_send_cmd(sc, &hcmd); ::free(req); return err; } int ItlIwx:: iwx_umac_scan_v14(struct iwx_softc *sc, int bgscan) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; int err = 0, async = bgscan; struct iwx_scan_req_umac_v14 *req; size_t req_len; uint16_t gen_flags = 0; struct iwx_scan_general_params_v10 *general_params; struct iwx_scan_channel_params_v6 *cp; const uint32_t timeout = bgscan ? htole32(120) : htole32(0); struct iwx_host_cmd hcmd = { .id = iwx_cmd_id(IWX_SCAN_REQ_UMAC, IWX_LONG_GROUP, 0), .len = { 0, }, .data = { NULL, }, .flags = 0, }; req_len = iwx_umac_scan_size(sc); req = (struct iwx_scan_req_umac_v14 *)malloc(req_len, 0, (async ? M_NOWAIT : M_WAITOK) | M_ZERO); if (req == NULL) return ENOMEM; hcmd.len[0] = (uint16_t)req_len; hcmd.data[0] = (void *)req; hcmd.flags |= async ? IWX_CMD_ASYNC : 0; general_params = &req->scan_params.general_params; req->ooc_priority = htole32(IWX_SCAN_PRIORITY_EXT_6); if (ic->ic_des_esslen == 0 || bgscan) gen_flags |= IWX_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE; gen_flags |= IWX_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL | IWX_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL; req->scan_params.general_params.flags = gen_flags; general_params->adwell_default_social_chn = IWX_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; general_params->adwell_default_2g = IWX_SCAN_ADWELL_DEFAULT_LB_N_APS; general_params->adwell_default_5g = IWX_SCAN_ADWELL_DEFAULT_HB_N_APS; if (ic->ic_des_esslen != 0 && !bgscan) general_params->adwell_max_budget = cpu_to_le16(IWX_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); else general_params->adwell_max_budget = cpu_to_le16(IWX_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); general_params->scan_priority = htole32(IWX_SCAN_PRIORITY_EXT_6); general_params->max_out_of_time[IWX_SCAN_LB_LMAC_IDX] = timeout; general_params->suspend_time[IWX_SCAN_LB_LMAC_IDX] = timeout; general_params->max_out_of_time[IWX_SCAN_HB_LMAC_IDX] = timeout; general_params->suspend_time[IWX_SCAN_HB_LMAC_IDX] = timeout; general_params->active_dwell[IWX_SCAN_LB_LMAC_IDX] = IWL_SCAN_DWELL_ACTIVE; general_params->passive_dwell[IWX_SCAN_LB_LMAC_IDX] = IWL_SCAN_DWELL_PASSIVE; general_params->active_dwell[IWX_SCAN_HB_LMAC_IDX] = IWL_SCAN_DWELL_ACTIVE; general_params->passive_dwell[IWX_SCAN_HB_LMAC_IDX] = IWL_SCAN_DWELL_PASSIVE; /* Specify the scan plan: We'll do one iteration. */ req->scan_params.periodic_params.schedule[0].interval = 0; req->scan_params.periodic_params.schedule[0].iter_count = 1; err = iwx_fill_probe_req(sc, &req->scan_params.probe_params.preq); if (err) return err; if (ic->ic_des_esslen != 0 && !bgscan) { req->scan_params.probe_params.direct_scan[0].id = IEEE80211_ELEMID_SSID; req->scan_params.probe_params.direct_scan[0].len = ic->ic_des_esslen; memcpy(req->scan_params.probe_params.direct_scan[0].ssid, ic->ic_des_essid, ic->ic_des_esslen); } cp = &req->scan_params.channel_params; cp->flags = IWX_SCAN_CHANNEL_FLAG_ENABLE_CHAN_ORDER; cp->count = iwx_umac_scan_fill_channels(sc, (struct iwx_scan_channel_cfg_umac *)cp->channel_config, ic->ic_des_esslen != 0, bgscan); cp->n_aps_override[0] = IWX_SCAN_ADWELL_N_APS_GO_FRIENDLY; cp->n_aps_override[1] = IWX_SCAN_ADWELL_N_APS_SOCIAL_CHS; err = iwx_send_cmd(sc, &hcmd); ::free(req); return err; } void ItlIwx:: iwx_mcc_update(struct iwx_softc *sc, struct iwx_mcc_chub_notif *notif) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); snprintf(sc->sc_fw_mcc, sizeof(sc->sc_fw_mcc), "%c%c", (le16toh(notif->mcc) & 0xff00) >> 8, le16toh(notif->mcc) & 0xff); if (sc->sc_fw_mcc_int != notif->mcc && sc->sc_ic.ic_event_handler) { (*sc->sc_ic.ic_event_handler)(&sc->sc_ic, IEEE80211_EVT_COUNTRY_CODE_UPDATE, NULL); } sc->sc_fw_mcc_int = notif->mcc; if (ifp->if_flags & IFF_DEBUG) { DPRINTFN(3, ("%s: firmware has detected regulatory domain '%s' " "(0x%x)\n", DEVNAME(sc), sc->sc_fw_mcc, le16toh(notif->mcc))); } /* TODO: Schedule a task to send MCC_UPDATE_CMD? */ } uint8_t ItlIwx:: iwx_ridx2rate(struct ieee80211_rateset *rs, int ridx) { int i; uint8_t rval; for (i = 0; i < rs->rs_nrates; i++) { rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL); if (rval == iwx_rates[ridx].rate) return rs->rs_rates[i]; } return 0; } int ItlIwx:: iwx_rval2ridx(int rval) { int ridx; for (ridx = 0; ridx < nitems(iwx_rates); ridx++) { if (iwx_rates[ridx].plcp == IWX_RATE_INVM_PLCP) continue; if (rval == iwx_rates[ridx].rate) break; } return ridx; } int ItlIwx:: iwx_rate2idx(int rate) { const struct ieee80211_rateset *rs = &ieee80211_std_rateset_11a; int idx; for (idx = 0; idx < rs->rs_nrates; idx++) { if (rs->rs_rates[idx] == rate) return idx; } return 0; } void ItlIwx:: iwx_ack_rates(struct iwx_softc *sc, struct iwx_node *in, int *cck_rates, int *ofdm_rates) { struct ieee80211_node *ni = &in->in_ni; struct ieee80211_rateset *rs = &ni->ni_rates; int lowest_present_ofdm = -1; int lowest_present_cck = -1; uint8_t cck = 0; uint8_t ofdm = 0; int i; if (ni->ni_chan == IEEE80211_CHAN_ANYC || IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) { for (i = IWX_FIRST_CCK_RATE; i < IWX_FIRST_OFDM_RATE; i++) { if ((iwx_ridx2rate(rs, i) & IEEE80211_RATE_BASIC) == 0) continue; cck |= (1 << i); if (lowest_present_cck == -1 || lowest_present_cck > i) lowest_present_cck = i; } } for (i = IWX_FIRST_OFDM_RATE; i <= IWX_LAST_NON_HT_RATE; i++) { if ((iwx_ridx2rate(rs, i) & IEEE80211_RATE_BASIC) == 0) continue; ofdm |= (1 << (i - IWX_FIRST_OFDM_RATE)); if (lowest_present_ofdm == -1 || lowest_present_ofdm > i) lowest_present_ofdm = i; } /* * Now we've got the basic rates as bitmaps in the ofdm and cck * variables. This isn't sufficient though, as there might not * be all the right rates in the bitmap. E.g. if the only basic * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps * and 6 Mbps because the 802.11-2007 standard says in 9.6: * * [...] a STA responding to a received frame shall transmit * its Control Response frame [...] at the highest rate in the * BSSBasicRateSet parameter that is less than or equal to the * rate of the immediately previous frame in the frame exchange * sequence ([...]) and that is of the same modulation class * ([...]) as the received frame. If no rate contained in the * BSSBasicRateSet parameter meets these conditions, then the * control frame sent in response to a received frame shall be * transmitted at the highest mandatory rate of the PHY that is * less than or equal to the rate of the received frame, and * that is of the same modulation class as the received frame. * * As a consequence, we need to add all mandatory rates that are * lower than all of the basic rates to these bitmaps. */ if (IWX_RATE_24M_INDEX < lowest_present_ofdm) ofdm |= IWX_RATE_BIT_MSK(24) >> IWX_FIRST_OFDM_RATE; if (IWX_RATE_12M_INDEX < lowest_present_ofdm) ofdm |= IWX_RATE_BIT_MSK(12) >> IWX_FIRST_OFDM_RATE; /* 6M already there or needed so always add */ ofdm |= IWX_RATE_BIT_MSK(6) >> IWX_FIRST_OFDM_RATE; /* * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP. * Note, however: * - if no CCK rates are basic, it must be ERP since there must * be some basic rates at all, so they're OFDM => ERP PHY * (or we're in 5 GHz, and the cck bitmap will never be used) * - if 11M is a basic rate, it must be ERP as well, so add 5.5M * - if 5.5M is basic, 1M and 2M are mandatory * - if 2M is basic, 1M is mandatory * - if 1M is basic, that's the only valid ACK rate. * As a consequence, it's not as complicated as it sounds, just add * any lower rates to the ACK rate bitmap. */ if (IWX_RATE_11M_INDEX < lowest_present_cck) cck |= IWX_RATE_BIT_MSK(11) >> IWX_FIRST_CCK_RATE; if (IWX_RATE_5M_INDEX < lowest_present_cck) cck |= IWX_RATE_BIT_MSK(5) >> IWX_FIRST_CCK_RATE; if (IWX_RATE_2M_INDEX < lowest_present_cck) cck |= IWX_RATE_BIT_MSK(2) >> IWX_FIRST_CCK_RATE; /* 1M already there or needed so always add */ cck |= IWX_RATE_BIT_MSK(1) >> IWX_FIRST_CCK_RATE; *cck_rates = cck; *ofdm_rates = ofdm; } static uint8_t iwx_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_edca_ac ac) { static const uint8_t mac80211_ac_to_ucode_ac[] = { IWX_AC_BE, IWX_AC_BK, IWX_AC_VI, IWX_AC_VO }; return mac80211_ac_to_ucode_ac[ac]; } void ItlIwx:: iwx_mac_ctxt_cmd_common(struct iwx_softc *sc, struct iwx_node *in, struct iwx_mac_ctx_cmd *cmd, uint32_t action) { #define IWX_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; int cck_ack_rates, ofdm_ack_rates; int i; cmd->id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color)); cmd->action = htole32(action); if (action == IWX_FW_CTXT_ACTION_REMOVE) return; if (ic->ic_opmode == IEEE80211_M_MONITOR) cmd->mac_type = htole32(IWX_FW_MAC_TYPE_LISTENER); else if (ic->ic_opmode == IEEE80211_M_STA) cmd->mac_type = htole32(IWX_FW_MAC_TYPE_BSS_STA); else panic("unsupported operating mode %d\n", ic->ic_opmode); cmd->tsf_id = htole32(IWX_TSF_ID_A); IEEE80211_ADDR_COPY(cmd->node_addr, ic->ic_myaddr); if (ic->ic_opmode == IEEE80211_M_MONITOR) { IEEE80211_ADDR_COPY(cmd->bssid_addr, etherbroadcastaddr); return; } IEEE80211_ADDR_COPY(cmd->bssid_addr, in->in_macaddr); iwx_ack_rates(sc, in, &cck_ack_rates, &ofdm_ack_rates); cmd->cck_rates = htole32(cck_ack_rates); cmd->ofdm_rates = htole32(ofdm_ack_rates); cmd->cck_short_preamble = htole32((ic->ic_flags & IEEE80211_F_SHPREAMBLE) ? IWX_MAC_FLG_SHORT_PREAMBLE : 0); cmd->short_slot = htole32((ic->ic_flags & IEEE80211_F_SHSLOT) ? IWX_MAC_FLG_SHORT_SLOT : 0); for (i = 0; i < EDCA_NUM_AC; i++) { struct ieee80211_edca_ac_params *ac = &ic->ic_edca_ac[i]; int txf = iwx_ac_to_tx_fifo[i]; uint8_t ucode_ac = iwx_mvm_mac80211_ac_to_ucode_ac((enum ieee80211_edca_ac)i); cmd->ac[ucode_ac].cw_min = htole16(IWX_EXP2(ac->ac_ecwmin)); cmd->ac[ucode_ac].cw_max = htole16(IWX_EXP2(ac->ac_ecwmax)); cmd->ac[ucode_ac].aifsn = ac->ac_aifsn; cmd->ac[ucode_ac].fifos_mask = (1 << txf); cmd->ac[ucode_ac].edca_txop = htole16(ac->ac_txoplimit * 32); } if (ni->ni_flags & IEEE80211_NODE_QOS) cmd->qos_flags |= htole32(IWX_MAC_QOS_FLG_UPDATE_EDCA); if (ni->ni_flags & IEEE80211_NODE_HT) { enum ieee80211_htprot htprot = (enum ieee80211_htprot)(ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK); /* The fw does not distinguish between ht and fat */ uint32_t ht_flag = IWX_MAC_PROT_FLG_HT_PROT | IWX_MAC_PROT_FLG_FAT_PROT; /* * See section 9.23.3.1 of IEEE 80211-2012. * Nongreenfield HT STAs Present is not supported. */ switch (htprot) { case IEEE80211_HTPROT_NONE: break; case IEEE80211_HTPROT_NONMEMBER: case IEEE80211_HTPROT_NONHT_MIXED: cmd->protection_flags = htole32(ht_flag); break; case IEEE80211_HTPROT_20MHZ: /* Protect when channel wider than 20MHz */ if (ni->ni_chw > IEEE80211_CHAN_WIDTH_20) cmd->protection_flags = htole32(ht_flag); break; default: XYLog("Illegal protection mode %d\n", htprot); break; } cmd->qos_flags |= htole32(IWX_MAC_QOS_FLG_TGN); } if (ic->ic_flags & IEEE80211_F_USEPROT) cmd->protection_flags |= htole32(IWX_MAC_PROT_FLG_TGG_PROTECT); cmd->filter_flags = htole32(IWX_MAC_FILTER_ACCEPT_GRP); #undef IWX_EXP2 } void ItlIwx:: iwx_mac_ctxt_cmd_fill_sta(struct iwx_softc *sc, struct iwx_node *in, struct iwx_mac_data_sta *sta, int assoc) { struct ieee80211_node *ni = &in->in_ni; uint32_t dtim_off; uint64_t tsf; dtim_off = ni->ni_dtimcount * ni->ni_intval * IEEE80211_DUR_TU; memcpy(&tsf, ni->ni_tstamp, sizeof(tsf)); tsf = letoh64(tsf); sta->is_assoc = htole32(assoc); sta->dtim_time = htole32(ni->ni_rstamp + dtim_off); sta->dtim_tsf = htole64(tsf + dtim_off); sta->bi = htole32(ni->ni_intval); sta->bi_reciprocal = htole32(iwx_reciprocal(ni->ni_intval)); sta->dtim_interval = htole32(ni->ni_intval * ni->ni_dtimperiod); sta->dtim_reciprocal = htole32(iwx_reciprocal(sta->dtim_interval)); sta->listen_interval = htole32(10); sta->assoc_id = htole32(ni->ni_associd); sta->assoc_beacon_arrive_time = htole32(ni->ni_rstamp); } int ItlIwx:: iwx_mac_ctxt_cmd(struct iwx_softc *sc, struct iwx_node *in, uint32_t action, int assoc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = &in->in_ni; struct iwx_mac_ctx_cmd cmd; int active = (sc->sc_flags & IWX_FLAG_MAC_ACTIVE); if (action == IWX_FW_CTXT_ACTION_ADD && active) { XYLog("MAC already added\n"); return 0; } if (action == IWX_FW_CTXT_ACTION_REMOVE && !active) { XYLog("MAC already removed\n"); return 0; } memset(&cmd, 0, sizeof(cmd)); iwx_mac_ctxt_cmd_common(sc, in, &cmd, action); if (action == IWX_FW_CTXT_ACTION_REMOVE) { return iwx_send_cmd_pdu(sc, IWX_MAC_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } if (ic->ic_opmode == IEEE80211_M_MONITOR) { cmd.filter_flags |= htole32(IWX_MAC_FILTER_IN_PROMISC | IWX_MAC_FILTER_IN_CONTROL_AND_MGMT | IWX_MAC_FILTER_ACCEPT_GRP | IWX_MAC_FILTER_IN_BEACON | IWX_MAC_FILTER_IN_PROBE_REQUEST | IWX_MAC_FILTER_IN_CRC32); } else if (!assoc || !ni->ni_associd || !ni->ni_dtimperiod) /* * Allow beacons to pass through as long as we are not * associated or we do not have dtim period information. */ cmd.filter_flags |= htole32(IWX_MAC_FILTER_IN_BEACON); else iwx_mac_ctxt_cmd_fill_sta(sc, in, &cmd.sta, assoc); if (ni->ni_flags & IEEE80211_NODE_HE) { cmd.filter_flags |= htole32(IWX_MAC_FILTER_IN_11AX); } return iwx_send_cmd_pdu(sc, IWX_MAC_CONTEXT_CMD, 0, sizeof(cmd), &cmd); } int ItlIwx:: iwx_clear_statistics(struct iwx_softc *sc) { struct iwx_statistics_cmd scmd = { .flags = htole32(IWX_STATISTICS_FLG_CLEAR) }; struct iwx_host_cmd cmd = { .id = IWX_STATISTICS_CMD, .len[0] = sizeof(scmd), .data[0] = &scmd, .flags = IWX_CMD_WANT_RESP, .resp_pkt_len = sizeof(struct iwx_notif_statistics), }; int err; err = iwx_send_cmd(sc, &cmd); if (err) return err; iwx_free_resp(sc, &cmd); return 0; } int ItlIwx:: iwx_update_quotas(struct iwx_softc *sc, struct iwx_node *in, int running) { struct iwx_time_quota_cmd cmd; int i, idx, num_active_macs, quota, quota_rem; int colors[IWX_MAX_BINDINGS] = { -1, -1, -1, -1, }; int n_ifs[IWX_MAX_BINDINGS] = {0, }; uint16_t id; memset(&cmd, 0, sizeof(cmd)); /* currently, PHY ID == binding ID */ if (in && in->in_phyctxt) { id = in->in_phyctxt->id; KASSERT(id < IWX_MAX_BINDINGS, "id < IWX_MAX_BINDINGS"); colors[id] = in->in_phyctxt->color; if (running) n_ifs[id] = 1; } /* * The FW's scheduling session consists of * IWX_MAX_QUOTA fragments. Divide these fragments * equally between all the bindings that require quota */ num_active_macs = 0; for (i = 0; i < IWX_MAX_BINDINGS; i++) { cmd.quotas[i].id_and_color = htole32(IWX_FW_CTXT_INVALID); num_active_macs += n_ifs[i]; } quota = 0; quota_rem = 0; if (num_active_macs) { quota = IWX_MAX_QUOTA / num_active_macs; quota_rem = IWX_MAX_QUOTA % num_active_macs; } for (idx = 0, i = 0; i < IWX_MAX_BINDINGS; i++) { if (colors[i] < 0) continue; cmd.quotas[idx].id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(i, colors[i])); if (n_ifs[i] <= 0) { cmd.quotas[idx].quota = htole32(0); cmd.quotas[idx].max_duration = htole32(0); } else { cmd.quotas[idx].quota = htole32(quota * n_ifs[i]); cmd.quotas[idx].max_duration = htole32(0); } idx++; } /* Give the remainder of the session to the first binding */ cmd.quotas[0].quota = htole32(le32toh(cmd.quotas[0].quota) + quota_rem); return iwx_send_cmd_pdu(sc, IWX_TIME_QUOTA_CMD, 0, sizeof(cmd), &cmd); } void ItlIwx:: iwx_add_task(struct iwx_softc *sc, struct taskq *taskq, struct task *task) { XYLog("%s %s\n", __FUNCTION__, task->name); int s = splnet(); if (sc->sc_flags & IWX_FLAG_SHUTDOWN) { XYLog("%s %s sc->sc_flags & IWX_FLAG_SHUTDOWN\n", __FUNCTION__, task->name); splx(s); return; } // refcnt_take(&sc->task_refs); if (!task_add(taskq, task)) { // refcnt_rele_wake(&sc->task_refs); } splx(s); } void ItlIwx:: iwx_del_task(struct iwx_softc *sc, struct taskq *taskq, struct task *task) { XYLog("%s %s\n", __FUNCTION__, task->name); if (task_del(taskq, task)) { // refcnt_rele(&sc->task_refs); } } int ItlIwx:: iwx_scan(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); int err; if (sc->sc_flags & IWX_FLAG_BGSCAN) { err = iwx_scan_abort(sc); if (err) { XYLog("%s: could not abort background scan\n", DEVNAME(sc)); return err; } } err = iwx_umac_scan(sc, 0); if (err) { XYLog("%s: could not initiate scan\n", DEVNAME(sc)); return err; } /* * The current mode might have been fixed during association. * Ensure all channels get scanned. */ if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); sc->sc_flags |= IWX_FLAG_SCANNING; if (ifp->if_flags & IFF_DEBUG) XYLog("%s: %s -> %s\n", ifp->if_xname, ieee80211_state_name[ic->ic_state], ieee80211_state_name[IEEE80211_S_SCAN]); if ((sc->sc_flags & IWX_FLAG_BGSCAN) == 0) { ieee80211_set_link_state(ic, LINK_STATE_DOWN); ieee80211_node_cleanup(ic, ic->ic_bss); } ic->ic_state = IEEE80211_S_SCAN; wakeupOn(&ic->ic_state); /* wake iwx_init() */ return 0; } int ItlIwx:: iwx_bgscan(struct ieee80211com *ic) { XYLog("%s\n", __FUNCTION__); struct iwx_softc *sc = (struct iwx_softc *)IC2IFP(ic)->if_softc; ItlIwx *that = container_of(sc, ItlIwx, com); int err; if (sc->sc_flags & IWX_FLAG_SCANNING) return 0; err = that->iwx_umac_scan(sc, 1); if (err) { XYLog("%s: could not initiate scan\n", DEVNAME(sc)); return err; } sc->sc_flags |= IWX_FLAG_BGSCAN; return 0; } int ItlIwx:: iwx_umac_scan_abort(struct iwx_softc *sc) { struct iwx_umac_scan_abort cmd = { 0 }; return iwx_send_cmd_pdu(sc, IWX_WIDE_ID(IWX_LONG_GROUP, IWX_SCAN_ABORT_UMAC), 0, sizeof(cmd), &cmd); } int ItlIwx:: iwx_scan_abort(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); int err; err = iwx_umac_scan_abort(sc); if (err == 0) sc->sc_flags &= ~(IWX_FLAG_SCANNING | IWX_FLAG_BGSCAN); return err; } int ItlIwx:: iwx_enable_mgmt_queue(struct iwx_softc *sc) { int err; int cmdver; cmdver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_ADD_STA); if (cmdver != IWX_FW_CMD_VER_UNKNOWN && cmdver >= 12) sc->first_data_qid = IWX_QID_MGMT - 1; else sc->first_data_qid = IWX_QID_MGMT; err = iwx_enable_txq(sc, IWX_STATION_ID, sc->first_data_qid, IWX_MGMT_TID, sc->txq[sc->first_data_qid].ring_count); if (err) { XYLog("%s: could not enable MGMT Tx queue %d (error %d)\n", DEVNAME(sc), sc->first_data_qid, err); return err; } return 0; } int ItlIwx:: iwx_rs_rval2idx(uint8_t rval) { /* Firmware expects indices which match our 11g rate set. */ const struct ieee80211_rateset *rs = &ieee80211_std_rateset_11g; int i; for (i = 0; i < rs->rs_nrates; i++) { if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rval) return i; } return -1; } uint16_t ItlIwx:: iwx_rs_ht_rates(struct iwx_softc *sc, struct ieee80211_node *ni, int rsidx) { struct ieee80211com *ic = &sc->sc_ic; const struct ieee80211_ht_rateset *rs; uint16_t htrates = 0; int mcs; rs = &ieee80211_std_ratesets_11n[rsidx]; for (mcs = rs->min_mcs; mcs <= rs->max_mcs; mcs++) { if (!isset(ni->ni_rxmcs, mcs) || !isset(ic->ic_sup_mcs, mcs)) continue; htrates |= (1 << (mcs - rs->min_mcs)); } return htrates; } static uint8_t iwx_rs_fw_bw_from_sta_bw(uint8_t bw) { uint8_t fw_bw; switch (bw) { case IEEE80211_CHAN_WIDTH_20: fw_bw = IWX_TLC_MNG_CH_WIDTH_20MHZ; break; case IEEE80211_CHAN_WIDTH_40: fw_bw = IWX_TLC_MNG_CH_WIDTH_40MHZ; break; case IEEE80211_CHAN_WIDTH_80: fw_bw = IWX_TLC_MNG_CH_WIDTH_80MHZ; break; case IEEE80211_CHAN_WIDTH_80P80: case IEEE80211_CHAN_WIDTH_160: fw_bw = IWX_TLC_MNG_CH_WIDTH_160MHZ; break; default: fw_bw = IWX_TLC_MNG_CH_WIDTH_20MHZ; break; } return fw_bw; } uint16_t ItlIwx:: iwx_rs_fw_get_config_flags(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; uint16_t flags = 0; if (ic->ic_state < IEEE80211_S_ASSOC) { return flags; } if (iwx_num_of_ant(iwx_fw_valid_tx_ant(sc)) > 1) { if ((ni->ni_flags & IEEE80211_NODE_HE) && ni->ni_he_cap_elem.phy_cap_info[2] & IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) { flags |= IWX_TLC_MNG_CFG_FLAGS_STBC_MSK; } else if (ni->ni_vhtcaps & IEEE80211_VHTCAP_RXSTBC_MASK) flags |= IWX_TLC_MNG_CFG_FLAGS_STBC_MSK; else if (ni->ni_htcaps & IEEE80211_HTCAP_RXSTBC_MASK) flags |= IWX_TLC_MNG_CFG_FLAGS_STBC_MSK; } if (((ni->ni_htcaps & IEEE80211_HTCAP_LDPC) || ((ic->ic_flags & IEEE80211_F_VHTON) && (ni->ni_vhtcaps & IEEE80211_VHTCAP_RXLDPC)))) flags |= IWX_TLC_MNG_CFG_FLAGS_LDPC_MSK; /* consider LDPC support in case of HE */ if ((ni->ni_flags & IEEE80211_NODE_HE) && (ni->ni_he_cap_elem.phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) flags |= IWX_TLC_MNG_CFG_FLAGS_LDPC_MSK; if ((ni->ni_flags & IEEE80211_NODE_HE) && !(ni->ni_he_cap_elem.phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) flags &= ~IWX_TLC_MNG_CFG_FLAGS_LDPC_MSK; if ((ni->ni_flags & IEEE80211_NODE_HE) && (ni->ni_he_cap_elem.phy_cap_info[3] & IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK)) flags |= IWX_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK; return flags; } static int rs_fw_vht_highest_rx_mcs_index(struct iwx_softc *sc, int nss) { uint16_t rx_mcs = le16toh(sc->sc_ic.ic_bss->ni_vht_mcsinfo.rx_mcs_map) & (0x3 << (2 * (nss - 1))); rx_mcs >>= (2 * (nss - 1)); switch (rx_mcs) { case IEEE80211_VHT_MCS_SUPPORT_0_7: return IWX_TLC_MNG_HT_RATE_MCS7; case IEEE80211_VHT_MCS_SUPPORT_0_8: return IWX_TLC_MNG_HT_RATE_MCS8; case IEEE80211_VHT_MCS_SUPPORT_0_9: return IWX_TLC_MNG_HT_RATE_MCS9; default: WARN_ON_ONCE(1); break; } return 0; } static void iwx_rs_fw_vht_set_enabled_rates(struct iwx_softc *sc, struct iwx_tlc_config_cmd_v4 *cmd) { uint16_t supp; int i, highest_mcs; struct ieee80211com *ic = &sc->sc_ic; for (i = 0; i < IWX_TLC_NSS_MAX && i < ic->ic_bss->ni_rx_nss; i++) { highest_mcs = rs_fw_vht_highest_rx_mcs_index(sc, i + 1); if (!highest_mcs) continue; supp = (1 << (highest_mcs + 1)) - 1; if (ic->ic_bss->ni_chw == IEEE80211_CHAN_WIDTH_20) supp &= ~(1 << IWX_TLC_MNG_HT_RATE_MCS9); cmd->ht_rates[i][IWX_TLC_MCS_PER_BW_80] = htole16(supp); if (ic->ic_bss->ni_chw == IEEE80211_CHAN_WIDTH_80P80 || ic->ic_bss->ni_chw == IEEE80211_CHAN_WIDTH_160) cmd->ht_rates[i][1] = cmd->ht_rates[i][0]; } } static uint16_t rs_fw_he_ieee80211_mcs_to_rs_mcs(uint16_t mcs) { switch (mcs) { case IEEE80211_HE_MCS_SUPPORT_0_7: return BIT(IWX_TLC_MNG_HT_RATE_MCS7 + 1) - 1; case IEEE80211_HE_MCS_SUPPORT_0_9: return BIT(IWX_TLC_MNG_HT_RATE_MCS9 + 1) - 1; case IEEE80211_HE_MCS_SUPPORT_0_11: return BIT(IWX_TLC_MNG_HT_RATE_MCS11 + 1) - 1; case IEEE80211_HE_MCS_NOT_SUPPORTED: return 0; } XYLog("invalid HE MCS %d\n", mcs); return 0; } static uint8_t iwx_rs_fw_set_active_chains(uint8_t chains) { uint8_t fw_chains = 0; if (chains & IWX_ANT_A) fw_chains |= IWX_TLC_MNG_CHAIN_A_MSK; if (chains & IWX_ANT_B) fw_chains |= IWX_TLC_MNG_CHAIN_B_MSK; return fw_chains; } static void iwx_rs_fw_he_set_enabled_rates(struct iwx_softc *sc, struct iwx_tlc_config_cmd_v4 *cmd) { struct ieee80211com *ic = &sc->sc_ic; uint16_t mcs_160 = le16toh(ic->ic_he_mcs_nss_supp.rx_mcs_160); uint16_t mcs_80 = le16toh(ic->ic_he_mcs_nss_supp.rx_mcs_80); uint16_t tx_mcs_80 = le16toh(ic->ic_he_mcs_nss_supp.tx_mcs_80); uint16_t tx_mcs_160 = le16toh(ic->ic_he_mcs_nss_supp.tx_mcs_160); int i; uint8_t nss = ic->ic_bss->ni_rx_nss; for (i = 0; i < nss && i < IWX_TLC_NSS_MAX; i++) { uint16_t _mcs_160 = (mcs_160 >> (2 * i)) & 0x3; uint16_t _mcs_80 = (mcs_80 >> (2 * i)) & 0x3; uint16_t _tx_mcs_160 = (tx_mcs_160 >> (2 * i)) & 0x3; uint16_t _tx_mcs_80 = (tx_mcs_80 >> (2 * i)) & 0x3; /* If one side doesn't support - mark both as not supporting */ if (_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED || _tx_mcs_80 == IEEE80211_HE_MCS_NOT_SUPPORTED) { _mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED; _tx_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED; } if (_mcs_80 > _tx_mcs_80) _mcs_80 = _tx_mcs_80; cmd->ht_rates[i][IWX_TLC_MCS_PER_BW_80] = htole16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_80)); /* If one side doesn't support - mark both as not supporting */ if (_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED || _tx_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED) { _mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED; _tx_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED; } if (_mcs_160 > _tx_mcs_160) _mcs_160 = _tx_mcs_160; cmd->ht_rates[i][IWX_TLC_MCS_PER_BW_160] = htole16(rs_fw_he_ieee80211_mcs_to_rs_mcs(_mcs_160)); } } int ItlIwx:: iwx_rs_init(struct iwx_softc *sc, struct iwx_node *in, bool update) { struct ieee80211_node *ni = &in->in_ni; struct ieee80211_rateset *rs = &ni->ni_rates; struct iwx_tlc_config_cmd_v4 cfg_cmd; uint32_t cmd_id; int i; uint16_t cmd_size; uint8_t cmdver; memset(&cfg_cmd, 0, sizeof(cfg_cmd)); for (i = 0; i < rs->rs_nrates; i++) { uint8_t rval = rs->rs_rates[i] & IEEE80211_RATE_VAL; int idx = iwx_rs_rval2idx(rval); if (idx == -1) return EINVAL; cfg_cmd.non_ht_rates |= (1 << idx); } if (ni->ni_flags & IEEE80211_NODE_HE) { cfg_cmd.mode = IWX_TLC_MNG_MODE_HE; iwx_rs_fw_he_set_enabled_rates(sc, &cfg_cmd); } else if (ni->ni_flags & IEEE80211_NODE_VHT) { cfg_cmd.mode = IWX_TLC_MNG_MODE_VHT; iwx_rs_fw_vht_set_enabled_rates(sc, &cfg_cmd); } else if (ni->ni_flags & IEEE80211_NODE_HT) { cfg_cmd.mode = IWX_TLC_MNG_MODE_HT; cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] = htole16(iwx_rs_ht_rates(sc, ni, ni->ni_chw == IEEE80211_CHAN_WIDTH_40 ? IEEE80211_HT_RATESET_CBW40_SISO : IEEE80211_HT_RATESET_SISO)); if (ni->ni_rx_nss > 1) cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] = htole16(iwx_rs_ht_rates(sc, ni, ni->ni_chw == IEEE80211_CHAN_WIDTH_40 ? IEEE80211_HT_RATESET_CBW40_MIMO2 : IEEE80211_HT_RATESET_MIMO2)); } else cfg_cmd.mode = IWX_TLC_MNG_MODE_NON_HT; cfg_cmd.sta_id = IWX_STATION_ID; cfg_cmd.max_ch_width = update ? iwx_rs_fw_bw_from_sta_bw(ni->ni_chw) : IWX_RATE_MCS_CHAN_WIDTH_20; cfg_cmd.chains = iwx_rs_fw_set_active_chains(iwx_fw_valid_tx_ant(sc)); cfg_cmd.flags = iwx_rs_fw_get_config_flags(sc); if ((ni->ni_flags & IEEE80211_NODE_HE) == 0) { if (ieee80211_node_supports_ht_sgi20(ni)) cfg_cmd.sgi_ch_width_supp = (1 << IWX_TLC_MNG_CH_WIDTH_20MHZ); if (ieee80211_node_supports_ht_sgi40(ni)) cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_40MHZ); if (ieee80211_node_supports_vht_sgi80(ni)) { cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_80MHZ); } if (ieee80211_node_supports_vht_sgi160(ni)) { cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_160MHZ); } } cmd_id = iwx_cmd_id(IWX_TLC_MNG_CONFIG_CMD, IWX_DATA_PATH_GROUP, 0); cmdver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP, IWX_TLC_MNG_CONFIG_CMD); XYLog("%s cmdver %d\n", __FUNCTION__, cmdver); if (cmdver == 4) { return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, sizeof(cfg_cmd), &cfg_cmd); } else if (cmdver < 4 || cmdver == IWX_FW_CMD_VER_UNKNOWN) { struct iwl_tlc_config_cmd_v3 cfg_cmd_v3 = { .sta_id = cfg_cmd.sta_id, .max_ch_width = cfg_cmd.max_ch_width, .mode = cfg_cmd.mode, .chains = cfg_cmd.chains, .amsdu = !!cfg_cmd.max_mpdu_len, .flags = cfg_cmd.flags, .non_ht_rates = cfg_cmd.non_ht_rates, .ht_rates[0][0] = cfg_cmd.ht_rates[0][0], .ht_rates[0][1] = cfg_cmd.ht_rates[0][1], .ht_rates[1][0] = cfg_cmd.ht_rates[1][0], .ht_rates[1][1] = cfg_cmd.ht_rates[1][1], .sgi_ch_width_supp = cfg_cmd.sgi_ch_width_supp, .max_mpdu_len = cfg_cmd.max_mpdu_len, }; cmd_size = sizeof(cfg_cmd_v3); /* In old versions of the API the struct is 4 bytes smaller */ if (cmdver == IWX_FW_CMD_VER_UNKNOWN || cmdver < 3) cmd_size -= 4; return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd_v3); } else { return -EINVAL; } } static uint32_t iwx_new_rate_from_v1(uint32_t rate_v1) { uint32_t rate_v2 = 0; uint32_t dup = 0; if (rate_v1 == 0) return rate_v1; /* convert rate */ if (rate_v1 & IWX_RATE_MCS_HT_MSK_V1) { uint32_t nss = 0; rate_v2 |= IWX_RATE_MCS_HT_MSK; rate_v2 |= rate_v1 & IWX_RATE_HT_MCS_RATE_CODE_MSK_V1; nss = (rate_v1 & IWX_RATE_HT_MCS_MIMO2_MSK) >> IWX_RATE_HT_MCS_NSS_POS_V1; rate_v2 |= nss << IWX_RATE_MCS_NSS_POS; } else if (rate_v1 & IWX_RATE_MCS_VHT_MSK_V1 || rate_v1 & IWX_RATE_MCS_HE_MSK_V1) { rate_v2 |= rate_v1 & IWX_RATE_VHT_MCS_RATE_CODE_MSK; rate_v2 |= rate_v1 & IWX_RATE_VHT_MCS_MIMO2_MSK; if (rate_v1 & IWX_RATE_MCS_HE_MSK_V1) { uint32_t he_type_bits = rate_v1 & IWX_RATE_MCS_HE_TYPE_MSK_V1; uint32_t he_type = he_type_bits >> IWX_RATE_MCS_HE_TYPE_POS_V1; uint32_t he_106t = (rate_v1 & IWX_RATE_MCS_HE_106T_MSK_V1) >> IWX_RATE_MCS_HE_106T_POS_V1; uint32_t he_gi_ltf = (rate_v1 & IWX_RATE_MCS_HE_GI_LTF_MSK_V1) >> IWX_RATE_MCS_HE_GI_LTF_POS; if ((he_type_bits == IWX_RATE_MCS_HE_TYPE_SU || he_type_bits == IWX_RATE_MCS_HE_TYPE_EXT_SU) && he_gi_ltf == IWX_RATE_MCS_HE_SU_4_LTF) /* the new rate have an additional bit to * represent the value 4 rather then using SGI * bit for this purpose - as it was done in the old * rate */ he_gi_ltf += (rate_v1 & IWX_RATE_MCS_SGI_MSK_V1) >> IWX_RATE_MCS_SGI_POS_V1; rate_v2 |= he_gi_ltf << IWX_RATE_MCS_HE_GI_LTF_POS; rate_v2 |= he_type << IWX_RATE_MCS_HE_TYPE_POS; rate_v2 |= he_106t << IWX_RATE_MCS_HE_106T_POS; rate_v2 |= rate_v1 & IWX_RATE_HE_DUAL_CARRIER_MODE_MSK; rate_v2 |= IWX_RATE_MCS_HE_MSK; } else { rate_v2 |= IWX_RATE_MCS_VHT_MSK; } /* if legacy format */ } else { uint32_t legacy_rate = iwx_hwrate_to_plcp_idx(rate_v1); WARN_ON(legacy_rate < 0); rate_v2 |= legacy_rate; if (!(rate_v1 & IWX_RATE_MCS_CCK_MSK_V1)) rate_v2 |= IWX_RATE_MCS_LEGACY_OFDM_MSK; } /* convert flags */ if (rate_v1 & IWX_RATE_MCS_LDPC_MSK_V1) rate_v2 |= IWX_RATE_MCS_LDPC_MSK; rate_v2 |= (rate_v1 & IWX_RATE_MCS_CHAN_WIDTH_MSK_V1) | (rate_v1 & IWX_RATE_MCS_ANT_AB_MSK) | (rate_v1 & IWX_RATE_MCS_STBC_MSK) | (rate_v1 & IWX_RATE_MCS_BF_MSK); dup = (rate_v1 & IWX_RATE_MCS_DUP_MSK_V1) >> IWX_RATE_MCS_DUP_POS_V1; if (dup) { rate_v2 |= IWX_RATE_MCS_DUP_MSK; rate_v2 |= dup << IWX_RATE_MCS_CHAN_WIDTH_POS; } if ((!(rate_v1 & IWX_RATE_MCS_HE_MSK_V1)) && (rate_v1 & IWX_RATE_MCS_SGI_MSK_V1)) rate_v2 |= IWX_RATE_MCS_SGI_MSK; return rate_v2; } void ItlIwx:: iwx_rs_update(struct iwx_softc *sc, struct iwx_tlc_update_notif *notif) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; struct ieee80211_rateset *rs = &ni->ni_rates; uint32_t rate_n_flags; int i; char pretty_rate[100]; uint8_t notifver; uint32_t format; if (notif->sta_id != IWX_STATION_ID || (le32toh(notif->flags) & IWX_TLC_NOTIF_FLAG_RATE) == 0) return; rate_n_flags = le32toh(notif->rate); notifver = iwx_lookup_notif_ver(sc, IWX_DATA_PATH_GROUP, IWX_TLC_MNG_UPDATE_NOTIF); if (notifver < 3 || notifver == IWX_FW_CMD_VER_UNKNOWN) { iwx_rs_pretty_print_rate_v1(pretty_rate, sizeof(pretty_rate), rate_n_flags); rate_n_flags = iwx_new_rate_from_v1(rate_n_flags); } else { iwx_rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate), rate_n_flags); } XYLog("%s new rate: %s\n", __FUNCTION__, pretty_rate); format = rate_n_flags & IWX_RATE_MCS_MOD_TYPE_MSK; if (format == IWX_RATE_MCS_VHT_MSK || format == IWX_RATE_MCS_HE_MSK || format == IWX_RATE_MCS_EHT_MSK) { ni->ni_txmcs = rate_n_flags & IWX_RATE_MCS_CODE_MSK; } else if (format == IWX_RATE_MCS_HT_MSK) { ni->ni_txmcs = IWX_RATE_HT_MCS_INDEX(rate_n_flags); } else { uint8_t plcp = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK_V1); uint8_t rval = 0; for (i = IWX_RATE_1M_INDEX; i < nitems(iwx_rates); i++) { if (iwx_rates[i].plcp == plcp) { rval = iwx_rates[i].rate; break; } } if (rval) { uint8_t rv; for (i = 0; i < rs->rs_nrates; i++) { rv = rs->rs_rates[i] & IEEE80211_RATE_VAL; if (rv == rval) { ni->ni_txrate = i; break; } } } } } int ItlIwx:: iwx_phy_ctxt_update(struct iwx_softc *sc, struct iwx_phy_ctxt *phyctxt, struct ieee80211_channel *chan, uint8_t chains_static, uint8_t chains_dynamic, uint32_t apply_time) { uint16_t band_flags = (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ); int err; if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && (phyctxt->channel->ic_flags & band_flags) != (chan->ic_flags & band_flags)) { err = iwx_phy_ctxt_cmd(sc, phyctxt, chains_static, chains_dynamic, IWX_FW_CTXT_ACTION_REMOVE, apply_time); if (err) { printf("%s: could not remove PHY context " "(error %d)\n", DEVNAME(sc), err); return err; } phyctxt->channel = chan; err = iwx_phy_ctxt_cmd(sc, phyctxt, chains_static, chains_dynamic, IWX_FW_CTXT_ACTION_ADD, apply_time); if (err) { printf("%s: could not add PHY context " "(error %d)\n", DEVNAME(sc), err); return err; } } else { phyctxt->channel = chan; err = iwx_phy_ctxt_cmd(sc, phyctxt, chains_static, chains_dynamic, IWX_FW_CTXT_ACTION_MODIFY, apply_time); if (err) { printf("%s: could not update PHY context (error %d)\n", DEVNAME(sc), err); return err; } } return 0; } int ItlIwx:: iwx_auth(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwx_node *in = (struct iwx_node *)ic->ic_bss; uint32_t duration; int generation = sc->sc_generation, err = 0; splassert(IPL_NET); in->in_ni.ni_chw = IEEE80211_CHAN_WIDTH_20_NOHT; in->in_ni.ni_flags &= ~(IEEE80211_NODE_HT | IEEE80211_NODE_QOS | IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40 | IEEE80211_NODE_VHT | IEEE80211_NODE_VHT_SGI80 | IEEE80211_NODE_VHT_SGI160 | IEEE80211_NODE_HE); if (ic->ic_opmode == IEEE80211_M_MONITOR) { err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], ic->ic_ibss_chan, 1, 1, 0); if (err) return err; } else { err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], in->in_ni.ni_chan, 1, 1, 0); if (err) return err; } in->in_phyctxt = &sc->sc_phyctxt[0]; IEEE80211_ADDR_COPY(in->in_macaddr, in->in_ni.ni_macaddr); err = iwx_mac_ctxt_cmd(sc, in, IWX_FW_CTXT_ACTION_ADD, 0); if (err) { XYLog("%s: could not add MAC context (error %d)\n", DEVNAME(sc), err); return err; } sc->sc_flags |= IWX_FLAG_MAC_ACTIVE; err = iwx_binding_cmd(sc, in, IWX_FW_CTXT_ACTION_ADD); if (err) { XYLog("%s: could not add binding (error %d)\n", DEVNAME(sc), err); goto rm_mac_ctxt; } sc->sc_flags |= IWX_FLAG_BINDING_ACTIVE; err = iwx_add_sta_cmd(sc, in, 0); if (err) { XYLog("%s: could not add sta (error %d)\n", DEVNAME(sc), err); goto rm_binding; } if (ic->ic_opmode == IEEE80211_M_MONITOR) { err = iwx_enable_txq(sc, IWX_MONITOR_STA_ID, IWX_DQA_INJECT_MONITOR_QUEUE, IWX_MGMT_TID, sc->txq[IWX_DQA_INJECT_MONITOR_QUEUE].ring_count); if (err) goto rm_sta; return 0; } err = iwx_enable_mgmt_queue(sc); if (err) goto rm_sta; err = iwx_clear_statistics(sc); if (err) goto rm_sta; /* * Prevent the FW from wandering off channel during association * by "protecting" the session with a time event. */ if (in->in_ni.ni_intval) duration = in->in_ni.ni_intval * 2; else duration = IEEE80211_DUR_TU; /* Try really hard to protect the session and hear a beacon * The new session protection command allows us to protect the * session for a much longer time since the firmware will internally * create two events: a 300TU one with a very high priority that * won't be fragmented which should be enough for 99% of the cases, * and another one (which we configure here to be 900TU long) which * will have a slightly lower priority, but more importantly, can be * fragmented so that it'll allow other activities to run. */ if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_SESSION_PROT_CMD)) err = iwx_schedule_protect_session(sc, in, duration); else iwx_protect_session(sc, in, duration, in->in_ni.ni_intval / 2); return err; rm_sta: if (generation == sc->sc_generation) iwx_rm_sta_cmd(sc, in); rm_binding: if (generation == sc->sc_generation) { iwx_binding_cmd(sc, in, IWX_FW_CTXT_ACTION_REMOVE); sc->sc_flags &= ~IWX_FLAG_BINDING_ACTIVE; } rm_mac_ctxt: if (generation == sc->sc_generation) { iwx_mac_ctxt_cmd(sc, in, IWX_FW_CTXT_ACTION_REMOVE, 0); sc->sc_flags &= ~IWX_FLAG_MAC_ACTIVE; } return err; } int ItlIwx:: iwx_deauth(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwx_node *in = (struct iwx_node *)ic->ic_bss; int err; splassert(IPL_NET); if (!isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_SESSION_PROT_CMD)) iwx_unprotect_session(sc, in); else iwx_cancel_session_protection(sc, in); if (sc->sc_flags & IWX_FLAG_STA_ACTIVE) { err = iwx_rm_sta(sc, in); if (err) return err; } if (sc->sc_flags & IWX_FLAG_BINDING_ACTIVE) { err = iwx_binding_cmd(sc, in, IWX_FW_CTXT_ACTION_REMOVE); if (err) { XYLog("%s: could not remove binding (error %d)\n", DEVNAME(sc), err); return err; } sc->sc_flags &= ~IWX_FLAG_BINDING_ACTIVE; } if (sc->sc_flags & IWX_FLAG_MAC_ACTIVE) { err = iwx_mac_ctxt_cmd(sc, in, IWX_FW_CTXT_ACTION_REMOVE, 0); if (err) { XYLog("%s: could not remove MAC context (error %d)\n", DEVNAME(sc), err); return err; } sc->sc_flags &= ~IWX_FLAG_MAC_ACTIVE; } in->in_ni.ni_chw = IEEE80211_CHAN_WIDTH_20_NOHT; in->in_ni.ni_flags &= ~(IEEE80211_NODE_HT | IEEE80211_NODE_QOS | IEEE80211_NODE_HT_SGI20 | IEEE80211_NODE_HT_SGI40 | IEEE80211_NODE_VHT | IEEE80211_NODE_VHT_SGI80 | IEEE80211_NODE_VHT_SGI160 | IEEE80211_NODE_HE); /* Move unused PHY context to a default channel. */ err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], &ic->ic_channels[1], 1, 1, 0); if (err) return err; return 0; } int ItlIwx:: iwx_run(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; struct iwx_node *in = (struct iwx_node *)ic->ic_bss; int err; int chains = iwx_mimo_enabled(sc) ? 2 : 1; splassert(IPL_NET); if (ic->ic_opmode == IEEE80211_M_MONITOR) { /* Add a MAC context and a sniffing STA. */ err = iwx_auth(sc); if (err) return err; } if (in->in_ni.ni_chw == IEEE80211_CHAN_WIDTH_80P80) { /* Fallback to 20mhz VHT */ in->in_ni.ni_chw = IEEE80211_CHAN_WIDTH_20; } /* Configure Rx chains for MIMO. */ if ((ic->ic_opmode == IEEE80211_M_MONITOR || (in->in_ni.ni_flags & IEEE80211_NODE_HT) || (in->in_ni.ni_flags & IEEE80211_NODE_VHT) || (in->in_ni.ni_flags & IEEE80211_NODE_HE))) { err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], in->in_ni.ni_chan, chains, chains, 0); if (err) { XYLog("%s: failed to update PHY\n", DEVNAME(sc)); return err; } } /* We have now been assigned an associd by the AP. */ err = iwx_mac_ctxt_cmd(sc, in, IWX_FW_CTXT_ACTION_MODIFY, 1); if (err) { XYLog("%s: failed to update MAC\n", DEVNAME(sc)); return err; } err = iwx_sf_config(sc, IWX_SF_FULL_ON); if (err) { XYLog("%s: could not set sf full on (error %d)\n", DEVNAME(sc), err); return err; } err = iwx_allow_mcast(sc); if (err) { XYLog("%s: could not allow mcast (error %d)\n", DEVNAME(sc), err); return err; } err = iwx_power_update_device(sc); if (err) { XYLog("%s: could not send power command (error %d)\n", DEVNAME(sc), err); return err; } #ifdef notyet /* * Disabled for now. Default beacon filter settings * prevent net80211 from getting ERP and HT protection * updates from beacons. */ err = iwx_enable_beacon_filter(sc, in); if (err) { XYLog("%s: could not enable beacon filter\n", DEVNAME(sc)); return err; } #endif err = iwx_power_mac_update_mode(sc, in); if (err) { XYLog("%s: could not update MAC power (error %d)\n", DEVNAME(sc), err); return err; } if (!isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) { err = iwx_update_quotas(sc, in, 1); if (err) { XYLog("%s: could not update quotas (error %d)\n", DEVNAME(sc), err); return err; } } if (ic->ic_opmode == IEEE80211_M_MONITOR) return 0; /* Start at lowest available bit-rate. Firmware will raise. */ in->in_ni.ni_txrate = 0; in->in_ni.ni_txmcs = 0; err = iwx_add_sta_cmd(sc, in, 1); if (err) { XYLog("%s: could not update sta (error %d)\n", DEVNAME(sc), err); return err; } err = iwx_rs_init(sc, in, true); if (err) { XYLog("%s: could not update rate scaling (error %d)\n", DEVNAME(sc), err); return err; } return 0; } int ItlIwx:: iwx_run_stop(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_node *in = (struct iwx_node *)ic->ic_bss; int err, i; splassert(IPL_NET); err = iwx_flush_sta(sc, in); if (err) { XYLog("%s: could not flush Tx path (error %d)\n", __FUNCTION__, err); return err; } /* * Stop Rx BA sessions now. We cannot rely on the BA task * for this when moving out of RUN state since it runs in a * separate thread. * Note that in->in_ni (struct ieee80211_node) already represents * our new access point in case we are roaming between APs. * This means we cannot rely on struct ieee802111_node to tell * us which BA sessions exist. */ for (i = 0; i < nitems(sc->sc_rxba_data); i++) { struct iwx_rxba_data *rxba = &sc->sc_rxba_data[i]; if (rxba->baid == IWX_RX_REORDER_DATA_INVALID_BAID) continue; iwx_sta_rx_agg(sc, ic->ic_bss, rxba->tid, 0, 0, 0, 0); } err = iwx_sf_config(sc, IWX_SF_INIT_OFF); if (err) return err; err = iwx_disable_beacon_filter(sc); if (err) { XYLog("%s: could not disable beacon filter (error %d)\n", DEVNAME(sc), err); return err; } if (!isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) { err = iwx_update_quotas(sc, in, 0); if (err) { XYLog("%s: could not update quotas (error %d)\n", DEVNAME(sc), err); return err; } } err = iwx_mac_ctxt_cmd(sc, in, IWX_FW_CTXT_ACTION_MODIFY, 0); if (err) { XYLog("%s: failed to update MAC\n", DEVNAME(sc)); return err; } /* Reset Tx chains in case MIMO was enabled. */ if ((in->in_ni.ni_flags & IEEE80211_NODE_HT) && iwx_mimo_enabled(sc)) { err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], in->in_ni.ni_chan, 1, 1, 0); if (err) { XYLog("%s: failed to update PHY\n", DEVNAME(sc)); return err; } } return 0; } struct ieee80211_node *ItlIwx:: iwx_node_alloc(struct ieee80211com *ic) { return (struct ieee80211_node *)malloc(sizeof (struct iwx_node), 0, M_NOWAIT | M_ZERO); } int ItlIwx:: iwx_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { struct iwx_softc *sc = (struct iwx_softc *)ic->ic_softc; struct iwx_add_sta_key_cmd cmd; ItlIwx *that = container_of(sc, ItlIwx, com); if (k->k_cipher != IEEE80211_CIPHER_CCMP) { /* Fallback to software crypto for other ciphers. */ return (ieee80211_set_key(ic, ni, k)); } memset(&cmd, 0, sizeof(cmd)); cmd.common.key_flags = htole16(IWX_STA_KEY_FLG_CCM | IWX_STA_KEY_FLG_WEP_KEY_MAP | ((k->k_id << IWX_STA_KEY_FLG_KEYID_POS) & IWX_STA_KEY_FLG_KEYID_MSK)); if (k->k_flags & IEEE80211_KEY_GROUP) { cmd.common.key_offset = 1; cmd.common.key_flags |= htole16(IWX_STA_KEY_MULTICAST); } else cmd.common.key_offset = 0; memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len)); cmd.common.sta_id = IWX_STATION_ID; cmd.transmit_seq_cnt = htole64(k->k_tsc); return that->iwx_send_cmd_pdu(sc, IWX_ADD_STA_KEY, IWX_CMD_ASYNC, sizeof(cmd), &cmd); } void ItlIwx:: iwx_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, struct ieee80211_key *k) { struct iwx_softc *sc = (struct iwx_softc *)ic->ic_softc; struct iwx_add_sta_key_cmd cmd; ItlIwx *that = container_of(sc, ItlIwx, com); if (k->k_cipher != IEEE80211_CIPHER_CCMP) { /* Fallback to software crypto for other ciphers. */ ieee80211_delete_key(ic, ni, k); return; } memset(&cmd, 0, sizeof(cmd)); cmd.common.key_flags = htole16(IWX_STA_KEY_NOT_VALID | IWX_STA_KEY_FLG_NO_ENC | IWX_STA_KEY_FLG_WEP_KEY_MAP | ((k->k_id << IWX_STA_KEY_FLG_KEYID_POS) & IWX_STA_KEY_FLG_KEYID_MSK)); memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len)); if (k->k_flags & IEEE80211_KEY_GROUP) cmd.common.key_offset = 1; else cmd.common.key_offset = 0; cmd.common.sta_id = IWX_STATION_ID; that->iwx_send_cmd_pdu(sc, IWX_ADD_STA_KEY, IWX_CMD_ASYNC, sizeof(cmd), &cmd); } int ItlIwx:: iwx_media_change(struct _ifnet *ifp) { struct iwx_softc *sc = (struct iwx_softc *)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; uint8_t rate, ridx; int err; err = ieee80211_media_change(ifp); if (err != ENETRESET) return err; if (ic->ic_fixed_mcs != -1) sc->sc_fixed_ridx = iwx_mcs2ridx[ic->ic_fixed_mcs]; else if (ic->ic_fixed_rate != -1) { rate = ic->ic_sup_rates[ic->ic_curmode]. rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; /* Map 802.11 rate to HW rate index. */ for (ridx = 0; ridx <= IWX_RIDX_MAX; ridx++) if (iwx_rates[ridx].rate == rate) break; sc->sc_fixed_ridx = ridx; } if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) { iwx_stop(ifp); err = iwx_init(ifp); } return err; } void ItlIwx:: iwx_newstate_task(void *psc) { XYLog("%s\n", __FUNCTION__); struct iwx_softc *sc = (struct iwx_softc *)psc; struct ieee80211com *ic = &sc->sc_ic; enum ieee80211_state nstate = sc->ns_nstate; enum ieee80211_state ostate = ic->ic_state; int arg = sc->ns_arg; int err = 0, s = splnet(); ItlIwx *that = container_of(sc, ItlIwx, com); XYLog("%s sc->sc_flags & IWX_FLAG_SHUTDOWN %s\n", __FUNCTION__, sc->sc_flags & IWX_FLAG_SHUTDOWN ? "true" : "false"); if (sc->sc_flags & IWX_FLAG_SHUTDOWN) { /* iwx_stop() is waiting for us. */ // refcnt_rele_wake(&sc->task_refs); splx(s); return; } if (ostate == IEEE80211_S_SCAN) { if (nstate == ostate) { if (sc->sc_flags & IWX_FLAG_SCANNING) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } /* Firmware is no longer scanning. Do another scan. */ goto next_scan; } } if (nstate <= ostate) { switch (ostate) { case IEEE80211_S_RUN: err = that->iwx_run_stop(sc); if (err) goto out; /* FALLTHROUGH */ case IEEE80211_S_ASSOC: case IEEE80211_S_AUTH: if (nstate <= IEEE80211_S_AUTH) { err = that->iwx_deauth(sc); if (err) goto out; } /* FALLTHROUGH */ case IEEE80211_S_SCAN: case IEEE80211_S_INIT: break; } /* Die now if iwx_stop() was called while we were sleeping. */ if (sc->sc_flags & IWX_FLAG_SHUTDOWN) { // refcnt_rele_wake(&sc->task_refs); splx(s); return; } } switch (nstate) { case IEEE80211_S_INIT: break; case IEEE80211_S_SCAN: next_scan: err = that->iwx_scan(sc); if (err) break; // refcnt_rele_wake(&sc->task_refs); splx(s); return; case IEEE80211_S_AUTH: err = that->iwx_auth(sc); break; case IEEE80211_S_ASSOC: err = that->iwx_rs_init(sc, (iwx_node *)ic->ic_bss, false); if (err) { XYLog("%s: could not init rate scaling (error %d)\n", DEVNAME(sc), err); goto out; } break; case IEEE80211_S_RUN: err = that->iwx_run(sc); break; } out: if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0) { if (err) task_add(systq, &sc->init_task); else sc->sc_newstate(ic, nstate, arg); } // refcnt_rele_wake(&sc->task_refs); splx(s); } int ItlIwx:: iwx_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { struct _ifnet *ifp = IC2IFP(ic); struct iwx_softc *sc = (struct iwx_softc *)ifp->if_softc; ItlIwx *that = container_of(sc, ItlIwx, com); struct ieee80211_node *ni = ic->ic_bss; /* * Prevent attemps to transition towards the same state, unless * we are scanning in which case a SCAN -> SCAN transition * triggers another scan iteration. And AUTH -> AUTH is needed * to support band-steering. */ if (sc->ns_nstate == nstate && nstate != IEEE80211_S_SCAN && nstate != IEEE80211_S_AUTH) if (ic->ic_state == IEEE80211_S_RUN) { if (nstate == IEEE80211_S_SCAN) { /* * During RUN->SCAN we don't call sc_newstate() so * we must stop A-MPDU Tx ourselves in this case. */ ieee80211_stop_ampdu_tx(ic, ni, -1); ieee80211_ba_del(ni); } that->iwx_del_task(sc, systq, &sc->ba_task); that->iwx_del_task(sc, systq, &sc->mac_ctxt_task); that->iwx_del_task(sc, systq, &sc->chan_ctxt_task); } sc->ns_nstate = nstate; sc->ns_arg = arg; that->iwx_add_task(sc, sc->sc_nswq, &sc->newstate_task); return 0; } void ItlIwx:: iwx_endscan(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni, *nextbs; // ni = RB_MIN(ieee80211_tree, &ic->ic_tree); // for (; ni != NULL; ni = nextbs) { // nextbs = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); // XYLog("%s scan_result ssid=%s, bssid=%s, ni_rsnciphers=%d, ni_rsncipher=%d, ni_rsngroupmgmtcipher=%d, ni_rsngroupcipher=%d, ni_rssi=%d, ni_capinfo=%d, ni_intval=%d, ni_rsnakms=%d, ni_supported_rsnakms=%d, ni_rsnprotos=%d, ni_supported_rsnprotos=%d, ni_rstamp=%d\n", __FUNCTION__, ni->ni_essid, ether_sprintf(ni->ni_bssid), ni->ni_rsnciphers, ni->ni_rsncipher, ni->ni_rsngroupmgmtcipher, ni->ni_rsngroupcipher, ni->ni_rssi, ni->ni_capinfo, ni->ni_intval, ni->ni_rsnakms, ni->ni_supported_rsnakms, ni->ni_rsnprotos, ni->ni_supported_rsnprotos, ni->ni_rstamp); // } if ((sc->sc_flags & (IWX_FLAG_SCANNING | IWX_FLAG_BGSCAN)) == 0) return; sc->sc_flags &= ~(IWX_FLAG_SCANNING | IWX_FLAG_BGSCAN); ieee80211_end_scan(&ic->ic_if); } /* * Aging and idle timeouts for the different possible scenarios * in default configuration */ static const uint32_t iwx_sf_full_timeout_def[IWX_SF_NUM_SCENARIO][IWX_SF_NUM_TIMEOUT_TYPES] = { { htole32(IWX_SF_SINGLE_UNICAST_AGING_TIMER_DEF), htole32(IWX_SF_SINGLE_UNICAST_IDLE_TIMER_DEF) }, { htole32(IWX_SF_AGG_UNICAST_AGING_TIMER_DEF), htole32(IWX_SF_AGG_UNICAST_IDLE_TIMER_DEF) }, { htole32(IWX_SF_MCAST_AGING_TIMER_DEF), htole32(IWX_SF_MCAST_IDLE_TIMER_DEF) }, { htole32(IWX_SF_BA_AGING_TIMER_DEF), htole32(IWX_SF_BA_IDLE_TIMER_DEF) }, { htole32(IWX_SF_TX_RE_AGING_TIMER_DEF), htole32(IWX_SF_TX_RE_IDLE_TIMER_DEF) }, }; /* * Aging and idle timeouts for the different possible scenarios * in single BSS MAC configuration. */ static const uint32_t iwx_sf_full_timeout[IWX_SF_NUM_SCENARIO][IWX_SF_NUM_TIMEOUT_TYPES] = { { htole32(IWX_SF_SINGLE_UNICAST_AGING_TIMER), htole32(IWX_SF_SINGLE_UNICAST_IDLE_TIMER) }, { htole32(IWX_SF_AGG_UNICAST_AGING_TIMER), htole32(IWX_SF_AGG_UNICAST_IDLE_TIMER) }, { htole32(IWX_SF_MCAST_AGING_TIMER), htole32(IWX_SF_MCAST_IDLE_TIMER) }, { htole32(IWX_SF_BA_AGING_TIMER), htole32(IWX_SF_BA_IDLE_TIMER) }, { htole32(IWX_SF_TX_RE_AGING_TIMER), htole32(IWX_SF_TX_RE_IDLE_TIMER) }, }; void ItlIwx:: iwx_fill_sf_command(struct iwx_softc *sc, struct iwx_sf_cfg_cmd *sf_cmd, struct ieee80211_node *ni) { int i, j, watermark; sf_cmd->watermark[IWX_SF_LONG_DELAY_ON] = htole32(IWX_SF_W_MARK_SCAN); /* * If we are in association flow - check antenna configuration * capabilities of the AP station, and choose the watermark accordingly. */ if (ni) { if (ni->ni_flags & IEEE80211_NODE_HT || ni->ni_flags & IEEE80211_NODE_VHT || ni->ni_flags & IEEE80211_NODE_HE) { if (ni->ni_rxmcs[1] != 0) watermark = IWX_SF_W_MARK_MIMO2; else watermark = IWX_SF_W_MARK_SISO; } else { watermark = IWX_SF_W_MARK_LEGACY; } /* default watermark value for unassociated mode. */ } else { watermark = IWX_SF_W_MARK_MIMO2; } sf_cmd->watermark[IWX_SF_FULL_ON] = htole32(watermark); for (i = 0; i < IWX_SF_NUM_SCENARIO; i++) { for (j = 0; j < IWX_SF_NUM_TIMEOUT_TYPES; j++) { sf_cmd->long_delay_timeouts[i][j] = htole32(IWX_SF_LONG_DELAY_AGING_TIMER); } } if (ni) { memcpy(sf_cmd->full_on_timeouts, iwx_sf_full_timeout, sizeof(iwx_sf_full_timeout)); } else { memcpy(sf_cmd->full_on_timeouts, iwx_sf_full_timeout_def, sizeof(iwx_sf_full_timeout_def)); } } int ItlIwx:: iwx_sf_config(struct iwx_softc *sc, int new_state) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_sf_cfg_cmd sf_cmd = { .state = htole32(new_state), }; int err = 0; switch (new_state) { case IWX_SF_UNINIT: case IWX_SF_INIT_OFF: iwx_fill_sf_command(sc, &sf_cmd, NULL); break; case IWX_SF_FULL_ON: iwx_fill_sf_command(sc, &sf_cmd, ic->ic_bss); break; default: return EINVAL; } err = iwx_send_cmd_pdu(sc, IWX_REPLY_SF_CFG_CMD, IWX_CMD_ASYNC, sizeof(sf_cmd), &sf_cmd); return err; } int ItlIwx:: iwx_send_bt_init_conf(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct iwx_bt_coex_cmd bt_cmd; bt_cmd.mode = htole32(IWX_BT_COEX_WIFI); bt_cmd.enabled_modules = 0; return iwx_send_cmd_pdu(sc, IWX_BT_CONFIG, 0, sizeof(bt_cmd), &bt_cmd); } int ItlIwx:: iwx_send_soc_conf(struct iwx_softc *sc) { struct iwx_soc_configuration_cmd cmd; int err; uint32_t cmd_id, flags = 0; memset(&cmd, 0, sizeof(cmd)); /* * In VER_1 of this command, the discrete value is considered * an integer; In VER_2, it's a bitmask. Since we have only 2 * values in VER_1, this is backwards-compatible with VER_2, * as long as we don't set any other flag bits. */ if (!sc->sc_integrated) { /* VER_1 */ flags = IWX_SOC_CONFIG_CMD_FLAGS_DISCRETE; } else { /* VER_2 */ uint8_t scan_cmd_ver; if (sc->sc_ltr_delay != IWX_SOC_FLAGS_LTR_APPLY_DELAY_NONE) flags |= (sc->sc_ltr_delay & IWX_SOC_FLAGS_LTR_APPLY_DELAY_MASK); scan_cmd_ver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP, IWX_SCAN_REQ_UMAC); if (scan_cmd_ver != IWX_FW_CMD_VER_UNKNOWN && scan_cmd_ver >= 2 && sc->sc_low_latency_xtal) flags |= IWX_SOC_CONFIG_CMD_FLAGS_LOW_LATENCY; } cmd.flags = htole32(flags); cmd.latency = htole32(sc->sc_xtal_latency); cmd_id = iwx_cmd_id(IWX_SOC_CONFIGURATION_CMD, IWX_SYSTEM_GROUP, 0); err = iwx_send_cmd_pdu(sc, cmd_id, 0, sizeof(cmd), &cmd); if (err) XYLog("%s: failed to set soc latency: %d\n", DEVNAME(sc), err); return err; } int ItlIwx:: iwx_send_update_mcc_cmd(struct iwx_softc *sc, const char *alpha2) { XYLog("%s\n", __FUNCTION__); struct iwx_mcc_update_cmd mcc_cmd; struct iwx_host_cmd hcmd = { .id = IWX_MCC_UPDATE_CMD, .flags = IWX_CMD_WANT_RESP, .data = { &mcc_cmd }, }; struct iwx_rx_packet *pkt; struct iwx_mcc_update_resp *resp; size_t resp_len; int err; memset(&mcc_cmd, 0, sizeof(mcc_cmd)); mcc_cmd.mcc = htole16(alpha2[0] << 8 | alpha2[1]); if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_WIFI_MCC_UPDATE) || isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_LAR_MULTI_MCC)) mcc_cmd.source_id = IWX_MCC_SOURCE_GET_CURRENT; else mcc_cmd.source_id = IWX_MCC_SOURCE_OLD_FW; hcmd.len[0] = sizeof(struct iwx_mcc_update_cmd); hcmd.resp_pkt_len = IWX_CMD_RESP_MAX; err = iwx_send_cmd(sc, &hcmd); if (err) return err; pkt = hcmd.resp_pkt; if (!pkt || (pkt->hdr.group_id & IWX_CMD_FAILED_MSK)) { err = EIO; goto out; } resp_len = iwx_rx_packet_payload_len(pkt); if (resp_len < sizeof(*resp)) { err = EIO; goto out; } resp = (struct iwx_mcc_update_resp *)pkt->data; if (resp_len != sizeof(*resp) + resp->n_channels * sizeof(resp->channels[0])) { err = EIO; goto out; } DPRINTF(("MCC status=0x%x mcc=0x%x cap=0x%x time=0x%x geo_info=0x%x source_id=0x%d n_channels=%u\n", resp->status, resp->mcc, resp->cap, resp->time, resp->geo_info, resp->source_id, resp->n_channels)); /* Update channel map for net80211 and our scan configuration. */ iwx_init_channel_map(sc, NULL, resp->channels, resp->n_channels); out: iwx_free_resp(sc, &hcmd); return err; } int ItlIwx:: iwx_send_temp_report_ths_cmd(struct iwx_softc *sc) { struct iwx_temp_report_ths_cmd cmd; int err; /* * In order to give responsibility for critical-temperature-kill * and TX backoff to FW we need to send an empty temperature * reporting command at init time. */ memset(&cmd, 0, sizeof(cmd)); err = iwx_send_cmd_pdu(sc, IWX_WIDE_ID(IWX_PHY_OPS_GROUP, IWX_TEMP_REPORTING_THRESHOLDS_CMD), 0, sizeof(cmd), &cmd); if (err) XYLog("%s: TEMP_REPORT_THS_CMD command failed (error %d)\n", DEVNAME(sc), err); return err; } #define TX_FIFO_MAX_NUM 15 #define RX_FIFO_MAX_NUM 2 #define TX_FIFO_INTERNAL_MAX_NUM 6 int ItlIwx:: iwx_init_hw(struct iwx_softc *sc) { XYLog("%s\n", __FUNCTION__); struct ieee80211com *ic = &sc->sc_ic; int err, i; err = iwx_preinit(sc); if (err) return err; err = iwx_start_hw(sc); if (err) { XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); return err; } err = iwx_run_init_mvm_ucode(sc, 0); if (err) return err; if (!iwx_nic_lock(sc)) return EBUSY; err = iwx_send_tx_ant_cfg(sc, iwx_fw_valid_tx_ant(sc)); if (err) { XYLog("%s: could not init tx ant config (error %d)\n", DEVNAME(sc), err); goto err; } iwx_toggle_tx_ant(sc, &sc->sc_mgmt_last_antenna_idx); if (sc->sc_tx_with_siso_diversity) { err = iwx_send_phy_cfg_cmd(sc); if (err) { XYLog("%s: could not send phy config (error %d)\n", DEVNAME(sc), err); goto err; } } err = iwx_send_bt_init_conf(sc); if (err) { XYLog("%s: could not init bt coex (error %d)\n", DEVNAME(sc), err); return err; } err = iwx_send_soc_conf(sc); if (err) return err; if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_DQA_SUPPORT)){ err = iwx_send_dqa_cmd(sc); if (err) return err; } /* Add auxiliary station for scanning */ err = iwx_add_aux_sta(sc); if (err) { XYLog("%s: could not add aux station (error %d)\n", DEVNAME(sc), err); goto err; } for (i = 0; i < IWX_NUM_PHY_CTX; i++) { /* * The channel used here isn't relevant as it's * going to be overwritten in the other flows. * For now use the first channel we have. */ sc->sc_phyctxt[i].id = i; sc->sc_phyctxt[i].channel = &ic->ic_channels[1]; err = iwx_phy_ctxt_cmd(sc, &sc->sc_phyctxt[i], 1, 1, IWX_FW_CTXT_ACTION_ADD, 0); if (err) { XYLog("%s: could not add phy context %d (error %d)\n", DEVNAME(sc), i, err); goto err; } } if (!isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_SET_LTR_GEN2)) { err = iwx_config_ltr(sc); if (err) { XYLog("%s: PCIe LTR configuration failed (error %d)\n", DEVNAME(sc), err); } } if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_CT_KILL_BY_FW)) { err = iwx_send_temp_report_ths_cmd(sc); if (err) goto err; } err = iwx_power_update_device(sc); if (err) { XYLog("%s: could not send power command (error %d)\n", DEVNAME(sc), err); goto err; } if (sc->sc_nvm.lar_enabled) { err = iwx_send_update_mcc_cmd(sc, "ZZ"); if (err) { XYLog("%s: could not init LAR (error %d)\n", DEVNAME(sc), err); goto err; } } err = iwx_config_umac_scan(sc); if (err) { XYLog("%s: could not configure scan (error %d)\n", DEVNAME(sc), err); goto err; } err = iwx_disable_beacon_filter(sc); if (err) { XYLog("%s: could not disable beacon filter (error %d)\n", DEVNAME(sc), err); goto err; } err: iwx_nic_unlock(sc); return err; } /* Allow multicast from our BSSID. */ int ItlIwx:: iwx_allow_mcast(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_node *in = (struct iwx_node *)ic->ic_bss; struct iwx_mcast_filter_cmd *cmd; size_t size; int err; size = roundup(sizeof(*cmd), 4); cmd = (struct iwx_mcast_filter_cmd *)malloc(size, 0, M_NOWAIT | M_ZERO); if (cmd == NULL) return ENOMEM; cmd->filter_own = 1; cmd->port_id = 0; cmd->count = 0; cmd->pass_all = 1; IEEE80211_ADDR_COPY(cmd->bssid, in->in_macaddr); err = iwx_send_cmd_pdu(sc, IWX_MCAST_FILTER_CMD, 0, size, cmd); ::free(cmd); return err; } int ItlIwx:: iwx_init(struct _ifnet *ifp) { XYLog("%s\n", __FUNCTION__); struct iwx_softc *sc = (struct iwx_softc *)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; int err, generation; int i; memset(sc->sc_tid_data, 0, sizeof(sc->sc_tid_data)); for (i = 0; i < ARRAY_SIZE(sc->sc_tid_data); i++) { sc->sc_tid_data[i].qid = IWX_INVALID_QUEUE; } // rw_assert_wrlock(&sc->ioctl_rwl); generation = ++sc->sc_generation; // KASSERT(sc->task_refs.refs == 0); // refcnt_init(&sc->task_refs); err = iwx_init_hw(sc); if (err) { if (generation == sc->sc_generation) iwx_stop_device(sc); return err; } if (sc->sc_nvm.sku_cap_11n_enable) iwx_setup_ht_rates(sc); if (sc->sc_nvm.sku_cap_11ac_enable) iwx_setup_vht_rates(sc); if (sc->sc_nvm.sku_cap_11ax_enable) iwx_setup_he_rates(sc); ifq_clr_oactive(&ifp->if_snd); ifq_flush(&ifp->if_snd); ifp->if_flags |= IFF_RUNNING; if (ic->ic_opmode == IEEE80211_M_MONITOR) { ic->ic_bss->ni_chan = ic->ic_ibss_chan; ieee80211_new_state(ic, IEEE80211_S_RUN, -1); return 0; } ieee80211_begin_scan(ifp); /* * ieee80211_begin_scan() ends up scheduling iwx_newstate_task(). * Wait until the transition to SCAN state has completed. */ do { err = tsleep_nsec(&ic->ic_state, PCATCH, "iwxinit", SEC_TO_NSEC(1)); if (generation != sc->sc_generation) return ENXIO; if (err) { iwx_stop(ifp); return err; } } while (ic->ic_state != IEEE80211_S_SCAN); return 0; } IOReturn ItlIwx:: _iwx_start_task(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) { struct _ifnet *ifp = (struct _ifnet *)arg0; struct iwx_softc *sc = (struct iwx_softc *)ifp->if_softc; ItlIwx *that = container_of(sc, ItlIwx, com); struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni; struct ether_header *eh; mbuf_t m; int ac = EDCA_AC_BE; /* XXX */ if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) { return kIOReturnError; } for (;;) { /* why isn't this done per-queue? */ if (sc->qfullmsk != 0) { ifq_set_oactive(&ifp->if_snd); break; } /* Don't queue additional frames while flushing Tx queues. */ if (sc->sc_flags & IWX_FLAG_TXFLUSH) break; /* need to send management frames even if we're not RUNning */ m = mq_dequeue(&ic->ic_mgtq); if (m) { // ni = m->m_pkthdr.ph_cookie; ni = (struct ieee80211_node *)mbuf_pkthdr_rcvif(m); goto sendit; } if ( #ifndef AIRPORT ic->ic_state != IEEE80211_S_RUN || #endif (ic->ic_xflags & IEEE80211_F_TX_MGMT_ONLY)) break; m = ifq_dequeue(&ifp->if_snd); if (!m) break; if (mbuf_len(m) < sizeof (*eh) && mbuf_pullup(&m, sizeof (*eh)) != 0) { ifp->netStat->outputErrors++; continue; } #if NBPFILTER > 0 if (ifp->if_bpf != NULL) bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) { ifp->netStat->outputErrors++; continue; } sendit: #if NBPFILTER > 0 if (ic->ic_rawbpf != NULL) bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT); #endif if (that->iwx_tx(sc, m, ni, ac) != 0) { ieee80211_release_node(ic, ni); ifp->netStat->outputErrors++; continue; } ifp->netStat->outputPackets++; if (ifp->if_flags & IFF_UP) { sc->sc_tx_timer = 15; ifp->if_timer = 1; } } return kIOReturnSuccess; } void ItlIwx:: iwx_start(struct _ifnet *ifp) { struct iwx_softc *sc = (struct iwx_softc*)ifp->if_softc; ItlIwx *that = container_of(sc, ItlIwx, com); that->getMainCommandGate()->attemptAction(_iwx_start_task, &that->com.sc_ic.ic_ac.ac_if); } void ItlIwx:: iwx_stop(struct _ifnet *ifp) { struct iwx_softc *sc = (struct iwx_softc *)ifp->if_softc; struct ieee80211com *ic = &sc->sc_ic; struct iwx_node *in = (struct iwx_node *)ic->ic_bss; int i, s = splnet(); // rw_assert_wrlock(&sc->ioctl_rwl); sc->sc_flags |= IWX_FLAG_SHUTDOWN; /* Disallow new tasks. */ /* Cancel scheduled tasks and let any stale tasks finish up. */ task_del(systq, &sc->init_task); iwx_del_task(sc, sc->sc_nswq, &sc->newstate_task); iwx_del_task(sc, systq, &sc->ba_task); iwx_del_task(sc, systq, &sc->mac_ctxt_task); iwx_del_task(sc, systq, &sc->chan_ctxt_task); KASSERT(sc->task_refs.refs >= 1, "sc->task_refs.refs >= 1"); // refcnt_finalize(&sc->task_refs, "iwxstop"); iwx_stop_device(sc); /* Reset soft state. */ sc->sc_generation++; for (i = 0; i < nitems(sc->sc_cmd_resp_pkt); i++) { ::free(sc->sc_cmd_resp_pkt[i]); sc->sc_cmd_resp_pkt[i] = NULL; sc->sc_cmd_resp_len[i] = 0; } ifp->if_flags &= ~IFF_RUNNING; ifq_clr_oactive(&ifp->if_snd); ifq_flush(&ifp->if_snd); if (in != NULL) { in->in_phyctxt = NULL; in->in_ni.ni_chw = IEEE80211_CHAN_WIDTH_20_NOHT; IEEE80211_ADDR_COPY(in->in_macaddr, etheranyaddr); } sc->sc_flags &= ~(IWX_FLAG_SCANNING | IWX_FLAG_BGSCAN); sc->sc_flags &= ~IWX_FLAG_MAC_ACTIVE; sc->sc_flags &= ~IWX_FLAG_BINDING_ACTIVE; sc->sc_flags &= ~IWX_FLAG_STA_ACTIVE; sc->sc_flags &= ~IWX_FLAG_TE_ACTIVE; sc->sc_flags &= ~IWX_FLAG_HW_ERR; sc->sc_flags &= ~IWX_FLAG_SHUTDOWN; sc->sc_flags &= ~IWX_FLAG_TXFLUSH; sc->sc_rx_ba_sessions = 0; sc->ba_rx.start_tidmask = 0; sc->ba_rx.stop_tidmask = 0; sc->ba_tx.start_tidmask = 0; sc->ba_tx.stop_tidmask = 0; sc->sc_newstate(ic, IEEE80211_S_INIT, -1); sc->ns_nstate = IEEE80211_S_INIT; for (i = 0; i < nitems(sc->sc_rxba_data); i++) { struct iwx_rxba_data *rxba = &sc->sc_rxba_data[i]; iwx_clear_reorder_buffer(sc, rxba); } ifp->if_timer = sc->sc_tx_timer = 0; splx(s); } void ItlIwx:: iwx_watchdog(struct _ifnet *ifp) { struct iwx_softc *sc = (struct iwx_softc *)ifp->if_softc; ItlIwx *that = container_of(sc, ItlIwx, com); ifp->if_timer = 0; if (sc->sc_tx_timer > 0) { if (--sc->sc_tx_timer == 0) { XYLog("%s: device timeout\n", DEVNAME(sc)); #ifdef IWX_DEBUG int i; /* Dump driver status (TX and RX rings) while we're here. */ XYLog("driver status:\n"); for (i = 0; i < IWX_MAX_QUEUES; i++) { struct iwx_tx_ring *ring = &sc->txq[i]; XYLog(" tx ring %2d: qid=%-2d cur=%-3d " "queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); } XYLog(" rx ring: cur=%d\n", sc->rxq.cur); XYLog(" 802.11 state %s\n", ieee80211_state_name[sc->sc_ic.ic_state]); that->iwx_nic_error(sc); #endif if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0) task_add(systq, &sc->init_task); ifp->netStat->outputErrors++; return; } ifp->if_timer = 1; } ieee80211_watchdog(ifp); } int ItlIwx:: iwx_ioctl(struct _ifnet *ifp, u_long cmd, caddr_t data) { struct iwx_softc *sc = (struct iwx_softc *)ifp->if_softc; int s, err = 0, generation = sc->sc_generation; ItlIwx *that = container_of(sc, ItlIwx, com); /* * Prevent processes from entering this function while another * process is tsleep'ing in it. */ // err = rw_enter(&sc->ioctl_rwl, RW_WRITE | RW_INTR); if (err == 0 && generation != sc->sc_generation) { // rw_exit(&sc->ioctl_rwl); return ENXIO; } if (err) return err; s = splnet(); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; /* FALLTHROUGH */ case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { if (!(ifp->if_flags & IFF_RUNNING)) { err = that->iwx_init(ifp); } } else { if (ifp->if_flags & IFF_RUNNING) that->iwx_stop(ifp); } break; default: err = ieee80211_ioctl(ifp, cmd, data); } if (err == ENETRESET) { err = 0; if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) { that->iwx_stop(ifp); err = that->iwx_init(ifp); } } splx(s); // rw_exit(&sc->ioctl_rwl); return err; } #if 1 /* usually #ifdef IWX_DEBUG but always enabled for now */ /* * Note: This structure is read from the device with IO accesses, * and the reading already does the endian conversion. As it is * read with uint32_t-sized accesses, any members with a different size * need to be ordered correctly though! */ struct iwx_error_event_table { uint32_t valid; /* (nonzero) valid, (0) log is empty */ uint32_t error_id; /* type of error */ uint32_t trm_hw_status0; /* TRM HW status */ uint32_t trm_hw_status1; /* TRM HW status */ uint32_t blink2; /* branch link */ uint32_t ilink1; /* interrupt link */ uint32_t ilink2; /* interrupt link */ uint32_t data1; /* error-specific data */ uint32_t data2; /* error-specific data */ uint32_t data3; /* error-specific data */ uint32_t bcon_time; /* beacon timer */ uint32_t tsf_low; /* network timestamp function timer */ uint32_t tsf_hi; /* network timestamp function timer */ uint32_t gp1; /* GP1 timer register */ uint32_t gp2; /* GP2 timer register */ uint32_t fw_rev_type; /* firmware revision type */ uint32_t major; /* uCode version major */ uint32_t minor; /* uCode version minor */ uint32_t hw_ver; /* HW Silicon version */ uint32_t brd_ver; /* HW board version */ uint32_t log_pc; /* log program counter */ uint32_t frame_ptr; /* frame pointer */ uint32_t stack_ptr; /* stack pointer */ uint32_t hcmd; /* last host command header */ uint32_t isr0; /* isr status register LMPM_NIC_ISR0: * rxtx_flag */ uint32_t isr1; /* isr status register LMPM_NIC_ISR1: * host_flag */ uint32_t isr2; /* isr status register LMPM_NIC_ISR2: * enc_flag */ uint32_t isr3; /* isr status register LMPM_NIC_ISR3: * time_flag */ uint32_t isr4; /* isr status register LMPM_NIC_ISR4: * wico interrupt */ uint32_t last_cmd_id; /* last HCMD id handled by the firmware */ uint32_t wait_event; /* wait event() caller address */ uint32_t l2p_control; /* L2pControlField */ uint32_t l2p_duration; /* L2pDurationField */ uint32_t l2p_mhvalid; /* L2pMhValidBits */ uint32_t l2p_addr_match; /* L2pAddrMatchStat */ uint32_t lmpm_pmg_sel; /* indicate which clocks are turned on * (LMPM_PMG_SEL) */ uint32_t u_timestamp; /* indicate when the date and time of the * compilation */ uint32_t flow_handler; /* FH read/write pointers, RX credit */ } __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; /* * UMAC error struct - relevant starting from family 8000 chip. * Note: This structure is read from the device with IO accesses, * and the reading already does the endian conversion. As it is * read with u32-sized accesses, any members with a different size * need to be ordered correctly though! */ struct iwx_umac_error_event_table { uint32_t valid; /* (nonzero) valid, (0) log is empty */ uint32_t error_id; /* type of error */ uint32_t blink1; /* branch link */ uint32_t blink2; /* branch link */ uint32_t ilink1; /* interrupt link */ uint32_t ilink2; /* interrupt link */ uint32_t data1; /* error-specific data */ uint32_t data2; /* error-specific data */ uint32_t data3; /* error-specific data */ uint32_t umac_major; uint32_t umac_minor; uint32_t frame_pointer; /* core register 27*/ uint32_t stack_pointer; /* core register 28 */ uint32_t cmd_header; /* latest host cmd sent to UMAC */ uint32_t nic_isr_pref; /* ISR status register */ } __packed; #define ERROR_START_OFFSET (1 * sizeof(uint32_t)) #define ERROR_ELEM_SIZE (7 * sizeof(uint32_t)) void ItlIwx:: iwx_nic_umac_error(struct iwx_softc *sc) { struct iwx_umac_error_event_table table; uint32_t base; base = sc->sc_uc.uc_umac_error_event_table; if (base < 0x400000) { XYLog("%s: Invalid error log pointer 0x%08x\n", DEVNAME(sc), base); return; } if (iwx_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t))) { XYLog("%s: reading errlog failed\n", DEVNAME(sc)); return; } if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { XYLog("%s: Start UMAC Error Log Dump:\n", DEVNAME(sc)); XYLog("%s: Status: 0x%x, count: %d\n", DEVNAME(sc), sc->sc_flags, table.valid); } XYLog("%s: 0x%08X | %s\n", DEVNAME(sc), table.error_id, iwx_desc_lookup(table.error_id)); XYLog("%s: 0x%08X | umac branchlink1\n", DEVNAME(sc), table.blink1); XYLog("%s: 0x%08X | umac branchlink2\n", DEVNAME(sc), table.blink2); XYLog("%s: 0x%08X | umac interruptlink1\n", DEVNAME(sc), table.ilink1); XYLog("%s: 0x%08X | umac interruptlink2\n", DEVNAME(sc), table.ilink2); XYLog("%s: 0x%08X | umac data1\n", DEVNAME(sc), table.data1); XYLog("%s: 0x%08X | umac data2\n", DEVNAME(sc), table.data2); XYLog("%s: 0x%08X | umac data3\n", DEVNAME(sc), table.data3); XYLog("%s: 0x%08X | umac major\n", DEVNAME(sc), table.umac_major); XYLog("%s: 0x%08X | umac minor\n", DEVNAME(sc), table.umac_minor); XYLog("%s: 0x%08X | frame pointer\n", DEVNAME(sc), table.frame_pointer); XYLog("%s: 0x%08X | stack pointer\n", DEVNAME(sc), table.stack_pointer); XYLog("%s: 0x%08X | last host cmd\n", DEVNAME(sc), table.cmd_header); XYLog("%s: 0x%08X | isr status reg\n", DEVNAME(sc), table.nic_isr_pref); } #define IWX_FW_SYSASSERT_CPU_MASK 0xf0000000 static struct { const char *name; uint8_t num; } advanced_lookup[] = { { "NMI_INTERRUPT_WDG", 0x34 }, { "SYSASSERT", 0x35 }, { "UCODE_VERSION_MISMATCH", 0x37 }, { "BAD_COMMAND", 0x38 }, { "BAD_COMMAND", 0x39 }, { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, { "FATAL_ERROR", 0x3D }, { "NMI_TRM_HW_ERR", 0x46 }, { "NMI_INTERRUPT_TRM", 0x4C }, { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, { "NMI_INTERRUPT_HOST", 0x66 }, { "NMI_INTERRUPT_LMAC_FATAL", 0x70 }, { "NMI_INTERRUPT_UMAC_FATAL", 0x71 }, { "NMI_INTERRUPT_OTHER_LMAC_FATAL", 0x73 }, { "NMI_INTERRUPT_ACTION_PT", 0x7C }, { "NMI_INTERRUPT_UNKNOWN", 0x84 }, { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, { "ADVANCED_SYSASSERT", 0 }, }; const char *ItlIwx:: iwx_desc_lookup(uint32_t num) { int i; for (i = 0; i < nitems(advanced_lookup) - 1; i++) if (advanced_lookup[i].num == (num & ~IWX_FW_SYSASSERT_CPU_MASK)) return advanced_lookup[i].name; /* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */ return advanced_lookup[i].name; } /* * Support for dumping the error log seemed like a good idea ... * but it's mostly hex junk and the only sensible thing is the * hw/ucode revision (which we know anyway). Since it's here, * I'll just leave it in, just in case e.g. the Intel guys want to * help us decipher some "ADVANCED_SYSASSERT" later. */ void ItlIwx:: iwx_nic_error(struct iwx_softc *sc) { struct iwx_error_event_table table; uint32_t base; XYLog("%s: dumping device error log\n", DEVNAME(sc)); base = sc->sc_uc.uc_lmac_error_event_table[0]; if (base < 0x400000) { XYLog("%s: Invalid error log pointer 0x%08x\n", DEVNAME(sc), base); return; } if (iwx_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t))) { XYLog("%s: reading errlog failed\n", DEVNAME(sc)); return; } if (!table.valid) { XYLog("%s: errlog not found, skipping\n", DEVNAME(sc)); return; } if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { XYLog("%s: Start Error Log Dump:\n", DEVNAME(sc)); XYLog("%s: Status: 0x%x, count: %d\n", DEVNAME(sc), sc->sc_flags, table.valid); } XYLog("%s: 0x%08X | %-28s\n", DEVNAME(sc), table.error_id, iwx_desc_lookup(table.error_id)); XYLog("%s: %08X | trm_hw_status0\n", DEVNAME(sc), table.trm_hw_status0); XYLog("%s: %08X | trm_hw_status1\n", DEVNAME(sc), table.trm_hw_status1); XYLog("%s: %08X | branchlink2\n", DEVNAME(sc), table.blink2); XYLog("%s: %08X | interruptlink1\n", DEVNAME(sc), table.ilink1); XYLog("%s: %08X | interruptlink2\n", DEVNAME(sc), table.ilink2); XYLog("%s: %08X | data1\n", DEVNAME(sc), table.data1); XYLog("%s: %08X | data2\n", DEVNAME(sc), table.data2); XYLog("%s: %08X | data3\n", DEVNAME(sc), table.data3); XYLog("%s: %08X | beacon time\n", DEVNAME(sc), table.bcon_time); XYLog("%s: %08X | tsf low\n", DEVNAME(sc), table.tsf_low); XYLog("%s: %08X | tsf hi\n", DEVNAME(sc), table.tsf_hi); XYLog("%s: %08X | time gp1\n", DEVNAME(sc), table.gp1); XYLog("%s: %08X | time gp2\n", DEVNAME(sc), table.gp2); XYLog("%s: %08X | uCode revision type\n", DEVNAME(sc), table.fw_rev_type); XYLog("%s: %08X | uCode version major\n", DEVNAME(sc), table.major); XYLog("%s: %08X | uCode version minor\n", DEVNAME(sc), table.minor); XYLog("%s: %08X | hw version\n", DEVNAME(sc), table.hw_ver); XYLog("%s: %08X | board version\n", DEVNAME(sc), table.brd_ver); XYLog("%s: %08X | hcmd\n", DEVNAME(sc), table.hcmd); XYLog("%s: %08X | isr0\n", DEVNAME(sc), table.isr0); XYLog("%s: %08X | isr1\n", DEVNAME(sc), table.isr1); XYLog("%s: %08X | isr2\n", DEVNAME(sc), table.isr2); XYLog("%s: %08X | isr3\n", DEVNAME(sc), table.isr3); XYLog("%s: %08X | isr4\n", DEVNAME(sc), table.isr4); XYLog("%s: %08X | last cmd Id\n", DEVNAME(sc), table.last_cmd_id); XYLog("%s: %08X | wait_event\n", DEVNAME(sc), table.wait_event); XYLog("%s: %08X | l2p_control\n", DEVNAME(sc), table.l2p_control); XYLog("%s: %08X | l2p_duration\n", DEVNAME(sc), table.l2p_duration); XYLog("%s: %08X | l2p_mhvalid\n", DEVNAME(sc), table.l2p_mhvalid); XYLog("%s: %08X | l2p_addr_match\n", DEVNAME(sc), table.l2p_addr_match); XYLog("%s: %08X | lmpm_pmg_sel\n", DEVNAME(sc), table.lmpm_pmg_sel); XYLog("%s: %08X | timestamp\n", DEVNAME(sc), table.u_timestamp); XYLog("%s: %08X | flow_handler\n", DEVNAME(sc), table.flow_handler); if (sc->sc_uc.uc_umac_error_event_table) iwx_nic_umac_error(sc); } #endif //#define SYNC_RESP_STRUCT(_var_, _pkt_) \ //do { \ // bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*(_pkt_)), \ // sizeof(*(_var_)), BUS_DMASYNC_POSTREAD); \ // _var_ = (void *)((_pkt_)+1); \ //} while (/*CONSTCOND*/0) // //#define SYNC_RESP_PTR(_ptr_, _len_, _pkt_) \ //do { \ // bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*(_pkt_)), \ // sizeof(len), BUS_DMASYNC_POSTREAD); \ // _ptr_ = (void *)((_pkt_)+1); \ //} while (/*CONSTCOND*/0) #define SYNC_RESP_STRUCT(_var_, _pkt_, t) \ do { \ bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*(_pkt_)), \ sizeof(*(_var_)), BUS_DMASYNC_POSTREAD); \ _var_ = (t)((_pkt_)+1); \ } while (/*CONSTCOND*/0) int ItlIwx:: iwx_rx_pkt_valid(struct iwx_rx_packet *pkt) { int qid, idx, code; qid = pkt->hdr.qid & ~0x80; idx = pkt->hdr.idx; code = IWX_WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); return (!(qid == 0 && idx == 0 && code == 0) && pkt->len_n_flags != htole32(IWX_FH_RSCSR_FRAME_INVALID)); } /** * struct iwl_pnvm_init_complete_ntfy - PNVM initialization complete * @status: PNVM image loading status */ struct iwl_pnvm_init_complete_ntfy { uint32_t status; } __packed; /* PNVM_INIT_COMPLETE_NTFY_S_VER_1 */ void ItlIwx:: iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *data, struct mbuf_list *ml) { struct _ifnet *ifp = IC2IFP(&sc->sc_ic); struct iwx_rx_packet *pkt, *nextpkt; uint32_t offset = 0, nextoff = 0, nmpdu = 0, len; mbuf_t m0, m; const size_t minsz = sizeof(pkt->len_n_flags) + sizeof(pkt->hdr); int qid, idx, code, handled = 1; // bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWX_RBUF_SIZE, // BUS_DMASYNC_POSTREAD); m0 = data->m; while (m0 && offset + minsz < IWX_RBUF_SIZE) { pkt = (struct iwx_rx_packet *)((uint8_t*)mbuf_data(m0) + offset); qid = pkt->hdr.qid; idx = pkt->hdr.idx; code = IWX_WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); DPRINTFN(3, ("%s gid=%d cmd=%d code=0x%02x qid=%d idx=%d packet_len=%d payload_len=%d\n", __FUNCTION__, pkt->hdr.group_id, pkt->hdr.cmd, code, qid, idx, iwx_rx_packet_len(pkt), iwx_rx_packet_payload_len(pkt))); if (!iwx_rx_pkt_valid(pkt)) break; /* * XXX Intel inside (tm) * Any commands in the LONG_GROUP could actually be in the * LEGACY group. Firmware API versions >= 50 reject commands * in group 0, forcing us to use this hack. */ if (iwx_cmd_groupid(code) == IWX_LONG_GROUP) { struct iwx_tx_ring *ring = &sc->txq[qid]; struct iwx_tx_data *txdata = &ring->data[idx]; if (txdata->flags & IWX_TXDATA_FLAG_CMD_IS_NARROW) code = iwx_cmd_opcode(code); } len = sizeof(pkt->len_n_flags) + iwx_rx_packet_len(pkt); if (len < minsz || len > (IWX_RBUF_SIZE - offset)) break; if (code == IWX_REPLY_RX_MPDU_CMD && ++nmpdu == 1) { /* Take mbuf m0 off the RX ring. */ if (iwx_rx_addbuf(sc, IWX_RBUF_SIZE, sc->rxq.cur)) { ifp->netStat->inputErrors++; break; } KASSERT(data->m != m0, "data->m != m0"); } switch (code) { case IWX_REPLY_RX_PHY_CMD: iwx_rx_rx_phy_cmd(sc, pkt, data); break; case IWX_REPLY_RX_MPDU_CMD: { size_t maxlen = IWX_RBUF_SIZE - offset - minsz; nextoff = offset + roundup(len, IWX_FH_RSCSR_FRAME_ALIGN); nextpkt = (struct iwx_rx_packet *) ((uint8_t*)mbuf_data(m0) + nextoff); if (nextoff + minsz >= IWX_RBUF_SIZE || !iwx_rx_pkt_valid(nextpkt)) { /* No need to copy last frame in buffer. */ if (offset > 0) mbuf_adj(m0, offset); iwx_rx_mpdu_mq(sc, m0, pkt->data, maxlen, ml); m0 = NULL; /* stack owns m0 now; abort loop */ } else { /* * Create an mbuf which points to the current * packet. Always copy from offset zero to * preserve m_pkthdr. */ mbuf_copym(m0, 0, MBUF_COPYALL, MBUF_DONTWAIT, &m); if (m == NULL) { ifp->netStat->inputErrors++; mbuf_freem(m0); m0 = NULL; break; } mbuf_adj(m, offset); iwx_rx_mpdu_mq(sc, m, pkt->data, maxlen, ml); } break; } case IWX_BA_NOTIF: iwx_rx_tx_ba_notif(sc, pkt, data); break; case IWX_TX_CMD: iwx_rx_tx_cmd(sc, pkt, data); break; case IWX_MISSED_BEACONS_NOTIFICATION: iwx_rx_bmiss(sc, pkt, data); break; case IWX_MFUART_LOAD_NOTIFICATION: break; case IWX_ALIVE: { struct iwx_alive_resp_v4 *resp4; struct iwx_alive_resp_v5 *resp5; DPRINTF(("%s: firmware alive, size=%d\n", __FUNCTION__, iwx_rx_packet_payload_len(pkt))); if (iwx_rx_packet_payload_len(pkt) == sizeof(*resp4)) { SYNC_RESP_STRUCT(resp4, pkt, struct iwx_alive_resp_v4 *); sc->sc_uc.uc_lmac_error_event_table[0] = le32toh( resp4->lmac_data[0].dbg_ptrs.error_event_table_ptr); sc->sc_uc.uc_lmac_error_event_table[1] = le32toh( resp4->lmac_data[1].dbg_ptrs.error_event_table_ptr); sc->sc_uc.uc_log_event_table = le32toh( resp4->lmac_data[0].dbg_ptrs.log_event_table_ptr); sc->sc_uc.uc_umac_error_event_table = le32toh( resp4->umac_data.dbg_ptrs.error_info_addr); if (resp4->status == IWX_ALIVE_STATUS_OK) sc->sc_uc.uc_ok = 1; else sc->sc_uc.uc_ok = 0; } else { SYNC_RESP_STRUCT(resp5, pkt, struct iwx_alive_resp_v5 *); sc->sc_uc.uc_lmac_error_event_table[0] = le32toh( resp5->lmac_data[0].dbg_ptrs.error_event_table_ptr); sc->sc_uc.uc_lmac_error_event_table[1] = le32toh( resp5->lmac_data[1].dbg_ptrs.error_event_table_ptr); sc->sc_uc.uc_log_event_table = le32toh( resp5->lmac_data[0].dbg_ptrs.log_event_table_ptr); sc->sc_uc.uc_umac_error_event_table = le32toh( resp5->umac_data.dbg_ptrs.error_info_addr); if (resp5->status == IWX_ALIVE_STATUS_OK) sc->sc_uc.uc_ok = 1; else sc->sc_uc.uc_ok = 0; sc->sku_id[0] = le32toh(resp5->sku_id.data[0]); sc->sku_id[1] = le32toh(resp5->sku_id.data[1]); sc->sku_id[2] = le32toh(resp5->sku_id.data[2]); XYLog("Got sku_id: 0x0%x 0x0%x 0x0%x\n", sc->sku_id[0], sc->sku_id[1], sc->sku_id[2]); } sc->sc_uc.uc_intr = 1; wakeupOn(&sc->sc_uc); break; } case IWX_STATISTICS_NOTIFICATION: { struct iwx_notif_statistics *stats; struct iwx_notif_statistics_v11 *stats_v11; if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_NEW_RX_STATS)) { SYNC_RESP_STRUCT(stats, pkt, struct iwx_notif_statistics *); sc->sc_noise = iwx_get_noise((uint8_t *)&stats->rx.general.beacon_silence_rssi_a); } else { SYNC_RESP_STRUCT(stats_v11, pkt, struct iwx_notif_statistics_v11 *); sc->sc_noise = iwx_get_noise((uint8_t *)&stats_v11->rx.general.beacon_silence_rssi_a); } break; } case IWX_DTS_MEASUREMENT_NOTIFICATION: case IWX_WIDE_ID(IWX_PHY_OPS_GROUP, IWX_DTS_MEASUREMENT_NOTIF_WIDE): case IWX_WIDE_ID(IWX_PHY_OPS_GROUP, IWX_TEMP_REPORTING_THRESHOLDS_CMD): break; case IWX_WIDE_ID(IWX_PHY_OPS_GROUP, IWX_CT_KILL_NOTIFICATION): { struct iwx_ct_kill_notif *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwx_ct_kill_notif *); XYLog("%s: device at critical temperature (%u degC), " "stopping device\n", DEVNAME(sc), le16toh(notif->temperature)); sc->sc_flags |= IWX_FLAG_HW_ERR; task_add(systq, &sc->init_task); break; } case IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP, IWX_NVM_GET_INFO): case IWX_ADD_STA_KEY: case IWX_PHY_CONFIGURATION_CMD: case IWX_TX_ANT_CONFIGURATION_CMD: case IWX_ADD_STA: case IWX_MAC_CONTEXT_CMD: case IWX_REPLY_SF_CFG_CMD: case IWX_POWER_TABLE_CMD: case IWX_LTR_CONFIG: case IWX_PHY_CONTEXT_CMD: case IWX_BINDING_CONTEXT_CMD: case IWX_WIDE_ID(IWX_LONG_GROUP, IWX_SCAN_CFG_CMD): case IWX_WIDE_ID(IWX_LONG_GROUP, IWX_SCAN_REQ_UMAC): case IWX_WIDE_ID(IWX_LONG_GROUP, IWX_SCAN_ABORT_UMAC): case IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_SESSION_PROTECTION_CMD): case IWX_REPLY_BEACON_FILTERING_CMD: case IWX_MAC_PM_POWER_TABLE: case IWX_TIME_QUOTA_CMD: case IWX_REMOVE_STA: case IWX_TXPATH_FLUSH: case IWX_BT_CONFIG: case IWX_MCC_UPDATE_CMD: case IWX_TIME_EVENT_CMD: case IWX_STATISTICS_CMD: case IWX_SCD_QUEUE_CFG: { size_t pkt_len; if (sc->sc_cmd_resp_pkt[idx] == NULL) break; // bus_dmamap_sync(sc->sc_dmat, data->map, 0, // sizeof(*pkt), BUS_DMASYNC_POSTREAD); pkt_len = sizeof(pkt->len_n_flags) + iwx_rx_packet_len(pkt); if ((pkt->hdr.group_id & IWX_CMD_FAILED_MSK) || pkt_len < sizeof(*pkt) || pkt_len > sc->sc_cmd_resp_len[idx]) { ::free(sc->sc_cmd_resp_pkt[idx]); sc->sc_cmd_resp_pkt[idx] = NULL; break; } // bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*pkt), // pkt_len - sizeof(*pkt), BUS_DMASYNC_POSTREAD); memcpy(sc->sc_cmd_resp_pkt[idx], pkt, pkt_len); break; } case IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP, IWX_PNVM_INIT_COMPLETE_NTFY): wakeupOn(&sc->sc_init_complete); struct iwl_pnvm_init_complete_ntfy *pnvm_ntf; SYNC_RESP_STRUCT(pnvm_ntf, pkt, struct iwl_pnvm_init_complete_ntfy *); XYLog("PNVM complete notification received with status 0x%0x\n", le32toh(pnvm_ntf->status)); break; case IWX_INIT_COMPLETE_NOTIF: sc->sc_init_complete |= IWX_INIT_COMPLETE; wakeupOn(&sc->sc_init_complete); break; case IWX_SCAN_COMPLETE_UMAC: { struct iwx_umac_scan_complete *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwx_umac_scan_complete *); iwx_endscan(sc); break; } case IWX_SCAN_ITERATION_COMPLETE_UMAC: { struct iwx_umac_scan_iter_complete_notif *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwx_umac_scan_iter_complete_notif *); iwx_endscan(sc); break; } case IWX_MCC_CHUB_UPDATE_CMD: { struct iwx_mcc_chub_notif *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwx_mcc_chub_notif *); iwx_mcc_update(sc, notif); break; } case IWX_REPLY_ERROR: { struct iwx_error_resp *resp; SYNC_RESP_STRUCT(resp, pkt, struct iwx_error_resp *); XYLog("%s: firmware error 0x%x, cmd 0x%x\n", DEVNAME(sc), le32toh(resp->error_type), resp->cmd_id); break; } case IWX_TIME_EVENT_NOTIFICATION: { struct iwx_time_event_notif *notif; uint32_t action; SYNC_RESP_STRUCT(notif, pkt, struct iwx_time_event_notif *); if (sc->sc_time_event_uid != le32toh(notif->unique_id)) break; action = le32toh(notif->action); if (action & IWX_TE_V2_NOTIF_HOST_EVENT_END) sc->sc_flags &= ~IWX_FLAG_TE_ACTIVE; break; } case IWX_WIDE_ID(IWX_SYSTEM_GROUP, IWX_FSEQ_VER_MISMATCH_NOTIFICATION): break; /* * Firmware versions 21 and 22 generate some DEBUG_LOG_MSG * messages. Just ignore them for now. */ case IWX_DEBUG_LOG_MSG: break; case IWX_MCAST_FILTER_CMD: break; case IWX_WIDE_ID(IWX_DATA_PATH_GROUP, IWX_DQA_ENABLE_CMD): break; case IWX_WIDE_ID(IWX_SYSTEM_GROUP, IWX_SOC_CONFIGURATION_CMD): break; case IWX_WIDE_ID(IWX_SYSTEM_GROUP, IWX_INIT_EXTENDED_CFG_CMD): break; case IWX_WIDE_ID(IWX_SYSTEM_GROUP, IWX_SHARED_MEM_CFG_CMD): break; case IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP, IWX_NVM_ACCESS_COMPLETE): break; case IWX_WIDE_ID(IWX_DATA_PATH_GROUP, IWX_RX_NO_DATA_NOTIF): break; /* happens in monitor mode; ignore for now */ case IWX_WIDE_ID(IWX_DATA_PATH_GROUP, IWX_TLC_MNG_CONFIG_CMD): break; case IWX_WIDE_ID(IWX_DATA_PATH_GROUP, IWX_TLC_MNG_UPDATE_NOTIF): { struct iwx_tlc_update_notif *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwx_tlc_update_notif *); if (iwx_rx_packet_payload_len(pkt) == sizeof(*notif)) iwx_rs_update(sc, notif); break; } case IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_SESSION_PROTECTION_NOTIF): { struct iwx_session_prot_notif *notif; SYNC_RESP_STRUCT(notif, pkt, struct iwx_session_prot_notif *); if (!notif->status) { XYLog("Session protection failure\n"); sc->sc_flags &= ~IWX_FLAG_TE_ACTIVE; break; } if (!notif->start) { /* * By now, we should have finished association * and know the dtim period. */ sc->sc_flags &= ~IWX_FLAG_TE_ACTIVE; XYLog("%s finish association\n", __FUNCTION__); } break; } case IWX_WIDE_ID(IWX_LEGACY_GROUP, IWX_BAR_FRAME_RELEASE): { struct iwx_bar_frame_release *release; SYNC_RESP_STRUCT(release, pkt, struct iwx_bar_frame_release *); unsigned int baid = le32_get_bits(release->ba_info, IWX_BAR_FRAME_RELEASE_BAID_MASK); unsigned int nssn = le32_get_bits(release->ba_info, IWX_BAR_FRAME_RELEASE_NSSN_MASK); unsigned int sta_id = le32_get_bits(release->sta_tid, IWX_BAR_FRAME_RELEASE_STA_MASK); unsigned int tid = le32_get_bits(release->sta_tid, IWX_BAR_FRAME_RELEASE_TID_MASK); struct iwx_rxba_data *baid_data; if (iwx_rx_packet_payload_len(pkt) < sizeof(*release)) break; if (baid == IWX_RX_REORDER_DATA_INVALID_BAID || baid >= IWX_MAX_BAID) break; baid_data = &sc->sc_rxba_data[baid]; if (!baid_data) { DPRINTFN(1, ("Got valid BAID %d but not allocated, invalid BAR release!\n", baid)); break; } if (tid != baid_data->tid || sta_id != baid_data->sta_id) { DPRINTFN(1, ("baid 0x%x is mapped to sta:%d tid:%d, but BAR release received for sta:%d tid:%d\n", baid, baid_data->sta_id, baid_data->tid, sta_id, tid)); break; } iwx_release_frames(sc, sc->sc_ic.ic_bss, baid_data, &baid_data->reorder_buf, nssn, ml); break; } default: handled = 0; XYLog("%s: unhandled firmware response 0x%x/0x%x " "rx ring %d[%d]\n", DEVNAME(sc), code, pkt->len_n_flags, (qid & ~0x80), idx); break; } /* * uCode sets bit 0x80 when it originates the notification, * i.e. when the notification is not a direct response to a * command sent by the driver. * For example, uCode issues IWX_REPLY_RX when it sends a * received frame to the driver. */ if (handled && !(qid & (1 << 7))) { iwx_cmd_done(sc, qid, idx, code); } offset += roundup(len, IWX_FH_RSCSR_FRAME_ALIGN); if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) break; } if (m0 && m0 != data->m && mbuf_type(m0) != MBUF_TYPE_FREE) mbuf_freem(m0); } void ItlIwx:: iwx_notif_intr(struct iwx_softc *sc) { struct mbuf_list ml = MBUF_LIST_INITIALIZER(); uint16_t hw; // bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map, // 0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD); if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) hw = le16toh(*(uint16_t *)(sc->rxq.stat)) & 0xfff; else hw = le16toh(((struct iwx_rb_status *)sc->rxq.stat)->closed_rb_num) & 0xfff; hw &= (IWX_RX_MQ_RING_COUNT - 1); DPRINTFN(3, ("%s hw=%d\n", __FUNCTION__, hw)); while (sc->rxq.cur != hw) { struct iwx_rx_data *data = &sc->rxq.data[sc->rxq.cur]; iwx_rx_pkt(sc, data, &ml); sc->rxq.cur = (sc->rxq.cur + 1) % IWX_RX_MQ_RING_COUNT; } if_input(&sc->sc_ic.ic_if, &ml); /* * Tell the firmware what we have processed. * Seems like the hardware gets upset unless we align the write by 8?? */ hw = (hw == 0) ? IWX_RX_MQ_RING_COUNT - 1 : hw - 1; IWX_WRITE(sc, IWX_RFH_Q0_FRBDCB_WIDX_TRG, hw & ~7); } int ItlIwx:: iwx_intr(OSObject *object, IOInterruptEventSource* sender, int count) { // XYLog("Interrupt!!!\n"); ItlIwx *that = (ItlIwx*)object; struct iwx_softc *sc = &that->com; int handled = 0; int r1, r2, rv = 0; // IWX_WRITE(&that->com, IWX_CSR_INT_MASK, 0); if (sc->sc_flags & IWX_FLAG_USE_ICT) { uint32_t *ict = (uint32_t *)sc->ict_dma.vaddr; int tmp; tmp = htole32(ict[sc->ict_cur]); if (!tmp) goto out_ena; /* * ok, there was something. keep plowing until we have all. */ r1 = r2 = 0; while (tmp) { r1 |= tmp; ict[sc->ict_cur] = 0; sc->ict_cur = (sc->ict_cur+1) % IWX_ICT_COUNT; tmp = htole32(ict[sc->ict_cur]); } /* this is where the fun begins. don't ask */ if (r1 == 0xffffffff) r1 = 0; /* i am not expected to understand this */ if (r1 & 0xc0000) r1 |= 0x8000; r1 = (0xff & r1) | ((0xff00 & r1) << 16); } else { r1 = IWX_READ(sc, IWX_CSR_INT); if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) goto out; r2 = IWX_READ(sc, IWX_CSR_FH_INT_STATUS); } if (r1 == 0 && r2 == 0) { goto out_ena; } IWX_WRITE(sc, IWX_CSR_INT, r1 | ~sc->sc_intmask); if (r1 & IWX_CSR_INT_BIT_ALIVE) { int i; /* Firmware has now configured the RFH. */ for (i = 0; i < IWX_RX_MQ_RING_COUNT; i++) that->iwx_update_rx_desc(sc, &sc->rxq, i); IWX_WRITE(sc, IWX_RFH_Q0_FRBDCB_WIDX_TRG, 8); } handled |= (r1 & (IWX_CSR_INT_BIT_ALIVE /*| IWX_CSR_INT_BIT_SCD*/)); if (r1 & IWX_CSR_INT_BIT_RF_KILL) { handled |= IWX_CSR_INT_BIT_RF_KILL; XYLog("%s RF_KILL has been toggled\n", __FUNCTION__); that->iwx_check_rfkill(sc); task_add(systq, &sc->init_task); rv = 1; goto out_ena; } if (r1 & IWX_CSR_INT_BIT_SW_ERR) { #if 1 /* usually #ifdef IWX_DEBUG but always enabled for now */ int i; that->iwx_nic_error(sc); /* Dump driver status (TX and RX rings) while we're here. */ XYLog("driver status:\n"); for (i = 0; i < IWX_MAX_QUEUES; i++) { struct iwx_tx_ring *ring = &sc->txq[i]; XYLog(" tx ring %2d: qid=%-2d cur=%-3d " "queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); } XYLog(" rx ring: cur=%d\n", sc->rxq.cur); XYLog(" 802.11 state %s\n", ieee80211_state_name[sc->sc_ic.ic_state]); #endif XYLog("%s: fatal firmware error\n", DEVNAME(sc)); if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0) task_add(systq, &sc->init_task); rv = 1; goto out; } if (r1 & IWX_CSR_INT_BIT_HW_ERR) { handled |= IWX_CSR_INT_BIT_HW_ERR; XYLog("%s: hardware error, stopping device \n", DEVNAME(sc)); if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0) { sc->sc_flags |= IWX_FLAG_HW_ERR; task_add(systq, &sc->init_task); } rv = 1; goto out; } /* firmware chunk loaded */ if (r1 & IWX_CSR_INT_BIT_FH_TX) { IWX_WRITE(sc, IWX_CSR_FH_INT_STATUS, IWX_CSR_FH_INT_TX_MASK); handled |= IWX_CSR_INT_BIT_FH_TX; sc->sc_fw_chunk_done = 1; that->wakeupOn(&sc->sc_fw); } if (r1 & (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX | IWX_CSR_INT_BIT_RX_PERIODIC)) { if (r1 & (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX)) { handled |= (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX); IWX_WRITE(sc, IWX_CSR_FH_INT_STATUS, IWX_CSR_FH_INT_RX_MASK); } if (r1 & IWX_CSR_INT_BIT_RX_PERIODIC) { handled |= IWX_CSR_INT_BIT_RX_PERIODIC; IWX_WRITE(sc, IWX_CSR_INT, IWX_CSR_INT_BIT_RX_PERIODIC); } /* Disable periodic interrupt; we use it as just a one-shot. */ IWX_WRITE_1(sc, IWX_CSR_INT_PERIODIC_REG, IWX_CSR_INT_PERIODIC_DIS); /* * Enable periodic interrupt in 8 msec only if we received * real RX interrupt (instead of just periodic int), to catch * any dangling Rx interrupt. If it was just the periodic * interrupt, there was no dangling Rx activity, and no need * to extend the periodic interrupt; one-shot is enough. */ if (r1 & (IWX_CSR_INT_BIT_FH_RX | IWX_CSR_INT_BIT_SW_RX)) IWX_WRITE_1(sc, IWX_CSR_INT_PERIODIC_REG, IWX_CSR_INT_PERIODIC_ENA); that->iwx_notif_intr(sc); } rv = 1; out_ena: that->iwx_restore_interrupts(sc); out: return rv; } int ItlIwx:: iwx_intr_msix(OSObject *object, IOInterruptEventSource* sender, int count) { // XYLog("Interrupt!!!\n"); ItlIwx *that = (ItlIwx*)object; struct iwx_softc *sc = &that->com; uint32_t inta_fh, inta_hw; int vector = 0; inta_fh = IWX_READ(sc, IWX_CSR_MSIX_FH_INT_CAUSES_AD); inta_hw = IWX_READ(sc, IWX_CSR_MSIX_HW_INT_CAUSES_AD); IWX_WRITE(sc, IWX_CSR_MSIX_FH_INT_CAUSES_AD, inta_fh); IWX_WRITE(sc, IWX_CSR_MSIX_HW_INT_CAUSES_AD, inta_hw); inta_fh &= sc->sc_fh_mask; inta_hw &= sc->sc_hw_mask; if (inta_fh & IWX_MSIX_FH_INT_CAUSES_Q0 || inta_fh & IWX_MSIX_FH_INT_CAUSES_Q1) { that->iwx_notif_intr(sc); } /* firmware chunk loaded */ if (inta_fh & IWX_MSIX_FH_INT_CAUSES_D2S_CH0_NUM) { sc->sc_fw_chunk_done = 1; that->wakeupOn(&sc->sc_fw); } if ((inta_fh & IWX_MSIX_FH_INT_CAUSES_FH_ERR) || (inta_hw & IWX_MSIX_HW_INT_CAUSES_REG_SW_ERR) || (inta_hw & IWX_MSIX_HW_INT_CAUSES_REG_SW_ERR_V2)) { #if 1 /* usually #ifdef IWX_DEBUG but always enabled for now */ int i; that->iwx_nic_error(sc); /* Dump driver status (TX and RX rings) while we're here. */ XYLog("driver status:\n"); for (i = 0; i < IWX_MAX_QUEUES; i++) { struct iwx_tx_ring *ring = &sc->txq[i]; XYLog(" tx ring %2d: qid=%-2d cur=%-3d " "queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); } XYLog(" rx ring: cur=%d\n", sc->rxq.cur); XYLog(" 802.11 state %s\n", ieee80211_state_name[sc->sc_ic.ic_state]); #endif XYLog("%s: fatal firmware error\n", DEVNAME(sc)); if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0) task_add(systq, &sc->init_task); return 1; } if (inta_hw & IWX_MSIX_HW_INT_CAUSES_REG_RF_KILL) { that->iwx_check_rfkill(sc); task_add(systq, &sc->init_task); } if (inta_hw & IWX_MSIX_HW_INT_CAUSES_REG_HW_ERR) { XYLog("%s: hardware error, stopping device \n", DEVNAME(sc)); if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0) { sc->sc_flags |= IWX_FLAG_HW_ERR; task_add(systq, &sc->init_task); } return 1; } if (inta_hw & IWX_MSIX_HW_INT_CAUSES_REG_ALIVE) { int i; /* Firmware has now configured the RFH. */ for (i = 0; i < IWX_RX_MQ_RING_COUNT; i++) that->iwx_update_rx_desc(sc, &sc->rxq, i); IWX_WRITE(sc, IWX_RFH_Q0_FRBDCB_WIDX_TRG, 8); } /* * Before sending the interrupt the HW disables it to prevent * a nested interrupt. This is done by writing 1 to the corresponding * bit in the mask register. After handling the interrupt, it should be * re-enabled by clearing this bit. This register is defined as * write 1 clear (W1C) register, meaning that it's being clear * by writing 1 to the bit. */ IWX_WRITE(sc, IWX_CSR_MSIX_AUTOMASK_ST_AD, 1 << vector); return 1; } #define PCI_VENDOR_INTEL 0x8086 #define IWL_PCI_DEVICE(dev, subdev, cfg) \ .pm_vid = PCI_VENDOR_INTEL, .pm_pid = (dev), \ .pm_sub_vid = PCI_ANY_ID, .pm_sub_dev = (subdev), \ .drv_data = (void *)&(cfg) /* * If the device doesn't support HE, no need to have that many buffers. * 22000 devices can split multiple frames into a single RB, so fewer are * needed; AX210 cannot (but use smaller RBs by default) - these sizes * were picked according to 8 MSDUs inside 256 A-MSDUs in an A-MPDU, with * additional overhead to account for processing time. */ #define IWL_NUM_RBDS_NON_HE 512 #define IWL_NUM_RBDS_22000_HE 2048 #define IWL_NUM_RBDS_AX210_HE 4096 /* * A-MPDU buffer sizes * According to HT size varies from 8 to 64 frames * HE adds the ability to have up to 256 frames. */ #define IEEE80211_MIN_AMPDU_BUF 0x8 #define IEEE80211_MAX_AMPDU_BUF_HT 0x40 #define IEEE80211_MAX_AMPDU_BUF 0x100 const struct iwl_cfg_trans_params iwl_qu_trans_cfg = { .device_family = IWX_DEVICE_FAMILY_22000, .integrated = 1, .xtal_latency = 5000, .ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_200, }; const struct iwl_cfg_trans_params iwl_qu_medium_latency_trans_cfg = { .device_family = IWX_DEVICE_FAMILY_22000, .integrated = 1, .xtal_latency = 1820, .ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_1820, }; const struct iwl_cfg_trans_params iwl_qu_long_latency_trans_cfg = { .device_family = IWX_DEVICE_FAMILY_22000, .integrated = 1, .xtal_latency = 12000, .low_latency_xtal = true, .ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_2500, }; const struct iwl_cfg_trans_params iwl_qnj_trans_cfg = { .device_family = IWX_DEVICE_FAMILY_22000, }; const struct iwl_cfg_trans_params iwl_snj_trans_cfg = { .device_family = IWX_DEVICE_FAMILY_AX210, }; const struct iwl_cfg_trans_params iwl_so_trans_cfg = { .device_family = IWX_DEVICE_FAMILY_AX210, .integrated = 1, .xtal_latency = 500, .ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_200, }; const struct iwl_cfg_trans_params iwl_so_long_latency_trans_cfg = { .device_family = IWX_DEVICE_FAMILY_AX210, .integrated = 1, .xtal_latency = 12000, .ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_2500, }; const struct iwl_cfg_trans_params iwl_ma_trans_cfg = { .device_family = IWX_DEVICE_FAMILY_AX210, .integrated = 1, }; const struct iwl_cfg_trans_params iwl_ax200_trans_cfg = { .device_family = IWX_DEVICE_FAMILY_22000, .bisr_workaround = 1, }; const struct iwl_cfg iwlax210_2ax_cfg_so_jf_a0 = { .name = "Intel(R) Wireless-AC 9560 160MHz", .fwname = "iwlwifi-so-a0-jf-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_NON_HE, }; const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0 = { .name = "Intel(R) Wi-Fi 6 AX210 160MHz", .fwname = "iwlwifi-so-a0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0 = { .name = "Intel(R) Wi-Fi 6 AX211 160MHz", .fwname = "iwlwifi-so-a0-gf-a0-68.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0_long = { .name = "Intel(R) Wi-Fi 6 AX211 160MHz", .fwname = "iwlwifi-so-a0-gf-a0-68.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .trans.xtal_latency = 12000, .trans.low_latency_xtal = 1, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0 = { .name = "Intel(R) Wi-Fi 6 AX210 160MHz", .fwname = "iwlwifi-ty-a0-gf-a0-68.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0 = { .name = "Intel(R) Wi-Fi 6 AX411 160MHz", .fwname = "iwlwifi-so-a0-gf4-a0-68.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0_long = { .name = "Intel(R) Wi-Fi 6 AX411 160MHz", .fwname = "iwlwifi-so-a0-gf4-a0-68.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .trans.xtal_latency = 12000, .trans.low_latency_xtal = 1, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwlax411_2ax_cfg_sosnj_gf4_a0 = { .name = "Intel(R) Wi-Fi 6 AX411 160MHz", .fwname = "iwlwifi-SoSnj-a0-gf4-a0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwlax211_cfg_snj_gf_a0 = { .name = "Intel(R) Wi-Fi 6 AX211 160MHz", .fwname = "iwlwifi-SoSnj-a0-gf-a0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_snj_hr_b0 = { .fwname = "iwlwifi-SoSnj-a0-hr-b0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_snj_a0_jf_b0 = { .fwname = "iwlwifi-SoSnj-a0-jf-b0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_ma_a0_hr_b0 = { .fwname = "iwlwifi-ma-a0-hr-b0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_ma_a0_gf_a0 = { .fwname = "iwlwifi-ma-a0-gf-a0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_ma_a0_gf4_a0 = { .fwname = "iwlwifi-ma-a0-gf4-a0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_ma_a0_mr_a0 = { .fwname = "iwlwifi-ma-a0-mr-a0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_ma_a0_fm_a0 = { .fwname = "iwlwifi-ma-a0-fm-a0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_snj_a0_mr_a0 = { .fwname = "iwlwifi-SoSnj-a0-mr-a0-63.ucode", .uhb_supported = 1, .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_so_a0_hr_a0 = { .fwname = "iwlwifi-so-a0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwl_cfg_quz_a0_hr_b0 = { .fwname = "iwlwifi-QuZ-a0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; static const struct pci_matchid iwx_devices[] = { /* Qu devices */ {IWL_PCI_DEVICE(0x02F0, PCI_ANY_ID, iwl_qu_trans_cfg)}, {IWL_PCI_DEVICE(0x06F0, PCI_ANY_ID, iwl_qu_trans_cfg)}, {IWL_PCI_DEVICE(0x34F0, PCI_ANY_ID, iwl_qu_medium_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x3DF0, PCI_ANY_ID, iwl_qu_medium_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x4DF0, PCI_ANY_ID, iwl_qu_medium_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x43F0, PCI_ANY_ID, iwl_qu_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0xA0F0, PCI_ANY_ID, iwl_qu_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x2720, PCI_ANY_ID, iwl_qnj_trans_cfg)}, {IWL_PCI_DEVICE(0x2723, PCI_ANY_ID, iwl_ax200_trans_cfg)}, /* So devices */ {IWL_PCI_DEVICE(0x2725, PCI_ANY_ID, iwl_so_trans_cfg)}, {IWL_PCI_DEVICE(0x2726, PCI_ANY_ID, iwl_snj_trans_cfg)}, {IWL_PCI_DEVICE(0x7A70, PCI_ANY_ID, iwl_so_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x7AF0, PCI_ANY_ID, iwl_so_trans_cfg)}, {IWL_PCI_DEVICE(0x51F0, PCI_ANY_ID, iwl_so_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x51F1, PCI_ANY_ID, iwl_so_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x54F0, PCI_ANY_ID, iwl_so_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x7F70, PCI_ANY_ID, iwl_so_trans_cfg)}, /* Ma devices */ {IWL_PCI_DEVICE(0x2729, PCI_ANY_ID, iwl_ma_trans_cfg)}, {IWL_PCI_DEVICE(0x7E40, PCI_ANY_ID, iwl_ma_trans_cfg)}, }; struct iwl_dev_info { uint16_t device; uint16_t subdevice; uint16_t mac_type; uint16_t rf_type; uint8_t mac_step; uint8_t rf_id; uint8_t no_160; uint8_t cores; uint8_t cdb; const struct iwl_cfg *cfg; const char *name; }; #define _IWL_DEV_INFO(_device, _subdevice, _mac_type, _mac_step, _rf_type, \ _rf_id, _no_160, _cores, _cdb, _cfg, _name) \ { .device = (uint16_t)(_device), .subdevice = (uint16_t)(_subdevice), .cfg = &(_cfg), \ .name = _name, .mac_type = (uint16_t)_mac_type, .rf_type = (uint16_t)_rf_type, \ .no_160 = (uint8_t)_no_160, .cores = (uint8_t)_cores, .rf_id = (uint8_t)_rf_id, \ .mac_step = (uint8_t)_mac_step, .cdb = (uint8_t)_cdb } #define IWL_DEV_INFO(_device, _subdevice, _cfg, _name) \ _IWL_DEV_INFO(_device, _subdevice, IWL_CFG_ANY, IWL_CFG_ANY, \ IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, \ IWL_CFG_NO_CDB, _cfg, _name) const char iwl9162_name[] = "Intel(R) Wireless-AC 9162"; const char iwl9260_name[] = "Intel(R) Wireless-AC 9260"; const char iwl9260_1_name[] = "Intel(R) Wireless-AC 9260-1"; const char iwl9270_name[] = "Intel(R) Wireless-AC 9270"; const char iwl9461_name[] = "Intel(R) Wireless-AC 9461"; const char iwl9462_name[] = "Intel(R) Wireless-AC 9462"; const char iwl9560_name[] = "Intel(R) Wireless-AC 9560"; const char iwl9162_160_name[] = "Intel(R) Wireless-AC 9162 160MHz"; const char iwl9260_160_name[] = "Intel(R) Wireless-AC 9260 160MHz"; const char iwl9270_160_name[] = "Intel(R) Wireless-AC 9270 160MHz"; const char iwl9461_160_name[] = "Intel(R) Wireless-AC 9461 160MHz"; const char iwl9462_160_name[] = "Intel(R) Wireless-AC 9462 160MHz"; const char iwl9560_160_name[] = "Intel(R) Wireless-AC 9560 160MHz"; const char iwl9260_killer_1550_name[] = "Killer (R) Wireless-AC 1550 Wireless Network Adapter (9260NGW) 160MHz"; const char iwl9560_killer_1550i_name[] = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)"; const char iwl9560_killer_1550i_160_name[] = "Killer(R) Wireless-AC 1550i Wireless Network Adapter (9560NGW) 160MHz"; const char iwl9560_killer_1550s_name[] = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)"; const char iwl9560_killer_1550s_160_name[] = "Killer(R) Wireless-AC 1550s Wireless Network Adapter (9560D2W) 160MHz"; const char iwl_ax101_name[] = "Intel(R) Wi-Fi 6 AX101"; const char iwl_ax200_name[] = "Intel(R) Wi-Fi 6 AX200 160MHz"; const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz"; const char iwl_ax203_name[] = "Intel(R) Wi-Fi 6 AX203"; const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz"; const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz"; const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz"; const char iwl_bz_name[] = "Intel(R) TBD Bz device"; const char iwl_ax200_killer_1650w_name[] = "Killer(R) Wi-Fi 6 AX1650w 160MHz Wireless Network Adapter (200D2W)"; const char iwl_ax200_killer_1650x_name[] = "Killer(R) Wi-Fi 6 AX1650x 160MHz Wireless Network Adapter (200NGW)"; const char iwl_ax201_killer_1650s_name[] = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)"; const char iwl_ax201_killer_1650i_name[] = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)"; const char iwl_ax210_killer_1675w_name[] = "Killer(R) Wi-Fi 6E AX1675w 160MHz Wireless Network Adapter (210D2W)"; const char iwl_ax210_killer_1675x_name[] = "Killer(R) Wi-Fi 6E AX1675x 160MHz Wireless Network Adapter (210NGW)"; const char iwl_ax211_killer_1675s_name[] = "Killer(R) Wi-Fi 6E AX1675s 160MHz Wireless Network Adapter (211NGW)"; const char iwl_ax211_killer_1675i_name[] = "Killer(R) Wi-Fi 6E AX1675i 160MHz Wireless Network Adapter (211NGW)"; const char iwl_ax411_killer_1690s_name[] = "Killer(R) Wi-Fi 6E AX1690s 160MHz Wireless Network Adapter (411D2W)"; const char iwl_ax411_killer_1690i_name[] = "Killer(R) Wi-Fi 6E AX1690i 160MHz Wireless Network Adapter (411NGW)"; const struct iwl_cfg iwl_ax200_cfg_cc = { .fwname = "iwlwifi-cc-a0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 0, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwl_qnj_b0_hr_b0_cfg = { .fwname = "iwlwifi-QuQnj-b0-hr-b0-48.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 0, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwlax210_2ax_cfg_so_jf_b0 = { .name = "Intel(R) Wireless-AC 9560 160MHz", .fwname = "iwlwifi-so-a0-jf-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_AX210, .num_rbds = IWL_NUM_RBDS_NON_HE, }; const struct iwl_cfg iwl_ax201_cfg_qu_hr = { .name = "Intel(R) Wi-Fi 6 AX201 160MHz", .fwname = "iwlwifi-Qu-b0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 0, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0 = { .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201NGW)", .fwname = "iwlwifi-Qu-b0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0 = { .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201D2W)", .fwname = "iwlwifi-Qu-b0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0 = { .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201NGW)", .fwname = "iwlwifi-Qu-c0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0 = { .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201D2W)", .fwname = "iwlwifi-Qu-c0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwl_ax201_cfg_quz_hr = { .name = "Intel(R) Wi-Fi 6 AX201 160MHz", .fwname = "iwlwifi-QuZ-a0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 0, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwl_ax1650s_cfg_quz_hr = { .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", .fwname = "iwlwifi-QuZ-a0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwl_ax1650i_cfg_quz_hr = { .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", .fwname = "iwlwifi-QuZ-a0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; /* * All JF radio modules are part of the 9000 series, but the MAC part * looks more like 22000. That's why this device is here, but called * 9560 nevertheless. */ const struct iwl_cfg iwl9560_qu_b0_jf_b0_cfg = { .fwname = "iwlwifi-Qu-b0-jf-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 0, .uhb_supported = 0, .num_rbds = IWL_NUM_RBDS_NON_HE, }; const struct iwl_cfg iwl9560_qu_c0_jf_b0_cfg = { .fwname = "iwlwifi-Qu-c0-jf-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 0, .uhb_supported = 0, .num_rbds = IWL_NUM_RBDS_NON_HE, }; const struct iwl_cfg iwl9560_quz_a0_jf_b0_cfg = { .fwname = "iwlwifi-QuZ-a0-jf-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 0, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_NON_HE, }; const struct iwl_cfg iwl9560_qnj_b0_jf_b0_cfg = { .fwname = "iwlwifi-QuQnj-b0-jf-b0-48.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 0, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_NON_HE, }; const struct iwl_cfg iwl_qu_b0_hr1_b0 = { .fwname = "iwlwifi-Qu-b0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 1, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwl_qu_b0_hr_b0 = { .fwname = "iwlwifi-Qu-b0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwl_qu_c0_hr_b0 = { .fwname = "iwlwifi-Qu-c0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwl_qu_c0_hr1_b0 = { .fwname = "iwlwifi-Qu-c0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 1, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwl_quz_a0_hr1_b0 = { .fwname = "iwlwifi-QuZ-a0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 1, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0 = { .name = "Intel(R) Wi-Fi 6 AX201 160MHz", .fwname = "iwlwifi-Qu-c0-hr-b0-68.ucode", .device_family = IWX_DEVICE_FAMILY_22000, .tx_with_siso_diversity = 0, .uhb_supported = 0, /* * This device doesn't support receiving BlockAck with a large bitmap * so we need to restrict the size of transmitted aggregation to the * HT size; mac80211 would otherwise pick the HE max (256) by default. */ .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, .num_rbds = IWL_NUM_RBDS_22000_HE, }; static const struct iwl_dev_info iwl_dev_info_table[] = { /* AX200 */ IWL_DEV_INFO(0x2723, IWL_CFG_ANY, iwl_ax200_cfg_cc, iwl_ax200_name), IWL_DEV_INFO(0x2723, 0x1653, iwl_ax200_cfg_cc, iwl_ax200_killer_1650w_name), IWL_DEV_INFO(0x2723, 0x1654, iwl_ax200_cfg_cc, iwl_ax200_killer_1650x_name), IWL_DEV_INFO(0x51F0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x51F0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x51F1, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x54F0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x54F0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x7A70, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x7A70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x7AF0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x7AF0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), /* Qu with Hr */ IWL_DEV_INFO(0x43F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, iwl_ax201_killer_1650s_name), IWL_DEV_INFO(0x43F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, iwl_ax201_killer_1650i_name), IWL_DEV_INFO(0x43F0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0A10, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0xA0F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0xA0F0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x6074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x02F0, 0x0070, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x0074, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x6074, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x0078, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x007C, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x0310, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x1651, iwl_ax1650s_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x1652, iwl_ax1650i_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x2074, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x4070, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x0070, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x0074, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x0078, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x007C, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x0310, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x1651, iwl_ax1650s_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x1652, iwl_ax1650i_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x2074, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x4070, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x34F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x0310, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x34F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x34F0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x0310, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x3DF0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x3DF0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x0310, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x4DF0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x4DF0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x6074, iwl_ax201_cfg_qu_hr, NULL), /* Qu with JF */ IWL_DEV_INFO(0x06f0, 0x1551, iwl9560_quz_a0_jf_b0_cfg, iwl9560_killer_1550s_160_name), IWL_DEV_INFO(0x06f0, 0x1552, iwl9560_quz_a0_jf_b0_cfg, iwl9560_killer_1550i_160_name), /* So with HR */ IWL_DEV_INFO(0x2725, 0x0090, iwlax211_2ax_cfg_so_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x0020, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x2020, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x0024, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x0310, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x0510, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x0A10, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0xE020, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0xE024, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x4020, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x6020, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x6024, iwlax210_2ax_cfg_ty_gf_a0, NULL), IWL_DEV_INFO(0x2725, 0x1673, iwlax210_2ax_cfg_ty_gf_a0, iwl_ax210_killer_1675w_name), IWL_DEV_INFO(0x2725, 0x1674, iwlax210_2ax_cfg_ty_gf_a0, iwl_ax210_killer_1675x_name), IWL_DEV_INFO(0x7A70, 0x0090, iwlax211_2ax_cfg_so_gf_a0_long, NULL), IWL_DEV_INFO(0x7A70, 0x0098, iwlax211_2ax_cfg_so_gf_a0_long, NULL), IWL_DEV_INFO(0x7A70, 0x00B0, iwlax411_2ax_cfg_so_gf4_a0_long, NULL), IWL_DEV_INFO(0x7A70, 0x0310, iwlax211_2ax_cfg_so_gf_a0_long, NULL), IWL_DEV_INFO(0x7A70, 0x0510, iwlax211_2ax_cfg_so_gf_a0_long, NULL), IWL_DEV_INFO(0x7A70, 0x0A10, iwlax211_2ax_cfg_so_gf_a0_long, NULL), IWL_DEV_INFO(0x7AF0, 0x0090, iwlax211_2ax_cfg_so_gf_a0, NULL), IWL_DEV_INFO(0x7AF0, 0x0098, iwlax211_2ax_cfg_so_gf_a0, NULL), IWL_DEV_INFO(0x7AF0, 0x00B0, iwlax411_2ax_cfg_so_gf4_a0, NULL), IWL_DEV_INFO(0x7AF0, 0x0310, iwlax211_2ax_cfg_so_gf_a0, NULL), IWL_DEV_INFO(0x7AF0, 0x0510, iwlax211_2ax_cfg_so_gf_a0, NULL), IWL_DEV_INFO(0x7AF0, 0x0A10, iwlax211_2ax_cfg_so_gf_a0, NULL), /* SnJ with HR */ IWL_DEV_INFO(0x2725, 0x00B0, iwlax411_2ax_cfg_sosnj_gf4_a0, NULL), IWL_DEV_INFO(0x2726, 0x0090, iwlax211_cfg_snj_gf_a0, NULL), IWL_DEV_INFO(0x2726, 0x0098, iwlax211_cfg_snj_gf_a0, NULL), IWL_DEV_INFO(0x2726, 0x00B0, iwlax411_2ax_cfg_sosnj_gf4_a0, NULL), IWL_DEV_INFO(0x2726, 0x00B4, iwlax411_2ax_cfg_sosnj_gf4_a0, NULL), IWL_DEV_INFO(0x2726, 0x0510, iwlax211_cfg_snj_gf_a0, NULL), IWL_DEV_INFO(0x2726, 0x1651, iwl_cfg_snj_hr_b0, iwl_ax201_killer_1650s_name), IWL_DEV_INFO(0x2726, 0x1652, iwl_cfg_snj_hr_b0, iwl_ax201_killer_1650i_name), IWL_DEV_INFO(0x2726, 0x1691, iwlax411_2ax_cfg_sosnj_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x2726, 0x1692, iwlax411_2ax_cfg_sosnj_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x7F70, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x7F70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x7AF0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x7AF0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), /* SO with GF2 */ IWL_DEV_INFO(0x2726, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x2726, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), IWL_DEV_INFO(0x51F0, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x51F0, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), IWL_DEV_INFO(0x54F0, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x54F0, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), IWL_DEV_INFO(0x7A70, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x7A70, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), IWL_DEV_INFO(0x7AF0, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x7AF0, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), IWL_DEV_INFO(0x7F70, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x7F70, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), /* MA with GF2 */ IWL_DEV_INFO(0x7E40, 0x1671, iwl_cfg_ma_a0_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x7E40, 0x1672, iwl_cfg_ma_a0_gf_a0, iwl_ax211_killer_1675i_name), /* Qu with Jf */ /* Qu B step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9462_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9560_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1551, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9560_killer_1550s_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1552, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9560_killer_1550i_name), /* Qu C step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9462_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9560_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1551, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9560_killer_1550s_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1552, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9560_killer_1550i_name), /* QuZ */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9462_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9560_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1551, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9560_killer_1550s_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1552, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9560_killer_1550i_name), /* QnJ */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qnj_b0_jf_b0_cfg, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qnj_b0_jf_b0_cfg, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qnj_b0_jf_b0_cfg, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qnj_b0_jf_b0_cfg, iwl9462_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qnj_b0_jf_b0_cfg, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qnj_b0_jf_b0_cfg, iwl9560_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1551, IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qnj_b0_jf_b0_cfg, iwl9560_killer_1550s_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1552, IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qnj_b0_jf_b0_cfg, iwl9560_killer_1550i_name), /* Qu with Hr */ /* Qu B step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_b0_hr1_b0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_b0_hr_b0, iwl_ax203_name), /* Qu C step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_c0_hr1_b0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, IWX_SILICON_C_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_c0_hr_b0, iwl_ax203_name), /* QuZ */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_quz_a0_hr1_b0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWX_SILICON_B_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_quz_a0_hr_b0, iwl_ax203_name), /* QnJ with Hr */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qnj_b0_hr_b0_cfg, iwl_ax201_name), /* SnJ with Jf */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl_cfg_snj_a0_jf_b0, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl_cfg_snj_a0_jf_b0, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl_cfg_snj_a0_jf_b0, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl_cfg_snj_a0_jf_b0, iwl9462_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl_cfg_snj_a0_jf_b0, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl_cfg_snj_a0_jf_b0, iwl9560_name), /* SnJ with Hr */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_snj_hr_b0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_snj_hr_b0, iwl_ax201_name), /* Ma */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_hr_b0, iwl_ax201_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_gf_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, iwl_cfg_ma_a0_gf4_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_mr_a0, iwl_ax221_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_fm_a0, iwl_ax231_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_snj_a0_mr_a0, iwl_ax221_name), /* So with Hr */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax203_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax201_name), /* So-F with Hr */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax203_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax201_name), /* So-F with Gf */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_name), /* SoF with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9560_name), /* SoF with JF */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9462_name), /* So with GF */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_name), /* So with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9560_name), /* So with JF */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9462_name) }; int ItlIwx:: iwx_match(IOPCIDevice *device) { int devId = device->configRead16(kIOPCIConfigDeviceID); return pci_matchbyid(PCI_VENDOR_INTEL, devId, iwx_devices, nitems(iwx_devices)); } int ItlIwx:: iwx_preinit(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = IC2IFP(ic); int err; static int attached; err = iwx_prepare_card_hw(sc); if (err) { XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); return err; } if (attached) { /* Update MAC in case the upper layers changed it. */ IEEE80211_ADDR_COPY(sc->sc_ic.ic_myaddr, ((struct arpcom *)ifp)->ac_enaddr); return 0; } err = iwx_start_hw(sc); if (err) { XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); return err; } err = iwx_run_init_mvm_ucode(sc, 1); iwx_stop_device(sc); if (err) return err; /* Print version info and MAC address on first successful fw load. */ attached = 1; XYLog("%s: hw rev 0x%x, fw ver %s, address %s\n", DEVNAME(sc), sc->sc_hw_rev & IWX_CSR_HW_REV_TYPE_MSK, sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr)); if (sc->sc_nvm.sku_cap_11n_enable) iwx_setup_ht_rates(sc); if (sc->sc_nvm.sku_cap_11ac_enable) iwx_setup_vht_rates(sc); if (sc->sc_nvm.sku_cap_11ax_enable) iwx_setup_he_rates(sc); /* not all hardware can do 5GHz band */ if (!sc->sc_nvm.sku_cap_band_52GHz_enable) memset(&ic->ic_sup_rates[IEEE80211_MODE_11A], 0, sizeof(ic->ic_sup_rates[IEEE80211_MODE_11A])); /* Configure channel information obtained from firmware. */ ieee80211_channel_init(ifp); /* Configure MAC address. */ err = if_setlladdr(ifp, ic->ic_myaddr); if (err) XYLog("%s: could not set MAC address (error %d)\n", DEVNAME(sc), err); ieee80211_media_init(ifp); return 0; } void ItlIwx:: iwx_attach_hook(struct device *self) { struct iwx_softc *sc = (struct iwx_softc *)self; iwx_preinit(sc); } bool ItlIwx:: intrFilter(OSObject *object, IOFilterInterruptEventSource *src) { ItlIwx *that = (ItlIwx*)object; IWX_WRITE(&that->com, IWX_CSR_INT_MASK, 0); return true; } bool ItlIwx:: iwx_attach(struct iwx_softc *sc, struct pci_attach_args *pa) { pcireg_t reg, memtype; struct ieee80211com *ic = &sc->sc_ic; struct _ifnet *ifp = &ic->ic_if; int err; int txq_i, i, j; sc->sc_pct = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; sc->sc_dmat = pa->pa_dmat; // rw_init(&sc->ioctl_rwl, "iwxioctl"); err = pci_get_capability(sc->sc_pct, sc->sc_pcitag, PCI_CAP_PCIEXPRESS, &sc->sc_cap_off, NULL); if (err == 0) { XYLog("%s: PCIe capability structure not found!\n", DEVNAME(sc)); return false; } /* Clear device-specific "PCI retry timeout" register (41h). */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40); pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00); /* Enable bus-mastering and hardware bug workaround. */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); reg |= PCI_COMMAND_MASTER_ENABLE; /* if !MSI */ if (reg & PCI_COMMAND_INTERRUPT_DISABLE) { reg &= ~PCI_COMMAND_INTERRUPT_DISABLE; } pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START); err = pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0, &sc->sc_st, &sc->sc_sh, NULL, &sc->sc_sz, 0); if (err) { XYLog("%s: can't map mem space\n", DEVNAME(sc)); return false; } if (0) { sc->sc_msix = 1; XYLog("msix intr mode\n"); } else if (pci_intr_map_msi(pa, &sc->ih)) { XYLog("%s: can't map interrupt\n", DEVNAME(sc)); return false; } if (!sc->sc_msix) { /* Hardware bug workaround. */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); if (reg & PCI_COMMAND_INTERRUPT_DISABLE) reg &= ~PCI_COMMAND_INTERRUPT_DISABLE; pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); } int msiIntrIndex = -1; for (int index = 0; ; index++) { int interruptType; int ret = pa->pa_tag->getInterruptType(index, &interruptType); if (ret != kIOReturnSuccess) break; if (interruptType & kIOInterruptTypePCIMessaged) { msiIntrIndex = index; break; } } if (msiIntrIndex == -1) { XYLog("%s: can't find MSI interrupt controller\n", DEVNAME(sc)); return false; } if (sc->sc_msix) sc->sc_ih = IOFilterInterruptEventSource::filterInterruptEventSource(this, (IOInterruptEventSource::Action)&ItlIwx::iwx_intr_msix, &ItlIwx::intrFilter ,pa->pa_tag, msiIntrIndex); else sc->sc_ih = IOFilterInterruptEventSource::filterInterruptEventSource(this, (IOInterruptEventSource::Action)&ItlIwx::iwx_intr, &ItlIwx::intrFilter ,pa->pa_tag, msiIntrIndex); if (sc->sc_ih == NULL || pa->workloop->addEventSource(sc->sc_ih) != kIOReturnSuccess) { XYLog("%s: can't establish interrupt\n", DEVNAME(sc)); return false; } sc->sc_ih->enable(); /* Clear pending interrupts. */ IWX_WRITE(sc, IWX_CSR_INT_MASK, 0); IWX_WRITE(sc, IWX_CSR_INT, ~0); IWX_WRITE(sc, IWX_CSR_FH_INT_STATUS, ~0); sc->sc_hw_rev = IWX_READ(sc, IWX_CSR_HW_REV); /* * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have * changed, and now the revision step also includes bit 0-1 (no more * "dash" value). To keep hw_rev backwards compatible - we'll store it * in the old format. */ sc->sc_hw_rev = (sc->sc_hw_rev & 0xfff0) | (IWX_CSR_HW_REV_STEP(sc->sc_hw_rev << 2) << 2); sc->sc_hw_rf_id = IWX_READ(sc, IWX_CSR_HW_RF_ID); uint16_t device = sc->sc_pcitag->configRead16(kIOPCIConfigDeviceID); uint16_t subsystem_device = sc->sc_pcitag->configRead16(kIOPCIConfigSubSystemID); uint16_t subsystem_vendor = sc->sc_pcitag->configRead16(kIOPCIConfigSubSystemVendorID); sc->sc_hw_id = (device << 16) + subsystem_device; pci_match(PCI_VENDOR_INTEL, device, subsystem_vendor, subsystem_device, iwx_devices, nitems(iwx_devices), (void **)&com.sc_cfg_params); if (!com.sc_cfg_params) { XYLog("%s: Why??? unknown adapter type\n", DEVNAME(sc)); return false; } for (i = 0; i < ARRAY_SIZE(iwl_dev_info_table); i++) { const struct iwl_dev_info *dev_info = &iwl_dev_info_table[i]; if ((dev_info->device == (u16)IWL_CFG_ANY || dev_info->device == device) && (dev_info->subdevice == (u16)IWL_CFG_ANY || dev_info->subdevice == subsystem_device) && (dev_info->mac_type == (u16)IWL_CFG_ANY || dev_info->mac_type == CSR_HW_REV_TYPE(sc->sc_hw_rev)) && (dev_info->mac_step == (u8)IWL_CFG_ANY || dev_info->mac_step == IWX_CSR_HW_REV_STEP(sc->sc_hw_rev)) && (dev_info->rf_type == (u16)IWL_CFG_ANY || dev_info->rf_type == CSR_HW_RFID_TYPE(sc->sc_hw_rf_id)) && (dev_info->cdb == IWL_CFG_NO_CDB || CSR_HW_RFID_IS_CDB(sc->sc_hw_rf_id)) && (dev_info->rf_id == (u8)IWL_CFG_ANY || dev_info->rf_id == IWL_SUBDEVICE_RF_ID(subsystem_device)) && (dev_info->no_160 == (u8)IWL_CFG_ANY || dev_info->no_160 == IWL_SUBDEVICE_NO_160(subsystem_device)) && (dev_info->cores == (u8)IWL_CFG_ANY || dev_info->cores == IWL_SUBDEVICE_CORES(subsystem_device))) { sc->sc_cfg = dev_info->cfg; if (dev_info->name) XYLog("Found device: %s fw: %s index: %d:%zu\n", dev_info->name, dev_info->cfg->fwname, i, ARRAY_SIZE(iwl_dev_info_table)); else if (dev_info->cfg->name) XYLog("Found device cfg: %s fw: %s index: %d:%zu\n", dev_info->cfg->name, dev_info->cfg->fwname, i, ARRAY_SIZE(iwl_dev_info_table)); else XYLog("Found device: No Name fw: %s index: %d:%zu\n", dev_info->cfg->fwname, i, ARRAY_SIZE(iwl_dev_info_table)); } } /* * Workaround for problematic SnJ device: sometimes when * certain RF modules are connected to SnJ, the device ID * changes to QnJ's ID. So we are using QnJ's trans_cfg until * here. But if we detect that the MAC type is actually SnJ, * we should switch to it here to avoid problems later. */ if (CSR_HW_REV_TYPE(sc->sc_hw_rev) == IWL_CFG_MAC_TYPE_SNJ) sc->sc_cfg_params = &iwl_so_trans_cfg; /* * This is a hack to switch from Qu B0 to Qu C0. We need to * do this for all cfgs that use Qu B0, except for those using * Jf, which have already been moved to the new table. The * rest must be removed once we convert Qu with Hr as well. */ if (sc->sc_hw_rev == CSR_HW_REV_TYPE_QU_C0) { if (sc->sc_cfg == &iwl_ax201_cfg_qu_hr) sc->sc_cfg = &iwl_ax201_cfg_qu_c0_hr_b0; else if (sc->sc_cfg == &killer1650s_2ax_cfg_qu_b0_hr_b0) sc->sc_cfg = &killer1650s_2ax_cfg_qu_c0_hr_b0; else if (sc->sc_cfg == &killer1650i_2ax_cfg_qu_b0_hr_b0) sc->sc_cfg = &killer1650i_2ax_cfg_qu_c0_hr_b0; } /* same thing for QuZ... */ if (sc->sc_hw_rev == CSR_HW_REV_TYPE_QUZ) { if (sc->sc_cfg == &iwl_ax201_cfg_qu_hr) sc->sc_cfg = &iwl_ax201_cfg_quz_hr; else if (sc->sc_cfg == &killer1650s_2ax_cfg_qu_b0_hr_b0) sc->sc_cfg = &iwl_ax1650s_cfg_quz_hr; else if (sc->sc_cfg == &killer1650i_2ax_cfg_qu_b0_hr_b0) sc->sc_cfg = &iwl_ax1650i_cfg_quz_hr; } if (sc->sc_cfg == NULL) { XYLog("No config found for PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n", device, subsystem_device, sc->sc_hw_rev, sc->sc_hw_rf_id); return false; } XYLog("Found PCI dev %04x/%04x, rev=0x%x, rfid=0x%x fw: %s\n", device, subsystem_device, sc->sc_hw_rev, sc->sc_hw_rf_id, sc->sc_cfg->fwname); sc->sc_fwname = sc->sc_cfg->fwname; sc->sc_device_family = sc->sc_cfg->device_family; sc->sc_integrated = sc->sc_cfg_params->integrated; sc->sc_ltr_delay = sc->sc_cfg_params->ltr_delay; sc->sc_low_latency_xtal = sc->sc_cfg_params->low_latency_xtal; sc->sc_xtal_latency = sc->sc_cfg_params->xtal_latency; sc->sc_tx_with_siso_diversity = sc->sc_cfg->tx_with_siso_diversity; sc->sc_uhb_supported = sc->sc_cfg->uhb_supported; /* Allocate DMA memory for loading firmware. */ if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->ctxt_info_dma, sizeof(struct iwx_context_info_gen3), 0); else err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->ctxt_info_dma, sizeof(struct iwx_context_info), 0); if (err) { XYLog("%s: could not allocate memory for loading firmware\n", DEVNAME(sc)); return false; } /* Allocate interrupt cause table (ICT).*/ err = iwx_dma_contig_alloc(sc->sc_dmat, &sc->ict_dma, IWX_ICT_SIZE, 1<txq); txq_i++) { err = iwx_alloc_tx_ring(sc, &sc->txq[txq_i], txq_i); if (err) { XYLog("%s: could not allocate TX ring %d\n", DEVNAME(sc), txq_i); goto fail4; } } err = iwx_alloc_rx_ring(sc, &sc->rxq); if (err) { XYLog("%s: could not allocate RX ring\n", DEVNAME(sc)); goto fail4; } taskq_init(); sc->sc_nswq = taskq_create("iwxns", 1, IPL_NET, 0); if (sc->sc_nswq == NULL) goto fail4; ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ ic->ic_state = IEEE80211_S_INIT; /* Set device capabilities. */ ic->ic_caps = IEEE80211_C_WEP | /* WEP */ IEEE80211_C_RSN | /* WPA/RSN */ IEEE80211_C_SCANALL | /* device scans all channels at once */ IEEE80211_C_SCANALLBAND | /* device scans all bands at once */ IEEE80211_C_MONITOR | /* monitor mode supported */ IEEE80211_C_SHSLOT | /* short slot time supported */ IEEE80211_C_SHPREAMBLE; /* short preamble supported */ ic->ic_htcaps = IEEE80211_HTCAP_SGI20; ic->ic_htcaps |= (IEEE80211_HTCAP_SMPS_DIS << IEEE80211_HTCAP_SMPS_SHIFT); ic->ic_htcaps |= (IEEE80211_HTCAP_CBW20_40 | IEEE80211_HTCAP_SGI40); ic->ic_htcaps |= IEEE80211_HTCAP_LDPC; /* all of the gen2/gen3 cards support LDPC */ ic->ic_htxcaps = 0; ic->ic_txbfcaps = 0; ic->ic_aselcaps = 0; ic->ic_ampdu_params = (IEEE80211_AMPDU_PARAM_SS_4 | 0x3 /* 64k */); ic->ic_caps |= (IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU_SETUP_IN_HW | IEEE80211_C_TX_AMPDU | IEEE80211_C_AMSDU_IN_AMPDU); ic->ic_caps |= IEEE80211_C_SUPPORTS_VHT_EXT_NSS_BW; ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; for (i = 0; i < nitems(sc->sc_phyctxt); i++) { sc->sc_phyctxt[i].id = i; } /* IBSS channel undefined for now. */ ic->ic_ibss_chan = &ic->ic_channels[1]; ic->ic_max_rssi = IWX_MAX_DBM - IWX_MIN_DBM; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_DEBUG; ifp->if_ioctl = iwx_ioctl; ifp->if_start = iwx_start; ifp->if_watchdog = iwx_watchdog; memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); if_attach(ifp); ieee80211_ifattach(ifp, getController()); ieee80211_media_init(ifp); #if NBPFILTER > 0 iwx_radiotap_attach(sc); #endif for (i = 0; i < nitems(sc->sc_rxba_data); i++) { struct iwx_rxba_data *rxba = &sc->sc_rxba_data[i]; rxba->baid = IWX_RX_REORDER_DATA_INVALID_BAID; rxba->sc = sc; timeout_set(&rxba->session_timer, iwx_rx_ba_session_expired, rxba); timeout_set(&rxba->reorder_buf.reorder_timer, iwx_reorder_timer_expired, &rxba->reorder_buf); for (j = 0; j < nitems(rxba->entries); j++) ml_init(&rxba->entries[j].frames); } task_set(&sc->init_task, iwx_init_task, sc, "iwx_init_task"); task_set(&sc->newstate_task, iwx_newstate_task, sc, "iwx_newstate_task"); task_set(&sc->ba_task, iwx_ba_task, sc, "iwx_ba_task"); task_set(&sc->mac_ctxt_task, iwx_mac_ctxt_task, sc, "iwx_mac_ctxt_task"); task_set(&sc->chan_ctxt_task, iwx_chan_ctxt_task, sc, "iwx_chan_ctxt_task"); ic->ic_node_alloc = iwx_node_alloc; ic->ic_bgscan_start = iwx_bgscan; ic->ic_set_key = iwx_set_key; ic->ic_delete_key = iwx_delete_key; /* Override 802.11 state transition machine. */ sc->sc_newstate = ic->ic_newstate; ic->ic_newstate = iwx_newstate; ic->ic_updateprot = iwx_updateprot; ic->ic_updateslot = iwx_updateslot; ic->ic_updateedca = iwx_updateedca; ic->ic_updatedtim = iwx_updatedtim; ic->ic_ampdu_rx_start = iwx_ampdu_rx_start; ic->ic_ampdu_rx_stop = iwx_ampdu_rx_stop; ic->ic_ampdu_tx_start = iwx_ampdu_tx_start; ic->ic_ampdu_tx_stop = iwx_ampdu_tx_stop; ic->ic_update_chw = iwx_update_chw; /* * We cannot read the MAC address without loading the * firmware from disk. Postpone until mountroot is done. */ // config_mountroot(self, iwx_attach_hook); if (iwx_preinit(sc)) { goto fail5; } return true; fail5: for (i = 0; i < nitems(sc->sc_rxba_data); i++) { struct iwx_rxba_data *rxba = &sc->sc_rxba_data[i]; iwx_clear_reorder_buffer(sc, rxba); } fail4: while (--txq_i >= 0) iwx_free_tx_ring(sc, &sc->txq[txq_i]); iwx_free_rx_ring(sc, &sc->rxq); fail3: if (sc->ict_dma.vaddr != NULL) iwx_dma_contig_free(&sc->ict_dma); fail0: iwx_dma_contig_free(&sc->ctxt_info_dma); return false; } #if NBPFILTER > 0 void ItlIwx:: iwx_radiotap_attach(struct iwx_softc *sc) { bpfattach(&sc->sc_drvbpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO, sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN); sc->sc_rxtap_len = sizeof sc->sc_rxtapu; sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); sc->sc_rxtap.wr_ihdr.it_present = htole32(IWX_RX_RADIOTAP_PRESENT); sc->sc_txtap_len = sizeof sc->sc_txtapu; sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); sc->sc_txtap.wt_ihdr.it_present = htole32(IWX_TX_RADIOTAP_PRESENT); } #endif void ItlIwx:: iwx_init_task(void *arg1) { XYLog("%s\n", __FUNCTION__); struct iwx_softc *sc = (struct iwx_softc *)arg1; struct _ifnet *ifp = &sc->sc_ic.ic_if; ItlIwx *that = container_of(sc, ItlIwx, com); int s = splnet(); int generation = sc->sc_generation; int fatal = (sc->sc_flags & (IWX_FLAG_HW_ERR | IWX_FLAG_RFKILL)); // rw_enter_write(&sc->ioctl_rwl); if (generation != sc->sc_generation) { // rw_exit(&sc->ioctl_rwl); splx(s); return; } if (ifp->if_flags & IFF_RUNNING) that->iwx_stop(ifp); else sc->sc_flags &= ~IWX_FLAG_HW_ERR; if (!fatal && (ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP) that->iwx_init(ifp); // rw_exit(&sc->ioctl_rwl); splx(s); } int ItlIwx:: iwx_resume(struct iwx_softc *sc) { pcireg_t reg; /* Clear device-specific "PCI retry timeout" register (41h). */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40); pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00); if (!sc->sc_msix) { /* Hardware bug workaround. */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG); if (reg & PCI_COMMAND_INTERRUPT_DISABLE) reg &= ~PCI_COMMAND_INTERRUPT_DISABLE; pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg); } iwx_enable_rfkill_int(sc); iwx_check_rfkill(sc); return iwx_prepare_card_hw(sc); } int ItlIwx:: iwx_activate(struct iwx_softc *sc, int act) { struct _ifnet *ifp = &sc->sc_ic.ic_if; int err = 0; switch (act) { case DVACT_QUIESCE: if (ifp->if_flags & IFF_RUNNING) { // rw_enter_write(&sc->ioctl_rwl); iwx_stop(ifp); // rw_exit(&sc->ioctl_rwl); } break; case DVACT_RESUME: err = iwx_resume(sc); if (err) XYLog("%s: could not initialize hardware\n", DEVNAME(sc)); break; case DVACT_WAKEUP: /* Hardware should be up at this point. */ if (iwx_set_hw_ready(sc)) task_add(systq, &sc->init_task); break; } return 0; } ================================================ FILE: itlwm/hal_iwx/ItlIwx.hpp ================================================ /* * 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. */ /* $OpenBSD: if_iwx.c,v 1.43 2020/08/02 11:11:07 stsp Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh * Author: Stefan Sperling * Copyright (c) 2014 Fixup Software Ltd. * Copyright (c) 2017, 2019, 2020 Stefan Sperling * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * ****************************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***************************************************************************** */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _ITLWMX_H #define _ITLWMX_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include "if_iwxreg.h" #include "if_iwxvar.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include class ItlIwx : public ItlHalService, ItlDriverInfo, ItlDriverController { OSDeclareDefaultStructors(ItlIwx) public: //kext void free() override; virtual bool attach(IOPCIDevice *device) override; virtual void detach(IOPCIDevice *device) override; IOReturn enable(IONetworkInterface *netif) override; IOReturn disable(IONetworkInterface *netif) override; virtual struct ieee80211com *get80211Controller() override; static bool intrFilter(OSObject *object, IOFilterInterruptEventSource *src); static IOReturn _iwx_start_task(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3); virtual ItlDriverInfo *getDriverInfo() override; virtual ItlDriverController *getDriverController() override; //driver info virtual const char *getFirmwareVersion() override; virtual int16_t getBSSNoise() override; virtual bool is5GBandSupport() override; virtual int getTxNSS() override; virtual const char *getFirmwareName() override; virtual UInt32 supportedFeatures() override; virtual const char *getFirmwareCountryCode() override; virtual uint32_t getTxQueueSize() override; //driver controller virtual void clearScanningFlags() override; virtual IOReturn setMulticastList(IOEthernetAddress *addr, int count) override; void releaseAll(); void joinSSID(const char *ssid, const char *pwd); //utils static void *mallocarray(size_t, size_t, int, int); // static void onLoadFW(OSKextRequestTag requestTag, OSReturn result, const void *resourceData, uint32_t resourceDataLength, void *context); uint8_t iwx_lookup_cmd_ver(struct iwx_softc *, uint8_t, uint8_t); uint8_t iwx_lookup_notif_ver(struct iwx_softc *, uint8_t, uint8_t); uint32_t iwx_lmac_id(struct iwx_softc *, ieee80211_channel *); int iwx_store_cscheme(struct iwx_softc *, uint8_t *, size_t); int iwx_alloc_fw_monitor_block(struct iwx_softc *, uint8_t, uint8_t); int iwx_alloc_fw_monitor(struct iwx_softc *, uint8_t); int iwx_apply_debug_destination(struct iwx_softc *); int iwx_ctxt_info_init(struct iwx_softc *, const struct iwx_fw_sects *); int iwx_ctxt_info_gen3_init(struct iwx_softc *, const struct iwx_fw_sects *); void iwx_ctxt_info_free_fw_img(struct iwx_softc *sc); int iwx_ctxt_info_alloc_dma(struct iwx_softc *sc, const struct iwx_fw_onesect *sec, struct iwx_dma_info *dram); void iwx_ctxt_info_free_paging(struct iwx_softc *); int iwx_get_num_sections(const struct iwx_fw_sects *fws, int start); int iwx_init_fw_sec(struct iwx_softc *, const struct iwx_fw_sects *, struct iwx_context_info_dram *); void iwx_fw_version_str(char *, size_t, uint32_t, uint32_t, uint32_t); int iwx_firmware_store_section(struct iwx_softc *, enum iwx_ucode_type, uint8_t *, size_t); int iwx_set_default_calib(struct iwx_softc *, const void *); void iwx_fw_info_free(struct iwx_fw_info *); void iwx_pnvm_free(struct iwx_fw_info *); int iwx_read_firmware(struct iwx_softc *); int iwx_read_pnvm(struct iwx_softc *); int iwx_load_pnvm(struct iwx_softc *); int iwx_pnvm_handle_section(struct iwx_softc *, const uint8_t *, size_t); uint32_t iwx_read_prph_unlocked(struct iwx_softc *, uint32_t); uint32_t iwx_read_prph(struct iwx_softc *, uint32_t); uint32_t iwx_read_umac_prph(struct iwx_softc *, uint32_t); void iwx_write_prph(struct iwx_softc *, uint32_t, uint32_t); void iwx_write_prph_unlocked(struct iwx_softc *, uint32_t, uint32_t); void iwx_write_umac_prph(struct iwx_softc *, uint32_t, uint32_t); void iwx_write_prph64(struct iwx_softc *sc, uint64_t addr, uint64_t val); int iwx_read_mem(struct iwx_softc *, uint32_t, void *, int); int iwx_write_mem(struct iwx_softc *, uint32_t, const void *, int); int iwx_write_mem32(struct iwx_softc *, uint32_t, uint32_t); int iwx_poll_bit(struct iwx_softc *, int, uint32_t, uint32_t, int); int iwx_nic_lock(struct iwx_softc *); void iwx_nic_assert_locked(struct iwx_softc *); void iwx_nic_unlock(struct iwx_softc *); void iwx_set_bits_mask_prph(struct iwx_softc *, uint32_t, uint32_t, uint32_t); void iwx_set_bits_prph(struct iwx_softc *, uint32_t, uint32_t); void iwx_clear_bits_prph(struct iwx_softc *, uint32_t, uint32_t); int iwx_dma_contig_alloc(bus_dma_tag_t, struct iwx_dma_info *, bus_size_t, bus_size_t); void iwx_dma_contig_free(struct iwx_dma_info *); int iwx_alloc_rx_ring(struct iwx_softc *, struct iwx_rx_ring *); void iwx_disable_rx_dma(struct iwx_softc *); void iwx_reset_rx_ring(struct iwx_softc *, struct iwx_rx_ring *); void iwx_free_rx_ring(struct iwx_softc *, struct iwx_rx_ring *); void iwx_tx_ring_init(struct iwx_softc *, struct iwx_tx_ring *, int); int iwx_alloc_tx_ring(struct iwx_softc *, struct iwx_tx_ring *, int); void iwx_reset_tx_ring(struct iwx_softc *, struct iwx_tx_ring *); void iwx_free_tx_ring(struct iwx_softc *, struct iwx_tx_ring *); void iwx_enable_rfkill_int(struct iwx_softc *); int iwx_check_rfkill(struct iwx_softc *); void iwx_enable_interrupts(struct iwx_softc *); void iwx_enable_fwload_interrupt(struct iwx_softc *); void iwx_restore_interrupts(struct iwx_softc *); void iwx_disable_interrupts(struct iwx_softc *); void iwx_ict_reset(struct iwx_softc *); int iwx_set_hw_ready(struct iwx_softc *); int iwx_prepare_card_hw(struct iwx_softc *); void iwx_force_power_gating(struct iwx_softc *); void iwx_clear_persistence_bit(struct iwx_softc *); void iwx_apm_config(struct iwx_softc *); int iwx_apm_init(struct iwx_softc *); void iwx_apm_stop(struct iwx_softc *); int iwx_allow_mcast(struct iwx_softc *); void iwx_init_msix_hw(struct iwx_softc *); void iwx_conf_msix_hw(struct iwx_softc *, int); int iwx_start_hw(struct iwx_softc *); void iwx_stop_device(struct iwx_softc *); void iwx_nic_config(struct iwx_softc *); int iwx_nic_rx_init(struct iwx_softc *); int iwx_nic_init(struct iwx_softc *); int iwx_enable_txq(struct iwx_softc *, int, int, int, int); int iwx_tvqm_alloc_txq(struct iwx_softc *, int, int); int iwx_tvqm_enable_txq(struct iwx_softc *, int, int, uint32_t); void iwx_post_alive(struct iwx_softc *); int iwx_send_time_event_cmd(struct iwx_softc *sc, const struct iwx_time_event_cmd *cmd); void iwx_protect_session(struct iwx_softc *, struct iwx_node *, uint32_t, uint32_t); int iwx_schedule_protect_session(struct iwx_softc *, struct iwx_node *, uint32_t); int iwx_cancel_session_protection(struct iwx_softc *, struct iwx_node *); void iwx_unprotect_session(struct iwx_softc *, struct iwx_node *); uint8_t iwx_fw_valid_tx_ant(struct iwx_softc *sc); uint8_t iwx_fw_valid_rx_ant(struct iwx_softc *sc); void iwx_init_channel_map(struct iwx_softc *, uint16_t *, uint32_t *, int); void iwx_setup_ht_rates(struct iwx_softc *); void iwx_setup_vht_rates(struct iwx_softc *); void iwx_setup_he_rates(struct iwx_softc *); int iwx_mimo_enabled(struct iwx_softc *); static void iwx_mac_ctxt_task(void *); static void iwx_chan_ctxt_task(void *); static void iwx_updateprot(struct ieee80211com *); static void iwx_updateslot(struct ieee80211com *); static void iwx_updateedca(struct ieee80211com *); static void iwx_updatedtim(struct ieee80211com *); void iwx_init_reorder_buffer(struct iwx_reorder_buffer *, uint16_t, uint16_t); void iwx_clear_reorder_buffer(struct iwx_softc *, struct iwx_rxba_data *); static int iwx_ampdu_rx_start(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwx_ampdu_rx_stop(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwx_rx_ba_session_expired(void *); static void iwx_reorder_timer_expired(void *); static void iwx_update_chw(struct ieee80211com *); void iwx_sta_rx_agg(struct iwx_softc *, struct ieee80211_node *, uint8_t, uint16_t, uint16_t, int, int); static int iwx_ampdu_tx_start(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwx_ampdu_tx_stop(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwx_ba_task(void *); int iwx_set_mac_addr_from_csr(struct iwx_softc *, struct iwx_nvm_data *); int iwx_is_valid_mac_addr(const uint8_t *); int iwx_nvm_get(struct iwx_softc *); int iwx_load_firmware(struct iwx_softc *); void iwx_set_ltr(struct iwx_softc *); int iwx_start_fw(struct iwx_softc *); int iwx_send_tx_ant_cfg(struct iwx_softc *, uint8_t); int iwx_send_phy_cfg_cmd(struct iwx_softc *); int iwx_load_ucode_wait_alive(struct iwx_softc *); int iwx_send_dqa_cmd(struct iwx_softc *); int iwx_run_init_mvm_ucode(struct iwx_softc *, int); int iwx_config_ltr(struct iwx_softc *); void iwx_update_rx_desc(struct iwx_softc *, struct iwx_rx_ring *, int); int iwx_rx_addbuf(struct iwx_softc *, int, int); int iwx_rxmq_get_signal_strength(struct iwx_softc *, struct iwx_rx_mpdu_desc *); void iwx_rx_rx_phy_cmd(struct iwx_softc *, struct iwx_rx_packet *, struct iwx_rx_data *); int iwx_get_noise(const uint8_t *); int iwx_rx_hwdecrypt(struct iwx_softc *, mbuf_t, uint32_t, struct ieee80211_rxinfo *); int iwx_ccmp_decap(struct iwx_softc *, mbuf_t, struct ieee80211_node *, struct ieee80211_rxinfo *); void iwx_rx_frame(struct iwx_softc *, mbuf_t, int, uint32_t, int, int, uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *); void iwx_rx_mpdu_mq(struct iwx_softc *sc, mbuf_t m, void *pktdata, size_t maxlen, struct mbuf_list *ml); void iwx_rx_tx_cmd_single(struct iwx_softc *, struct iwx_rx_packet *, struct iwx_tx_data *); void iwx_txd_done(struct iwx_softc *sc, struct iwx_tx_data *txd); void iwx_clear_oactive(struct iwx_softc *sc, struct iwx_tx_ring *ring); void iwx_ampdu_txq_advance(struct iwx_softc *sc, struct iwx_tx_ring *ring, int idx); void iwx_rx_tx_ba_notif(struct iwx_softc *sc, struct iwx_rx_packet *pkt, struct iwx_rx_data *data); void iwx_rx_tx_cmd(struct iwx_softc *, struct iwx_rx_packet *, struct iwx_rx_data *); void iwx_rx_bmiss(struct iwx_softc *, struct iwx_rx_packet *, struct iwx_rx_data *); int iwx_binding_cmd(struct iwx_softc *, struct iwx_node *, uint32_t); int iwx_phy_ctxt_cmd_uhb(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t, uint8_t, uint32_t, uint32_t); int iwx_phy_ctxt_cmd_v3(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t, uint8_t, uint32_t, uint32_t); int iwx_phy_ctxt_cmd(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t, uint8_t, uint32_t, uint32_t); int iwx_send_cmd(struct iwx_softc *, struct iwx_host_cmd *); int iwx_send_cmd_pdu(struct iwx_softc *, uint32_t, uint32_t, uint16_t, const void *); int iwx_send_cmd_status(struct iwx_softc *, struct iwx_host_cmd *, uint32_t *); int iwx_send_cmd_pdu_status(struct iwx_softc *, uint32_t, uint16_t, const void *, uint32_t *); void iwx_free_resp(struct iwx_softc *, struct iwx_host_cmd *); void iwx_cmd_done(struct iwx_softc *, int, int, int); const struct iwx_rate *iwx_tx_fill_cmd(struct iwx_softc *, struct iwx_node *, struct ieee80211_frame *, uint32_t *, uint32_t *); uint32_t iwx_get_tx_ant(struct iwx_softc *sc, struct ieee80211_node *ni, const struct iwx_rate *rinfo, int type, struct ieee80211_frame *wh); void iwx_toggle_tx_ant(struct iwx_softc *sc, uint8_t *ant); void iwx_tx_update_byte_tbl(struct iwx_softc *, struct iwx_tx_ring *, int, uint16_t, uint16_t); int iwx_tx(struct iwx_softc *, mbuf_t, struct ieee80211_node *, int); int iwx_flush_sta_tids(struct iwx_softc *, int, uint16_t); int iwx_flush_sta(struct iwx_softc *, struct iwx_node *); int iwx_drain_sta(struct iwx_softc *sc, struct iwx_node *, int); int iwx_beacon_filter_send_cmd(struct iwx_softc *, struct iwx_beacon_filter_cmd *); int iwx_update_beacon_abort(struct iwx_softc *, struct iwx_node *, int); void iwx_power_build_cmd(struct iwx_softc *, struct iwx_node *, struct iwx_mac_power_cmd *); int iwx_power_mac_update_mode(struct iwx_softc *, struct iwx_node *); int iwx_power_update_device(struct iwx_softc *); int iwx_enable_beacon_filter(struct iwx_softc *, struct iwx_node *); int iwx_disable_beacon_filter(struct iwx_softc *); int iwx_add_sta_cmd(struct iwx_softc *, struct iwx_node *, int); int iwx_add_aux_sta(struct iwx_softc *); int iwx_rm_sta_cmd(struct iwx_softc *, struct iwx_node *); int iwx_rm_sta(struct iwx_softc *, struct iwx_node *); uint8_t iwx_umac_scan_fill_channels(struct iwx_softc *sc, struct iwx_scan_channel_cfg_umac *chan, int n_ssids, int bgscan); int iwx_fill_probe_req_v1(struct iwx_softc *sc, struct iwx_scan_probe_req_v1 *preq1); int iwx_fill_probe_req(struct iwx_softc *, struct iwx_scan_probe_req *); int iwx_config_umac_scan(struct iwx_softc *); int iwx_config_legacy_umac_scan(struct iwx_softc *); int iwx_umac_scan_size(struct iwx_softc *sc); struct iwx_scan_umac_chan_param *iwx_get_scan_req_umac_chan_param(struct iwx_softc *sc, struct iwx_scan_req_umac *req); void *iwx_get_scan_req_umac_data(struct iwx_softc *sc, struct iwx_scan_req_umac *req); int iwx_umac_scan(struct iwx_softc *, int); int iwx_umac_scan_v12(struct iwx_softc *, int); int iwx_umac_scan_v14(struct iwx_softc *, int); void iwx_mcc_update(struct iwx_softc *, struct iwx_mcc_chub_notif *); uint8_t iwx_ridx2rate(struct ieee80211_rateset *, int); int iwx_rval2ridx(int); int iwx_rate2idx(int); void iwx_ack_rates(struct iwx_softc *, struct iwx_node *, int *, int *); void iwx_mac_ctxt_cmd_common(struct iwx_softc *, struct iwx_node *, struct iwx_mac_ctx_cmd *, uint32_t); void iwx_mac_ctxt_cmd_fill_sta(struct iwx_softc *, struct iwx_node *, struct iwx_mac_data_sta *, int); int iwx_mac_ctxt_cmd(struct iwx_softc *, struct iwx_node *, uint32_t, int); int iwx_clear_statistics(struct iwx_softc *); int iwx_update_quotas(struct iwx_softc *, struct iwx_node *, int); void iwx_add_task(struct iwx_softc *, struct taskq *, struct task *); void iwx_del_task(struct iwx_softc *, struct taskq *, struct task *); int iwx_scan(struct iwx_softc *); static int iwx_bgscan(struct ieee80211com *); int iwx_umac_scan_abort(struct iwx_softc *); int iwx_scan_abort(struct iwx_softc *); int iwx_rs_rval2idx(uint8_t); uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ieee80211_node *, int); uint16_t iwx_rs_fw_get_config_flags(struct iwx_softc *sc); int iwx_rs_init(struct iwx_softc *, struct iwx_node *, bool update); void iwx_rs_update(struct iwx_softc *sc, struct iwx_tlc_update_notif *notif); int iwx_enable_mgmt_queue(struct iwx_softc *); int iwx_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *, struct ieee80211_channel *, uint8_t, uint8_t, uint32_t); int iwx_auth(struct iwx_softc *); int iwx_deauth(struct iwx_softc *); int iwx_run(struct iwx_softc *); int iwx_run_stop(struct iwx_softc *); static struct ieee80211_node *iwx_node_alloc(struct ieee80211com *); static int iwx_set_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); static void iwx_delete_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); int iwx_media_change(struct _ifnet *); static void iwx_newstate_task(void *); static int iwx_newstate(struct ieee80211com *, enum ieee80211_state, int); void iwx_endscan(struct iwx_softc *); void iwx_fill_sf_command(struct iwx_softc *, struct iwx_sf_cfg_cmd *, struct ieee80211_node *); int iwx_sf_config(struct iwx_softc *, int); int iwx_send_bt_init_conf(struct iwx_softc *); int iwx_send_soc_conf(struct iwx_softc *); int iwx_send_update_mcc_cmd(struct iwx_softc *, const char *); int iwx_send_temp_report_ths_cmd(struct iwx_softc *); int iwx_init_hw(struct iwx_softc *); int iwx_init(struct _ifnet *); static void iwx_start(struct _ifnet *); void iwx_stop(struct _ifnet *); static void iwx_watchdog(struct _ifnet *); static int iwx_ioctl(struct _ifnet *, u_long, caddr_t); const char *iwx_desc_lookup(uint32_t); void iwx_nic_error(struct iwx_softc *); void iwx_nic_umac_error(struct iwx_softc *); void iwx_flip_address(uint8_t *); int iwx_detect_duplicate(struct iwx_softc *, mbuf_t, struct iwx_rx_mpdu_desc *, struct ieee80211_rxinfo *); int iwx_is_sn_less(uint16_t, uint16_t, uint16_t); void iwx_release_frames(struct iwx_softc *, struct ieee80211_node *, struct iwx_rxba_data *, struct iwx_reorder_buffer *, uint16_t, struct mbuf_list *); int iwx_oldsn_workaround(struct iwx_softc *, struct ieee80211_node *, int, struct iwx_reorder_buffer *, uint32_t, uint32_t); int iwx_rx_reorder(struct iwx_softc *, mbuf_t, int, struct iwx_rx_mpdu_desc *, int, int, uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *); int iwx_rx_pkt_valid(struct iwx_rx_packet *); void iwx_rx_pkt(struct iwx_softc *, struct iwx_rx_data *, struct mbuf_list *); void iwx_notif_intr(struct iwx_softc *); static int iwx_intr(OSObject *object, IOInterruptEventSource* sender, int count); static int iwx_intr_msix(OSObject *object, IOInterruptEventSource* sender, int count); static int iwx_match(IOPCIDevice *); int iwx_preinit(struct iwx_softc *); void iwx_attach_hook(struct device *); bool iwx_attach(struct iwx_softc *, struct pci_attach_args *); static void iwx_init_task(void *); int iwx_activate(struct iwx_softc *, int); int iwx_resume(struct iwx_softc *); public: IOInterruptEventSource* fInterrupt; struct pci_attach_args pci; struct iwx_softc com; }; #endif ================================================ FILE: itlwm/hal_iwx/if_iwxreg.h ================================================ /* * 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. */ /* $OpenBSD: if_iwxreg.h,v 1.17 2020/08/01 16:14:05 stsp Exp $ */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * ****************************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***************************************************************************** */ /* maximmum number of DRAM map entries supported by FW */ #define IWX_MAX_DRAM_ENTRY 64 #define IWX_CSR_CTXT_INFO_BA 0x40 #define IWX_CSR_CTXT_INFO_BOOT_CTRL 0x0 #define IWX_CSR_CTXT_INFO_ADDR 0x118 #define IWX_CSR_IML_DATA_ADDR 0x120 #define IWX_CSR_IML_SIZE_ADDR 0x128 #define IWX_CSR_IML_RESP_ADDR 0x12c /* Set bit for enabling automatic function boot */ #define IWX_CSR_AUTO_FUNC_BOOT_ENA (1 << 1) /* Set bit for initiating function boot */ #define IWX_CSR_AUTO_FUNC_INIT (1 << 7) /** * enum iwx_context_info_flags - Context information control flags * @IWX_CTXT_INFO_AUTO_FUNC_INIT: If set, FW will not wait before interrupting * the init done for driver command that configures several system modes * @IWX_CTXT_INFO_EARLY_DEBUG: enable early debug * @IWX_CTXT_INFO_ENABLE_CDMP: enable core dump * @IWX_CTXT_INFO_RB_CB_SIZE_POS: position of the RBD Cyclic Buffer Size * exponent, the actual size is 2**value, valid sizes are 8-2048. * The value is four bits long. Maximum valid exponent is 12 * @IWX_CTXT_INFO_TFD_FORMAT_LONG: use long TFD Format (the * default is short format - not supported by the driver) * @IWX_CTXT_INFO_RB_SIZE_POS: RB size position * (values are IWX_CTXT_INFO_RB_SIZE_*K) * @IWX_CTXT_INFO_RB_SIZE_1K: Value for 1K RB size * @IWX_CTXT_INFO_RB_SIZE_2K: Value for 2K RB size * @IWX_CTXT_INFO_RB_SIZE_4K: Value for 4K RB size * @IWX_CTXT_INFO_RB_SIZE_8K: Value for 8K RB size * @IWX_CTXT_INFO_RB_SIZE_12K: Value for 12K RB size * @IWX_CTXT_INFO_RB_SIZE_16K: Value for 16K RB size * @IWX_CTXT_INFO_RB_SIZE_20K: Value for 20K RB size * @IWX_CTXT_INFO_RB_SIZE_24K: Value for 24K RB size * @IWX_CTXT_INFO_RB_SIZE_28K: Value for 28K RB size * @IWX_CTXT_INFO_RB_SIZE_32K: Value for 32K RB size */ enum iwx_context_info_flags { IWX_CTXT_INFO_AUTO_FUNC_INIT = (1 << 0), IWX_CTXT_INFO_EARLY_DEBUG = (1 << 1), IWX_CTXT_INFO_ENABLE_CDMP = (1 << 2), IWX_CTXT_INFO_RB_CB_SIZE_POS = 4, IWX_CTXT_INFO_TFD_FORMAT_LONG = (1 << 8), IWX_CTXT_INFO_RB_SIZE_POS = 9, IWX_CTXT_INFO_RB_SIZE_1K = 0x1, IWX_CTXT_INFO_RB_SIZE_2K = 0x2, IWX_CTXT_INFO_RB_SIZE_4K = 0x4, IWX_CTXT_INFO_RB_SIZE_8K = 0x8, IWX_CTXT_INFO_RB_SIZE_12K = 0x9, IWX_CTXT_INFO_RB_SIZE_16K = 0xa, IWX_CTXT_INFO_RB_SIZE_20K = 0xb, IWX_CTXT_INFO_RB_SIZE_24K = 0xc, IWX_CTXT_INFO_RB_SIZE_28K = 0xd, IWX_CTXT_INFO_RB_SIZE_32K = 0xe, }; /* * struct iwx_context_info_version - version structure * @mac_id: SKU and revision id * @version: context information version id * @size: the size of the context information in DWs */ struct iwx_context_info_version { uint16_t mac_id; uint16_t version; uint16_t size; uint16_t reserved; } __packed; /* * struct iwx_context_info_control - version structure * @control_flags: context information flags see &enum iwx_context_info_flags */ struct iwx_context_info_control { uint32_t control_flags; uint32_t reserved; } __packed; /* * struct iwx_context_info_dram - images DRAM map * each entry in the map represents a DRAM chunk of up to 32 KB * @umac_img: UMAC image DRAM map * @lmac_img: LMAC image DRAM map * @virtual_img: paged image DRAM map */ struct iwx_context_info_dram { uint64_t umac_img[IWX_MAX_DRAM_ENTRY]; uint64_t lmac_img[IWX_MAX_DRAM_ENTRY]; uint64_t virtual_img[IWX_MAX_DRAM_ENTRY]; } __packed; /* * struct iwx_context_info_rbd_cfg - RBDs configuration * @free_rbd_addr: default queue free RB CB base address * @used_rbd_addr: default queue used RB CB base address * @status_wr_ptr: default queue used RB status write pointer */ struct iwx_context_info_rbd_cfg { uint64_t free_rbd_addr; uint64_t used_rbd_addr; uint64_t status_wr_ptr; } __packed; /* * struct iwx_context_info_hcmd_cfg - command queue configuration * @cmd_queue_addr: address of command queue * @cmd_queue_size: number of entries */ struct iwx_context_info_hcmd_cfg { uint64_t cmd_queue_addr; uint8_t cmd_queue_size; uint8_t reserved[7]; } __packed; /* * struct iwx_context_info_dump_cfg - Core Dump configuration * @core_dump_addr: core dump (debug DRAM address) start address * @core_dump_size: size, in DWs */ struct iwx_context_info_dump_cfg { uint64_t core_dump_addr; uint32_t core_dump_size; uint32_t reserved; } __packed; /* * struct iwx_context_info_pnvm_cfg - platform NVM data configuration * @platform_nvm_addr: Platform NVM data start address * @platform_nvm_size: size in DWs */ struct iwx_context_info_pnvm_cfg { uint64_t platform_nvm_addr; uint32_t platform_nvm_size; uint32_t reserved; } __packed; /* * struct iwx_context_info_early_dbg_cfg - early debug configuration for * dumping DRAM addresses * @early_debug_addr: early debug start address * @early_debug_size: size in DWs */ struct iwx_context_info_early_dbg_cfg { uint64_t early_debug_addr; uint32_t early_debug_size; uint32_t reserved; } __packed; /* * struct iwx_context_info - device INIT configuration * @version: version information of context info and HW * @control: control flags of FH configurations * @rbd_cfg: default RX queue configuration * @hcmd_cfg: command queue configuration * @dump_cfg: core dump data * @edbg_cfg: early debug configuration * @pnvm_cfg: platform nvm configuration * @dram: firmware image addresses in DRAM */ struct iwx_context_info { struct iwx_context_info_version version; struct iwx_context_info_control control; uint64_t reserved0; struct iwx_context_info_rbd_cfg rbd_cfg; struct iwx_context_info_hcmd_cfg hcmd_cfg; uint32_t reserved1[4]; struct iwx_context_info_dump_cfg dump_cfg; struct iwx_context_info_early_dbg_cfg edbg_cfg; struct iwx_context_info_pnvm_cfg pnvm_cfg; uint32_t reserved2[16]; struct iwx_context_info_dram dram; uint32_t reserved3[16]; } __packed; /** * enum iwx_prph_scratch_flags - PRPH scratch control flags * @IWL_PRPH_SCRATCH_EARLY_DEBUG_EN: enable early debug conf * @IWL_PRPH_SCRATCH_EDBG_DEST_DRAM: use DRAM, with size allocated * in hwm config. * @IWL_PRPH_SCRATCH_EDBG_DEST_INTERNAL: use buffer on SRAM * @IWL_PRPH_SCRATCH_EDBG_DEST_ST_ARBITER: use st arbiter, mainly for * multicomm. * @IWL_PRPH_SCRATCH_EDBG_DEST_TB22DTF: route debug data to SoC HW * @IWL_PRPH_SCTATCH_RB_SIZE_4K: Use 4K RB size (the default is 2K) * @IWL_PRPH_SCRATCH_MTR_MODE: format used for completion - 0: for * completion descriptor, 1 for responses (legacy) * @IWL_PRPH_SCRATCH_MTR_FORMAT: a mask for the size of the tfd. * There are 4 optional values: 0: 16 bit, 1: 32 bit, 2: 64 bit, * 3: 256 bit. * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_MASK: RB size full information, ignored * by older firmware versions, so set IWL_PRPH_SCRATCH_RB_SIZE_4K * appropriately; use the below values for this. * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_8K: 8kB RB size * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_12K: 12kB RB size */ enum iwx_prph_scratch_flags { IWX_PRPH_SCRATCH_EARLY_DEBUG_EN = BIT(4), IWX_PRPH_SCRATCH_EDBG_DEST_DRAM = BIT(8), IWX_PRPH_SCRATCH_EDBG_DEST_INTERNAL = BIT(9), IWX_PRPH_SCRATCH_EDBG_DEST_ST_ARBITER = BIT(10), IWX_PRPH_SCRATCH_EDBG_DEST_TB22DTF = BIT(11), IWX_PRPH_SCRATCH_RB_SIZE_4K = BIT(16), IWX_PRPH_SCRATCH_MTR_MODE = BIT(17), IWX_PRPH_SCRATCH_MTR_FORMAT = BIT(18) | BIT(19), IWX_PRPH_SCRATCH_RB_SIZE_EXT_MASK = 0xf << 20, IWX_PRPH_SCRATCH_RB_SIZE_EXT_8K = 8 << 20, IWX_PRPH_SCRATCH_RB_SIZE_EXT_12K = 9 << 20, }; /** * enum iwx_ini_cfg_state * @IWX_INI_CFG_STATE_NOT_LOADED: no debug cfg was given * @IWX_INI_CFG_STATE_LOADED: debug cfg was found and loaded * @IWX_INI_CFG_STATE_CORRUPTED: debug cfg was found and some of the TLVs * are corrupted. The rest of the debug TLVs will still be used */ enum iwx_ini_cfg_state { IWX_INI_CFG_STATE_NOT_LOADED, IWX_INI_CFG_STATE_LOADED, IWX_INI_CFG_STATE_CORRUPTED, }; /** * enum iwx_fw_ini_buffer_location * * @IWX_FW_INI_LOCATION_INVALID: invalid * @IWX_FW_INI_LOCATION_SRAM_PATH: SRAM location * @IWX_FW_INI_LOCATION_DRAM_PATH: DRAM location * @IWX_FW_INI_LOCATION_NPK_PATH: NPK location */ enum iwx_fw_ini_buffer_location { IWX_FW_INI_LOCATION_INVALID, IWX_FW_INI_LOCATION_SRAM_PATH, IWX_FW_INI_LOCATION_DRAM_PATH, IWX_FW_INI_LOCATION_NPK_PATH, IWX_FW_INI_LOCATION_NUM, }; /* FW_DEBUG_TLV_BUFFER_LOCATION_E_VER_1 */ /** * enum iwx_prph_scratch_mtr_format - tfd size configuration * @IWL_PRPH_MTR_FORMAT_16B: 16 bit tfd * @IWL_PRPH_MTR_FORMAT_32B: 32 bit tfd * @IWL_PRPH_MTR_FORMAT_64B: 64 bit tfd * @IWL_PRPH_MTR_FORMAT_256B: 256 bit tfd */ enum iwx_prph_scratch_mtr_format { IWX_PRPH_MTR_FORMAT_16B = 0x0, IWX_PRPH_MTR_FORMAT_32B = 0x40000, IWX_PRPH_MTR_FORMAT_64B = 0x80000, IWX_PRPH_MTR_FORMAT_256B = 0xC0000, }; /* * struct iwx_prph_scratch_version - version structure * @mac_id: SKU and revision id * @version: prph scratch information version id * @size: the size of the context information in DWs * @reserved: reserved */ struct iwx_prph_scratch_version { __le16 mac_id; __le16 version; __le16 size; __le16 reserved; } __packed; /* PERIPH_SCRATCH_VERSION_S */ /* * struct iwx_prph_scratch_control - control structure * @control_flags: context information flags see &enum iwl_prph_scratch_flags * @reserved: reserved */ struct iwx_prph_scratch_control { __le32 control_flags; __le32 reserved; } __packed; /* PERIPH_SCRATCH_CONTROL_S */ /* * struct iwx_prph_scratch_pnvm_cfg - ror config * @pnvm_base_addr: PNVM start address * @pnvm_size: PNVM size in DWs * @reserved: reserved */ struct iwx_prph_scratch_pnvm_cfg { __le64 pnvm_base_addr; __le32 pnvm_size; __le32 reserved; } __packed; /* PERIPH_SCRATCH_PNVM_CFG_S */ /* * struct iwx_prph_scratch_hwm_cfg - hwm config * @hwm_base_addr: hwm start address * @hwm_size: hwm size in DWs * @reserved: reserved */ struct iwx_prph_scratch_hwm_cfg { __le64 hwm_base_addr; __le32 hwm_size; __le32 reserved; } __packed; /* PERIPH_SCRATCH_HWM_CFG_S */ /* * struct iwx_prph_scratch_rbd_cfg - RBDs configuration * @free_rbd_addr: default queue free RB CB base address * @reserved: reserved */ struct iwx_prph_scratch_rbd_cfg { __le64 free_rbd_addr; __le32 reserved; } __packed; /* PERIPH_SCRATCH_RBD_CFG_S */ /* * struct iwx_prph_scratch_ctrl_cfg - prph scratch ctrl and config * @version: version information of context info and HW * @control: control flags of FH configurations * @pnvm_cfg: ror configuration * @hwm_cfg: hwm configuration * @rbd_cfg: default RX queue configuration */ struct iwx_prph_scratch_ctrl_cfg { struct iwx_prph_scratch_version version; struct iwx_prph_scratch_control control; struct iwx_prph_scratch_pnvm_cfg pnvm_cfg; struct iwx_prph_scratch_hwm_cfg hwm_cfg; struct iwx_prph_scratch_rbd_cfg rbd_cfg; } __packed; /* PERIPH_SCRATCH_CTRL_CFG_S */ /* * struct iwx_prph_scratch - peripheral scratch mapping * @ctrl_cfg: control and configuration of prph scratch * @dram: firmware images addresses in DRAM * @reserved: reserved */ struct iwx_prph_scratch { struct iwx_prph_scratch_ctrl_cfg ctrl_cfg; __le32 reserved[16]; struct iwx_context_info_dram dram; } __packed; /* PERIPH_SCRATCH_S */ /* * struct iwx_prph_info - peripheral information * @boot_stage_mirror: reflects the value in the Boot Stage CSR register * @ipc_status_mirror: reflects the value in the IPC Status CSR register * @sleep_notif: indicates the peripheral sleep status * @reserved: reserved */ struct iwx_prph_info { __le32 boot_stage_mirror; __le32 ipc_status_mirror; __le32 sleep_notif; __le32 reserved; } __packed; /* PERIPH_INFO_S */ /* * struct iwx_context_info_gen3 - device INIT configuration * @version: version of the context information * @size: size of context information in DWs * @config: context in which the peripheral would execute - a subset of * capability csr register published by the peripheral * @prph_info_base_addr: the peripheral information structure start address * @cr_head_idx_arr_base_addr: the completion ring head index array * start address * @tr_tail_idx_arr_base_addr: the transfer ring tail index array * start address * @cr_tail_idx_arr_base_addr: the completion ring tail index array * start address * @tr_head_idx_arr_base_addr: the transfer ring head index array * start address * @cr_idx_arr_size: number of entries in the completion ring index array * @tr_idx_arr_size: number of entries in the transfer ring index array * @mtr_base_addr: the message transfer ring start address * @mcr_base_addr: the message completion ring start address * @mtr_size: number of entries which the message transfer ring can hold * @mcr_size: number of entries which the message completion ring can hold * @mtr_doorbell_vec: the doorbell vector associated with the message * transfer ring * @mcr_doorbell_vec: the doorbell vector associated with the message * completion ring * @mtr_msi_vec: the MSI which shall be generated by the peripheral after * completing a transfer descriptor in the message transfer ring * @mcr_msi_vec: the MSI which shall be generated by the peripheral after * completing a completion descriptor in the message completion ring * @mtr_opt_header_size: the size of the optional header in the transfer * descriptor associated with the message transfer ring in DWs * @mtr_opt_footer_size: the size of the optional footer in the transfer * descriptor associated with the message transfer ring in DWs * @mcr_opt_header_size: the size of the optional header in the completion * descriptor associated with the message completion ring in DWs * @mcr_opt_footer_size: the size of the optional footer in the completion * descriptor associated with the message completion ring in DWs * @msg_rings_ctrl_flags: message rings control flags * @prph_info_msi_vec: the MSI which shall be generated by the peripheral * after updating the Peripheral Information structure * @prph_scratch_base_addr: the peripheral scratch structure start address * @prph_scratch_size: the size of the peripheral scratch structure in DWs * @reserved: reserved */ struct iwx_context_info_gen3 { __le16 version; __le16 size; __le32 config; __le64 prph_info_base_addr; __le64 cr_head_idx_arr_base_addr; __le64 tr_tail_idx_arr_base_addr; __le64 cr_tail_idx_arr_base_addr; __le64 tr_head_idx_arr_base_addr; __le16 cr_idx_arr_size; __le16 tr_idx_arr_size; __le64 mtr_base_addr; __le64 mcr_base_addr; __le16 mtr_size; __le16 mcr_size; __le16 mtr_doorbell_vec; __le16 mcr_doorbell_vec; __le16 mtr_msi_vec; __le16 mcr_msi_vec; u8 mtr_opt_header_size; u8 mtr_opt_footer_size; u8 mcr_opt_header_size; u8 mcr_opt_footer_size; __le16 msg_rings_ctrl_flags; __le16 prph_info_msi_vec; __le64 prph_scratch_base_addr; __le32 prph_scratch_size; __le32 reserved; } __packed; /* IPC_CONTEXT_INFO_S */ #define IWX_MQ_RX_TABLE_SIZE 512 /* cb size is the exponent */ #define IWX_RX_QUEUE_CB_SIZE(x) ((sizeof(x) <= 4) ? (_fls(x) - 1) : (flsl(x) - 1)) #define GEN3_UMAC_PRPH_OFFSET 0x300000 /** * struct iwx_fw_ini_header - Common Header for all ini debug TLV's structures * * @version: TLV version * @domain: domain of the TLV. One of &enum iwl_fw_ini_dbg_domain * @data: TLV data */ struct iwx_fw_ini_header { __le32 version; __le32 domain; u8 data[0]; } __packed; /* FW_TLV_DEBUG_HEADER_S_VER_1 */ /** * struct iwx_fw_ini_allocation_tlv - Allocates DRAM buffers * * @hdr: debug header * @alloc_id: allocation id. One of &enum iwl_fw_ini_allocation_id * @buf_location: buffer location. One of &enum iwl_fw_ini_buffer_location * @req_size: requested buffer size * @max_frags_num: maximum number of fragments * @min_size: minimum buffer size */ struct iwx_fw_ini_allocation_tlv { struct iwx_fw_ini_header hdr; __le32 alloc_id; __le32 buf_location; __le32 req_size; __le32 max_frags_num; __le32 min_size; } __packed; /* FW_TLV_DEBUG_BUFFER_ALLOCATION_API_S_VER_1 */ /** * enum iwx_fw_ini_allocation_id * * @IWX_FW_INI_ALLOCATION_INVALID: invalid * @IWX_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration * @IWX_FW_INI_ALLOCATION_ID_DBGC2: allocation meant for DBGC2 configuration * @IWX_FW_INI_ALLOCATION_ID_DBGC3: allocation meant for DBGC3 configuration * @IWX_FW_INI_ALLOCATION_ID_INTERNAL: allocation meant for Intreanl SMEM in D3 * @IWX_FW_INI_ALLOCATION_NUM: number of allocation ids */ enum iwx_fw_ini_allocation_id { IWX_FW_INI_ALLOCATION_INVALID, IWX_FW_INI_ALLOCATION_ID_DBGC1, IWX_FW_INI_ALLOCATION_ID_DBGC2, IWX_FW_INI_ALLOCATION_ID_DBGC3, IWX_FW_INI_ALLOCATION_ID_INTERNAL, IWX_FW_INI_ALLOCATION_NUM, }; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */ /* * CSR (control and status registers) * * CSR registers are mapped directly into PCI bus space, and are accessible * whenever platform supplies power to device, even when device is in * low power states due to driver-invoked device resets * (e.g. IWX_CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes. * * Use iwl_write32() and iwl_read32() family to access these registers; * these provide simple PCI bus access, without waking up the MAC. * Do not use iwl_write_direct32() family for these registers; * no need to "grab nic access" via IWX_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ. * The MAC (uCode processor, etc.) does not need to be powered up for accessing * the CSR registers. * * NOTE: Device does need to be awake in order to read this memory * via IWX_CSR_EEPROM and IWX_CSR_OTP registers */ #define IWX_CSR_HW_IF_CONFIG_REG (0x000) /* hardware interface config */ #define IWX_CSR_INT_COALESCING (0x004) /* accum ints, 32-usec units */ #define IWX_CSR_INT (0x008) /* host interrupt status/ack */ #define IWX_CSR_INT_MASK (0x00c) /* host interrupt enable */ #define IWX_CSR_FH_INT_STATUS (0x010) /* busmaster int status/ack*/ #define IWX_CSR_GPIO_IN (0x018) /* read external chip pins */ #define IWX_CSR_RESET (0x020) /* busmaster enable, NMI, etc*/ #define IWX_CSR_GP_CNTRL (0x024) /* 2nd byte of IWX_CSR_INT_COALESCING, not accessible via iwl_write32()! */ #define IWX_CSR_INT_PERIODIC_REG (0x005) /* * Hardware revision info * Bit fields: * 31-16: Reserved * 15-4: Type of device: see IWX_CSR_HW_REV_TYPE_xxx definitions * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D * 1-0: "Dash" (-) value, as in A-1, etc. */ #define IWX_CSR_HW_REV (0x028) /* * RF ID revision info * Bit fields: * 31:24: Reserved (set to 0x0) * 23:12: Type * 11:8: Step (A - 0x0, B - 0x1, etc) * 7:4: Dash * 3:0: Flavor */ #define IWX_CSR_HW_RF_ID (0x09c) #define IWX_CSR_GIO_REG (0x03C) /* * UCODE-DRIVER GP (general purpose) mailbox registers. * SET/CLR registers set/clear bit(s) if "1" is written. */ #define IWX_CSR_UCODE_DRV_GP1 (0x054) #define IWX_CSR_UCODE_DRV_GP1_SET (0x058) #define IWX_CSR_UCODE_DRV_GP1_CLR (0x05c) #define IWX_CSR_UCODE_DRV_GP2 (0x060) #define IWX_CSR_MBOX_SET_REG (0x088) #define IWX_CSR_MBOX_SET_REG_OS_ALIVE 0x20 #define IWX_CSR_DRAM_INT_TBL_REG (0x0A0) #define IWX_CSR_MAC_SHADOW_REG_CTRL (0x0A8) /* 6000 and up */ /* LTR control (since IWL_DEVICE_FAMILY_22000) */ #define IWX_CSR_LTR_LONG_VAL_AD 0x0D4 #define IWX_CSR_LTR_LONG_VAL_AD_NO_SNOOP_REQ 0x80000000 #define IWX_CSR_LTR_LONG_VAL_AD_NO_SNOOP_SCALE 0x1c000000 #define IWX_CSR_LTR_LONG_VAL_AD_NO_SNOOP_VAL 0x03ff0000 #define IWX_CSR_LTR_LONG_VAL_AD_SNOOP_REQ 0x00008000 #define IWX_CSR_LTR_LONG_VAL_AD_SNOOP_SCALE 0x00001c00 #define IWX_CSR_LTR_LONG_VAL_AD_SNOOP_VAL 0x000003ff #define IWX_CSR_LTR_LONG_VAL_AD_SCALE_USEC 2 /* LTR control (Qu only) */ #define IWX_HPM_MAC_LTR_CSR 0xa0348c #define IWX_HPM_MAC_LRT_ENABLE_ALL 0xf /* also uses CSR_LTR_* for values */ #define IWX_HPM_UMAC_LTR 0xa03480 /* GIO Chicken Bits (PCI Express bus link power management) */ #define IWX_CSR_GIO_CHICKEN_BITS (0x100) #define IWX_CSR_DBG_HPET_MEM_REG (0x240) #define IWX_CSR_DBG_LINK_PWR_MGMT_REG (0x250) /* Bits for IWX_CSR_HW_IF_CONFIG_REG */ #define IWX_CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH (0x00000003) #define IWX_CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP (0x0000000C) #define IWX_CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x000000C0) #define IWX_CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define IWX_CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) #define IWX_CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE (0x00000C00) #define IWX_CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH (0x00003000) #define IWX_CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP (0x0000C000) #define IWX_CSR_HW_IF_CONFIG_REG_POS_MAC_DASH (0) #define IWX_CSR_HW_IF_CONFIG_REG_POS_MAC_STEP (2) #define IWX_CSR_HW_IF_CONFIG_REG_POS_BOARD_VER (6) #define IWX_CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE (10) #define IWX_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH (12) #define IWX_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP (14) #define IWX_CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) #define IWX_CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) #define IWX_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */ #define IWX_CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */ #define IWX_CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */ #define IWX_CSR_HW_IF_CONFIG_REG_ENABLE_PME (0x10000000) #define IWX_CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */ #define IWX_CSR_INT_PERIODIC_DIS (0x00) /* disable periodic int*/ #define IWX_CSR_INT_PERIODIC_ENA (0xFF) /* 255*32 usec ~ 8 msec*/ /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), * acknowledged (reset) by host writing "1" to flagged bits. */ #define IWX_CSR_INT_BIT_FH_RX (1U << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ #define IWX_CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ #define IWX_CSR_INT_BIT_RX_PERIODIC (1 << 28) /* Rx periodic */ #define IWX_CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ #define IWX_CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ #define IWX_CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ #define IWX_CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ #define IWX_CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ #define IWX_CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ #define IWX_CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ #define IWX_CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ #define IWX_CSR_INI_SET_MASK (IWX_CSR_INT_BIT_FH_RX | \ IWX_CSR_INT_BIT_HW_ERR | \ IWX_CSR_INT_BIT_FH_TX | \ IWX_CSR_INT_BIT_SW_ERR | \ IWX_CSR_INT_BIT_RF_KILL | \ IWX_CSR_INT_BIT_SW_RX | \ IWX_CSR_INT_BIT_WAKEUP | \ IWX_CSR_INT_BIT_ALIVE | \ IWX_CSR_INT_BIT_RX_PERIODIC) /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ #define IWX_CSR_FH_INT_BIT_ERR (1U << 31) /* Error */ #define IWX_CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ #define IWX_CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ #define IWX_CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ #define IWX_CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ #define IWX_CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ #define IWX_CSR_FH_INT_RX_MASK (IWX_CSR_FH_INT_BIT_HI_PRIOR | \ IWX_CSR_FH_INT_BIT_RX_CHNL1 | \ IWX_CSR_FH_INT_BIT_RX_CHNL0) #define IWX_CSR_FH_INT_TX_MASK (IWX_CSR_FH_INT_BIT_TX_CHNL1 | \ IWX_CSR_FH_INT_BIT_TX_CHNL0) /* RESET */ #define IWX_CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) #define IWX_CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) #define IWX_CSR_RESET_REG_FLAG_SW_RESET (0x00000080) #define IWX_CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) #define IWX_CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) #define IWX_CSR_RESET_LINK_PWR_MGMT_DISABLED (0x80000000) /* * GP (general purpose) CONTROL REGISTER * Bit fields: * 27: HW_RF_KILL_SW * Indicates state of (platform's) hardware RF-Kill switch * 26-24: POWER_SAVE_TYPE * Indicates current power-saving mode: * 000 -- No power saving * 001 -- MAC power-down * 010 -- PHY (radio) power-down * 011 -- Error * 9-6: SYS_CONFIG * Indicates current system configuration, reflecting pins on chip * as forced high/low by device circuit board. * 4: GOING_TO_SLEEP * Indicates MAC is entering a power-saving sleep power-down. * Not a good time to access device-internal resources. * 3: MAC_ACCESS_REQ * Host sets this to request and maintain MAC wakeup, to allow host * access to device-internal resources. Host must wait for * MAC_CLOCK_READY (and !GOING_TO_SLEEP) before accessing non-CSR * device registers. * 2: INIT_DONE * Host sets this to put device into fully operational D0 power mode. * Host resets this after SW_RESET to put device into low power mode. * 0: MAC_CLOCK_READY * Indicates MAC (ucode processor, etc.) is powered up and can run. * Internal resources are accessible. * NOTE: This does not indicate that the processor is actually running. * NOTE: This does not indicate that device has completed * init or post-power-down restore of internal SRAM memory. * Use IWX_CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that * SRAM is restored and uCode is in normal operation mode. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and * do not need to save/restore it. * NOTE: After device reset, this bit remains "0" until host sets * INIT_DONE */ #define IWX_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) #define IWX_CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) #define IWX_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) #define IWX_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) #define IWX_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) #define IWX_CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) #define IWX_CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN (0x04000000) #define IWX_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) /* HW REV */ #define IWX_CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0) #define IWX_CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2) #define IWX_CSR_HW_REV_TYPE_MSK (0x000FFF0) /* CSR GIO */ #define IWX_CSR_GIO_REG_VAL_L0S_DISABLED (0x00000002) /* * UCODE-DRIVER GP (general purpose) mailbox register 1 * Host driver and uCode write and/or read this register to communicate with * each other. * Bit fields: * 4: UCODE_DISABLE * Host sets this to request permanent halt of uCode, same as * sending CARD_STATE command with "halt" bit set. * 3: CT_KILL_EXIT * Host sets this to request exit from CT_KILL state, i.e. host thinks * device temperature is low enough to continue normal operation. * 2: CMD_BLOCKED * Host sets this during RF KILL power-down sequence (HW, SW, CT KILL) * to release uCode to clear all Tx and command queues, enter * unassociated mode, and power down. * NOTE: Some devices also use HBUS_TARG_MBX_C register for this bit. * 1: SW_BIT_RFKILL * Host sets this when issuing CARD_STATE command to request * device sleep. * 0: MAC_SLEEP * uCode sets this when preparing a power-saving power-down. * uCode resets this when power-up is complete and SRAM is sane. * NOTE: device saves internal SRAM data to host when powering down, * and must restore this data after powering back up. * MAC_SLEEP is the best indication that restore is complete. * Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and * do not need to save/restore it. */ #define IWX_CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) #define IWX_CSR_UCODE_SW_BIT_RFKILL (0x00000002) #define IWX_CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) #define IWX_CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) #define IWX_CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE (0x00000020) /* GIO Chicken Bits (PCI Express bus link power management) */ #define IWX_CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define IWX_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) /* HPET MEM debug */ #define IWX_CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) /* DRAM INT TABLE */ #define IWX_CSR_DRAM_INT_TBL_ENABLE (1U << 31) #define IWX_CSR_DRAM_INIT_TBL_WRITE_POINTER (1 << 28) #define IWX_CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) /* 22000 configuration registers */ /* * TFH Configuration register. * * BIT fields: * * Bits 3:0: * Define the maximum number of pending read requests. * Maximum configration value allowed is 0xC * Bits 9:8: * Define the maximum transfer size. (64 / 128 / 256) * Bit 10: * When bit is set and transfer size is set to 128B, the TFH will enable * reading chunks of more than 64B only if the read address is aligned to 128B. * In case of DRAM read address which is not aligned to 128B, the TFH will * enable transfer size which doesn't cross 64B DRAM address boundary. */ #define IWX_TFH_TRANSFER_MODE (0x1F40) #define IWX_TFH_TRANSFER_MAX_PENDING_REQ 0xc #define IWX_TFH_CHUNK_SIZE_128 (1 << 8) #define IWX_TFH_CHUNK_SPLIT_MODE (1 << 10) /* * Defines the offset address in dwords referring from the beginning of the * Tx CMD which will be updated in DRAM. * Note that the TFH offset address for Tx CMD update is always referring to * the start of the TFD first TB. * In case of a DRAM Tx CMD update the TFH will update PN and Key ID */ #define IWX_TFH_TXCMD_UPDATE_CFG (0x1F48) /* * Controls TX DMA operation * * BIT fields: * * Bits 31:30: Enable the SRAM DMA channel. * Turning on bit 31 will kick the SRAM2DRAM DMA. * Note that the sram2dram may be enabled only after configuring the DRAM and * SRAM addresses registers and the byte count register. * Bits 25:24: Defines the interrupt target upon dram2sram transfer done. When * set to 1 - interrupt is sent to the driver * Bit 0: Indicates the snoop configuration */ #define IWX_TFH_SRV_DMA_CHNL0_CTRL (0x1F60) #define IWX_TFH_SRV_DMA_SNOOP (1 << 0) #define IWX_TFH_SRV_DMA_TO_DRIVER (1 << 24) #define IWX_TFH_SRV_DMA_START (1U << 31) /* Defines the DMA SRAM write start address to transfer a data block */ #define IWX_TFH_SRV_DMA_CHNL0_SRAM_ADDR (0x1F64) /* Defines the 64bits DRAM start address to read the DMA data block from */ #define IWX_TFH_SRV_DMA_CHNL0_DRAM_ADDR (0x1F68) /* * Defines the number of bytes to transfer from DRAM to SRAM. * Note that this register may be configured with non-dword aligned size. */ #define IWX_TFH_SRV_DMA_CHNL0_BC (0x1F70) /* 9000 rx series registers */ #define IWX_RFH_Q0_FRBDCB_BA_LSB 0xA08000 /* 64 bit address */ #define IWX_RFH_Q_FRBDCB_BA_LSB(q) (IWX_RFH_Q0_FRBDCB_BA_LSB + (q) * 8) /* Write index table */ #define IWX_RFH_Q0_FRBDCB_WIDX 0xA08080 #define IWX_RFH_Q_FRBDCB_WIDX(q) (IWX_RFH_Q0_FRBDCB_WIDX + (q) * 4) /* Write index table - shadow registers */ #define IWX_RFH_Q0_FRBDCB_WIDX_TRG 0x1C80 #define IWX_RFH_Q_FRBDCB_WIDX_TRG(q) (IWX_RFH_Q0_FRBDCB_WIDX_TRG + (q) * 4) /* Read index table */ #define IWX_RFH_Q0_FRBDCB_RIDX 0xA080C0 #define IWX_RFH_Q_FRBDCB_RIDX(q) (IWX_RFH_Q0_FRBDCB_RIDX + (q) * 4) /* Used list table */ #define IWX_RFH_Q0_URBDCB_BA_LSB 0xA08100 /* 64 bit address */ #define IWX_RFH_Q_URBDCB_BA_LSB(q) (IWX_RFH_Q0_URBDCB_BA_LSB + (q) * 8) /* Write index table */ #define IWX_RFH_Q0_URBDCB_WIDX 0xA08180 #define IWX_RFH_Q_URBDCB_WIDX(q) (IWX_RFH_Q0_URBDCB_WIDX + (q) * 4) #define IWX_RFH_Q0_URBDCB_VAID 0xA081C0 #define IWX_RFH_Q_URBDCB_VAID(q) (IWX_RFH_Q0_URBDCB_VAID + (q) * 4) /* stts */ #define IWX_RFH_Q0_URBD_STTS_WPTR_LSB 0xA08200 /*64 bits address */ #define IWX_RFH_Q_URBD_STTS_WPTR_LSB(q) (IWX_RFH_Q0_URBD_STTS_WPTR_LSB + (q) * 8) #define IWX_RFH_Q0_ORB_WPTR_LSB 0xA08280 #define IWX_RFH_Q_ORB_WPTR_LSB(q) (IWX_RFH_Q0_ORB_WPTR_LSB + (q) * 8) #define IWX_RFH_RBDBUF_RBD0_LSB 0xA08300 #define IWX_RFH_RBDBUF_RBD_LSB(q) (IWX_RFH_RBDBUF_RBD0_LSB + (q) * 8) /** * RFH Status Register * * Bit fields: * * Bit 29: RBD_FETCH_IDLE * This status flag is set by the RFH when there is no active RBD fetch from * DRAM. * Once the RFH RBD controller starts fetching (or when there is a pending * RBD read response from DRAM), this flag is immediately turned off. * * Bit 30: SRAM_DMA_IDLE * This status flag is set by the RFH when there is no active transaction from * SRAM to DRAM. * Once the SRAM to DRAM DMA is active, this flag is immediately turned off. * * Bit 31: RXF_DMA_IDLE * This status flag is set by the RFH when there is no active transaction from * RXF to DRAM. * Once the RXF-to-DRAM DMA is active, this flag is immediately turned off. */ #define IWX_RFH_GEN_STATUS 0xA09808 #define IWX_RFH_GEN_STATUS_GEN3 0xA07824 #define IWX_RBD_FETCH_IDLE (1 << 29) #define IWX_SRAM_DMA_IDLE (1 << 30) #define IWX_RXF_DMA_IDLE (1U << 31) /* DMA configuration */ #define IWX_RFH_RXF_DMA_CFG 0xA09820 #define IWX_RFH_RXF_DMA_CFG_GEN3 0xA07880 /* RB size */ #define IWX_RFH_RXF_DMA_RB_SIZE_MASK (0x000F0000) /* bits 16-19 */ #define IWX_RFH_RXF_DMA_RB_SIZE_POS 16 #define IWX_RFH_RXF_DMA_RB_SIZE_1K (0x1 << IWX_RFH_RXF_DMA_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_RB_SIZE_2K (0x2 << IWX_RFH_RXF_DMA_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_RB_SIZE_4K (0x4 << IWX_RFH_RXF_DMA_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_RB_SIZE_8K (0x8 << IWX_RFH_RXF_DMA_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_RB_SIZE_12K (0x9 << IWX_RFH_RXF_DMA_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_RB_SIZE_16K (0xA << IWX_RFH_RXF_DMA_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_RB_SIZE_20K (0xB << IWX_RFH_RXF_DMA_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_RB_SIZE_24K (0xC << IWX_RFH_RXF_DMA_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_RB_SIZE_28K (0xD << IWX_RFH_RXF_DMA_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_RB_SIZE_32K (0xE << IWX_RFH_RXF_DMA_RB_SIZE_POS) /* RB Circular Buffer size:defines the table sizes in RBD units */ #define IWX_RFH_RXF_DMA_RBDCB_SIZE_MASK (0x00F00000) /* bits 20-23 */ #define IWX_RFH_RXF_DMA_RBDCB_SIZE_POS 20 #define IWX_RFH_RXF_DMA_RBDCB_SIZE_8 (0x3 << IWX_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWX_RFH_RXF_DMA_RBDCB_SIZE_16 (0x4 << IWX_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWX_RFH_RXF_DMA_RBDCB_SIZE_32 (0x5 << IWX_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWX_RFH_RXF_DMA_RBDCB_SIZE_64 (0x7 << IWX_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWX_RFH_RXF_DMA_RBDCB_SIZE_128 (0x7 << IWX_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWX_RFH_RXF_DMA_RBDCB_SIZE_256 (0x8 << IWX_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWX_RFH_RXF_DMA_RBDCB_SIZE_512 (0x9 << IWX_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWX_RFH_RXF_DMA_RBDCB_SIZE_1024 (0xA << IWX_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWX_RFH_RXF_DMA_RBDCB_SIZE_2048 (0xB << IWX_RFH_RXF_DMA_RBDCB_SIZE_POS) #define IWX_RFH_RXF_DMA_MIN_RB_SIZE_MASK (0x03000000) /* bit 24-25 */ #define IWX_RFH_RXF_DMA_MIN_RB_SIZE_POS 24 #define IWX_RFH_RXF_DMA_MIN_RB_4_8 (3 << IWX_RFH_RXF_DMA_MIN_RB_SIZE_POS) #define IWX_RFH_RXF_DMA_DROP_TOO_LARGE_MASK (0x04000000) /* bit 26 */ #define IWX_RFH_RXF_DMA_SINGLE_FRAME_MASK (0x20000000) /* bit 29 */ #define IWX_RFH_DMA_EN_MASK (0xC0000000) /* bits 30-31*/ #define IWX_RFH_DMA_EN_ENABLE_VAL (1U << 31) #define IWX_RFH_RXF_RXQ_ACTIVE 0xA0980C #define IWX_RFH_GEN_CFG 0xA09800 #define IWX_RFH_GEN_CFG_SERVICE_DMA_SNOOP (1 << 0) #define IWX_RFH_GEN_CFG_RFH_DMA_SNOOP (1 << 1) #define IWX_RFH_GEN_CFG_RB_CHUNK_SIZE_128 0x00000010 #define IWX_RFH_GEN_CFG_RB_CHUNK_SIZE_64 0x00000000 /* the driver assumes everywhere that the default RXQ is 0 */ #define IWX_RFH_GEN_CFG_DEFAULT_RXQ_NUM 0xF00 /* end of 9000 rx series registers */ /* * This register is writen by driver and is read by uCode during boot flow. * Note this address is cleared after MAC reset. */ #define IWX_UREG_UCODE_LOAD_STATUS (0xa05c40) #define IWX_UREG_CPU_INIT_RUN (0xa05c44) /* * HBUS (Host-side Bus) * * HBUS registers are mapped directly into PCI bus space, but are used * to indirectly access device's internal memory or registers that * may be powered-down. * * Use iwl_write_direct32()/iwl_read_direct32() family for these registers; * host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ * to make sure the MAC (uCode processor, etc.) is powered up for accessing * internal resources. * * Do not use iwl_write32()/iwl_read32() family to access these registers; * these provide only simple PCI bus access, without waking up the MAC. */ #define IWX_HBUS_BASE (0x400) /* * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM * structures, error log, event log, verifying uCode load). * First write to address register, then read from or write to data register * to complete the job. Once the address register is set up, accesses to * data registers auto-increment the address by one dword. * Bit usage for address registers (read or write): * 0-31: memory address within device */ #define IWX_HBUS_TARG_MEM_RADDR (IWX_HBUS_BASE+0x00c) #define IWX_HBUS_TARG_MEM_WADDR (IWX_HBUS_BASE+0x010) #define IWX_HBUS_TARG_MEM_WDAT (IWX_HBUS_BASE+0x018) #define IWX_HBUS_TARG_MEM_RDAT (IWX_HBUS_BASE+0x01c) /* * Registers for accessing device's internal peripheral registers * (e.g. SCD, BSM, etc.). First write to address register, * then read from or write to data register to complete the job. * Bit usage for address registers (read or write): * 0-15: register address (offset) within device * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) */ #define IWX_HBUS_TARG_PRPH_WADDR (IWX_HBUS_BASE+0x044) #define IWX_HBUS_TARG_PRPH_RADDR (IWX_HBUS_BASE+0x048) #define IWX_HBUS_TARG_PRPH_WDAT (IWX_HBUS_BASE+0x04c) #define IWX_HBUS_TARG_PRPH_RDAT (IWX_HBUS_BASE+0x050) /* enable the ID buf for read */ #define IWX_WFPM_PS_CTL_CLR 0xa0300c #define IWX_WFMP_MAC_ADDR_0 0xa03080 #define IWX_WFMP_MAC_ADDR_1 0xa03084 #define IWX_LMPM_PMG_EN 0xa01cec #define IWX_RADIO_REG_SYS_MANUAL_DFT_0 0xad4078 #define IWX_RFIC_REG_RD 0xad0470 #define IWX_WFPM_CTRL_REG 0xa03030 #define IWX_WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK 0x08000000 #define IWX_ENABLE_WFPM 0x80000000 #define IWX_AUX_MISC_MASTER1_EN 0xa20818 #define IWX_AUX_MISC_MASTER1_EN_SBE_MSK 0x1 #define IWX_AUX_MISC_MASTER1_SMPHR_STATUS 0xa20800 #define IWX_RSA_ENABLE 0xa24b08 #define IWX_PREG_AUX_BUS_WPROT_0 0xa04cc0 #define IWX_PREG_PRPH_WPROT_9000 0xa04ce0 #define IWX_PREG_PRPH_WPROT_22000 0xa04d00 #define IWX_SB_CFG_OVERRIDE_ADDR 0xa26c78 #define IWX_SB_CFG_OVERRIDE_ENABLE 0x8000 #define IWX_SB_CFG_BASE_OVERRIDE 0xa20000 #define IWX_SB_MODIFY_CFG_FLAG 0xa03088 #define IWX_UMAG_SB_CPU_1_STATUS 0xa038c0 #define IWX_UMAG_SB_CPU_2_STATUS 0xa038c4 #define IWX_UMAG_GEN_HW_STATUS 0xA038C8 #define IWX_UREG_UMAC_CURRENT_PC 0xa05c18 #define IWX_UREG_LMAC1_CURRENT_PC 0xa05c1c #define IWX_UREG_LMAC2_CURRENT_PC 0xa05c20 #define IWX_UREG_CHICK 0xa05c00 #define IWX_UREG_CHICK_MSI_ENABLE (1 << 24) #define IWX_UREG_CHICK_MSIX_ENABLE (1 << 25) #define IWX_HPM_DEBUG 0xa03440 #define IWX_PERSISTENCE_BIT (1 << 12) #define IWX_PREG_WFPM_ACCESS (1 << 12) #define IWX_HPM_HIPM_GEN_CFG 0xa03458 #define IWX_HPM_HIPM_GEN_CFG_CR_PG_EN (1 << 0) #define IWX_HPM_HIPM_GEN_CFG_CR_SLP_EN (1 << 1) #define IWX_HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE (1 << 10) #define IWX_UREG_DOORBELL_TO_ISR6 0xA05C04 #define IWX_UREG_DOORBELL_TO_ISR6_NMI_BIT (1 << 0) #define iWX_UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE ((1 << 0) | (1 << 1)) #define IWX_UREG_DOORBELL_TO_ISR6_SUSPEND (1 << 18) #define IWX_UREG_DOORBELL_TO_ISR6_RESUME (1 << 19) #define IWX_UREG_DOORBELL_TO_ISR6_PNVM (1 << 20) /* * Per-Tx-queue write pointer (index, really!) * Indicates index to next TFD that driver will fill (1 past latest filled). * Bit usage: * 0-7: queue write index * 11-8: queue selector */ #define IWX_HBUS_TARG_WRPTR (IWX_HBUS_BASE+0x060) /********************************************************** * CSR values **********************************************************/ /* * host interrupt timeout value * used with setting interrupt coalescing timer * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit * * default interrupt coalescing timer is 64 x 32 = 2048 usecs */ #define IWX_HOST_INT_TIMEOUT_MAX (0xFF) #define IWX_HOST_INT_TIMEOUT_DEF (0x40) #define IWX_HOST_INT_TIMEOUT_MIN (0x0) #define IWX_HOST_INT_OPER_MODE (1U << 31) /***************************************************************************** * MSIX related registers * *****************************************************************************/ #define IWX_CSR_MSIX_BASE (0x2000) #define IWX_CSR_MSIX_FH_INT_CAUSES_AD (IWX_CSR_MSIX_BASE + 0x800) #define IWX_CSR_MSIX_FH_INT_MASK_AD (IWX_CSR_MSIX_BASE + 0x804) #define IWX_CSR_MSIX_HW_INT_CAUSES_AD (IWX_CSR_MSIX_BASE + 0x808) #define IWX_CSR_MSIX_HW_INT_MASK_AD (IWX_CSR_MSIX_BASE + 0x80C) #define IWX_CSR_MSIX_AUTOMASK_ST_AD (IWX_CSR_MSIX_BASE + 0x810) #define IWX_CSR_MSIX_RX_IVAR_AD_REG (IWX_CSR_MSIX_BASE + 0x880) #define IWX_CSR_MSIX_IVAR_AD_REG (IWX_CSR_MSIX_BASE + 0x890) #define IWX_CSR_MSIX_PENDING_PBA_AD (IWX_CSR_MSIX_BASE + 0x1000) #define IWX_CSR_MSIX_RX_IVAR(cause) (IWX_CSR_MSIX_RX_IVAR_AD_REG + (cause)) #define IWX_CSR_MSIX_IVAR(cause) (IWX_CSR_MSIX_IVAR_AD_REG + (cause)) /* * Causes for the FH register interrupts */ enum iwx_msix_fh_int_causes { IWX_MSIX_FH_INT_CAUSES_Q0 = (1 << 0), IWX_MSIX_FH_INT_CAUSES_Q1 = (1 << 1), IWX_MSIX_FH_INT_CAUSES_D2S_CH0_NUM = (1 << 16), IWX_MSIX_FH_INT_CAUSES_D2S_CH1_NUM = (1 << 17), IWX_MSIX_FH_INT_CAUSES_S2D = (1 << 19), IWX_MSIX_FH_INT_CAUSES_FH_ERR = (1 << 21), }; /* * Causes for the HW register interrupts */ enum iwx_msix_hw_int_causes { IWX_MSIX_HW_INT_CAUSES_REG_ALIVE = (1 << 0), IWX_MSIX_HW_INT_CAUSES_REG_WAKEUP = (1 << 1), IWX_MSIX_HW_INT_CAUSES_REG_IPC = (1 << 1), IWX_MSIX_HW_INT_CAUSES_REG_IML = (1 << 2), IWX_MSIX_HW_INT_CAUSES_REG_SW_ERR_V2 = (1 << 5), IWX_MSIX_HW_INT_CAUSES_REG_CT_KILL = (1 << 6), IWX_MSIX_HW_INT_CAUSES_REG_RF_KILL = (1 << 7), IWX_MSIX_HW_INT_CAUSES_REG_PERIODIC = (1 << 8), IWX_MSIX_HW_INT_CAUSES_REG_SW_ERR = (1 << 25), IWX_MSIX_HW_INT_CAUSES_REG_SCD = (1 << 26), IWX_MSIX_HW_INT_CAUSES_REG_FH_TX = (1 << 27), IWX_MSIX_HW_INT_CAUSES_REG_HW_ERR = (1 << 29), IWX_MSIX_HW_INT_CAUSES_REG_HAP = (1 << 30), }; /* * Registers to map causes to vectors */ enum iwx_msix_ivar_for_cause { IWX_MSIX_IVAR_CAUSE_D2S_CH0_NUM = 0x0, IWX_MSIX_IVAR_CAUSE_D2S_CH1_NUM = 0x1, IWX_MSIX_IVAR_CAUSE_S2D = 0x3, IWX_MSIX_IVAR_CAUSE_FH_ERR = 0x5, IWX_MSIX_IVAR_CAUSE_REG_ALIVE = 0x10, IWX_MSIX_IVAR_CAUSE_REG_WAKEUP = 0x11, IWX_MSIX_IVAR_CAUSE_REG_IML = 0x12, IWX_MSIX_IVAR_CAUSE_REG_CT_KILL = 0x16, IWX_MSIX_IVAR_CAUSE_REG_RF_KILL = 0x17, IWX_MSIX_IVAR_CAUSE_REG_PERIODIC = 0x18, IWX_MSIX_IVAR_CAUSE_REG_SW_ERR = 0x29, IWX_MSIX_IVAR_CAUSE_REG_SCD = 0x2a, IWX_MSIX_IVAR_CAUSE_REG_FH_TX = 0x2b, IWX_MSIX_IVAR_CAUSE_REG_HW_ERR = 0x2d, IWX_MSIX_IVAR_CAUSE_REG_HAP = 0x2e, }; #define IWX_MSIX_AUTO_CLEAR_CAUSE (0 << 7) #define IWX_MSIX_NON_AUTO_CLEAR_CAUSE (1 << 7) /***************************************************************************** * HW address related registers * *****************************************************************************/ #define IWX_CSR_ADDR_BASE (0x380) #define IWX_CSR_MAC_ADDR0_OTP (IWX_CSR_ADDR_BASE) #define IWX_CSR_MAC_ADDR1_OTP (IWX_CSR_ADDR_BASE + 4) #define IWX_CSR_MAC_ADDR0_STRAP (IWX_CSR_ADDR_BASE + 8) #define IWX_CSR_MAC_ADDR1_STRAP (IWX_CSR_ADDR_BASE + 0xC) /** * uCode API flags * @IWX_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * was a separate TLV but moved here to save space. * @IWX_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, * treats good CRC threshold as a boolean * @IWX_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). * @IWX_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. * @IWX_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS * @IWX_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD * @IWX_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan * offload profile config command. * @IWX_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six * (rather than two) IPv6 addresses * @IWX_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element * from the probe request template. * @IWX_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version) * @IWX_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version) * @IWX_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a * single bound interface). * @IWX_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD * @IWX_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS. * @IWX_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save * @IWX_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering. * @IWX_UCODE_TLV_FLAGS_GO_UAPSD: AP/GO interfaces support uAPSD clients * */ #define IWX_UCODE_TLV_FLAGS_PAN (1 << 0) #define IWX_UCODE_TLV_FLAGS_NEWSCAN (1 << 1) #define IWX_UCODE_TLV_FLAGS_MFP (1 << 2) #define IWX_UCODE_TLV_FLAGS_P2P (1 << 3) #define IWX_UCODE_TLV_FLAGS_DW_BC_TABLE (1 << 4) #define IWX_UCODE_TLV_FLAGS_SHORT_BL (1 << 7) #define IWX_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS (1 << 10) #define IWX_UCODE_TLV_FLAGS_NO_BASIC_SSID (1 << 12) #define IWX_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL (1 << 15) #define IWX_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE (1 << 16) #define IWX_UCODE_TLV_FLAGS_P2P_PS (1 << 21) #define IWX_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM (1 << 22) #define IWX_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM (1 << 23) #define IWX_UCODE_TLV_FLAGS_UAPSD_SUPPORT (1 << 24) #define IWX_UCODE_TLV_FLAGS_EBS_SUPPORT (1 << 25) #define IWX_UCODE_TLV_FLAGS_P2P_PS_UAPSD (1 << 26) #define IWX_UCODE_TLV_FLAGS_BCAST_FILTERING (1 << 29) #define IWX_UCODE_TLV_FLAGS_GO_UAPSD (1 << 30) #define IWX_UCODE_TLV_FLAGS_LTE_COEX (1U << 31) #define IWX_UCODE_TLV_FLAG_BITS \ "\020\1PAN\2NEWSCAN\3MFP\4P2P\5DW_BC_TABLE\6NEWBT_COEX\7PM_CMD\10SHORT_BL\11RX_ENERGY\12TIME_EVENT_V2\13D3_6_IPV6\14BF_UPDATED\15NO_BASIC_SSID\17D3_CONTINUITY\20NEW_NSOFFL_S\21NEW_NSOFFL_L\22SCHED_SCAN\24STA_KEY_CMD\25DEVICE_PS_CMD\26P2P_PS\27P2P_PS_DCM\30P2P_PS_SCM\31UAPSD_SUPPORT\32EBS\33P2P_PS_UAPSD\36BCAST_FILTERING\37GO_UAPSD\40LTE_COEX" /** * uCode TLV api * @IWX_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. * @IWX_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * @IWX_UCODE_TLV_API_WIDE_CMD_HDR: ucode supports wide command header * @IWX_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params * @IWX_UCODE_TLV_API_NEW_VERSION: new versioning format * @IWX_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size * (command version 3) that supports per-chain limits * @IWX_UCODE_TLV_API_SCAN_TSF_REPORT: Scan start time reported in scan * iteration complete notification, and the timestamp reported for RX * received during scan, are reported in TSF of the mac specified in the * scan request. * @IWX_UCODE_TLV_API_TKIP_MIC_KEYS: This ucode supports version 2 of * ADD_MODIFY_STA_KEY_API_S_VER_2. * @IWX_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. * @IWX_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority * instead of 3. * @IWX_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used * @IWX_UCODE_TLV_API_REDUCED_SCAN_CONFIG: This ucode supports v3 of * SCAN_CONFIG_DB_CMD_API_S. * * @IWX_NUM_UCODE_TLV_API: number of bits used */ #define IWX_UCODE_TLV_API_FRAGMENTED_SCAN 8 #define IWX_UCODE_TLV_API_WIFI_MCC_UPDATE 9 #define IWX_UCODE_TLV_API_WIDE_CMD_HDR 14 #define IWX_UCODE_TLV_API_LQ_SS_PARAMS 18 #define IWX_UCODE_TLV_API_NEW_VERSION 20 #define IWX_UCODE_TLV_API_EXT_SCAN_PRIORITY 24 #define IWX_UCODE_TLV_API_TX_POWER_CHAIN 27 #define IWX_UCODE_TLV_API_SCAN_TSF_REPORT 28 #define IWX_UCODE_TLV_API_TKIP_MIC_KEYS 29 #define IWX_UCODE_TLV_API_STA_TYPE 30 #define IWX_UCODE_TLV_API_NAN2_VER2 31 #define IWX_UCODE_TLV_API_ADAPTIVE_DWELL 32 #define IWX_UCODE_TLV_API_NEW_RX_STATS 35 #define IWX_UCODE_TLV_API_ADAPTIVE_DWELL_V2 42 #define IWX_UCODE_TLV_API_BEACON_FILTER_V4 47 #define IWX_UCODE_TLV_API_REGULATORY_NVM_INFO 48 #define IWX_UCODE_TLV_API_FTM_NEW_RANGE_REQ 49 #define IWX_UCODE_TLV_API_SCAN_OFFLOAD_CHANS 50 #define IWX_UCODE_TLV_API_MBSSID_HE 52 #define IWX_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE 53 #define IWX_UCODE_TLV_API_FTM_RTT_ACCURACY 54 #define IWX_UCODE_TLV_API_SAR_TABLE_VER 55 #define IWX_UCODE_TLV_API_REDUCED_SCAN_CONFIG 56 #define IWX_UCODE_TLV_API_ADWELL_HB_DEF_N_AP 57 #define IWX_UCODE_TLV_API_SCAN_EXT_CHAN_VER 58 #define IWX_UCODE_TLV_API_BAND_IN_RX_DATA 59 #define IWX_NUM_UCODE_TLV_API 128 #define IWX_UCODE_TLV_API_BITS \ "\020\10FRAGMENTED_SCAN\11WIFI_MCC_UPDATE\16WIDE_CMD_HDR\22LQ_SS_PARAMS\30EXT_SCAN_PRIO\33TX_POWER_CHAIN\35TKIP_MIC_KEYS" /** * uCode capabilities * @IWX_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 * @IWX_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory * @IWX_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. * @IWX_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer * @IWX_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM) * @IWX_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality * @IWX_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current * tx power value into TPC Report action frame and Link Measurement Report * action frame * @IWX_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT: supports updating current * channel in DS parameter set element in probe requests. * @IWX_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT: supports adding TPC Report IE in * probe requests. * @IWX_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests * @IWX_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), * which also implies support for the scheduler configuration command * @IWX_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching * @IWX_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG: Consolidated D3-D0 image * @IWX_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command * @IWX_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command * @IWX_UCODE_TLV_CAPA_2G_COEX_SUPPORT: supports 2G coex Command * @IWX_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload * @IWX_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics * @IWX_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD * @IWX_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running * @IWX_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different * sources for the MCC. This TLV bit is a future replacement to * IWX_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR * is supported. * @IWX_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC * @IWX_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan * @IWX_UCODE_TLV_CAPA_NAN_SUPPORT: supports NAN * @IWX_UCODE_TLV_CAPA_UMAC_UPLOAD: supports upload mode in umac (1=supported, * 0=no support) * @IWx_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS: firmware supports ultra high band * (6 GHz). * @IWX_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement * @IWX_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts * @IWX_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT * @IWX_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what * antenna the beacon should be transmitted * @IWX_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon * from AP and will send it upon d0i3 exit. * @IWX_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2 * @IWX_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill * @IWX_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature * thresholds reporting * @IWX_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command * @IWX_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in * regular image. * @IWX_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared * memory addresses from the firmware. * @IWX_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement * @IWX_UCODE_TLV_CAPA_LMAC_UPLOAD: supports upload mode in lmac (1=supported, * 0=no support) * * @IWX_NUM_UCODE_TLV_CAPA: number of bits used */ #define IWX_UCODE_TLV_CAPA_D0I3_SUPPORT 0 #define IWX_UCODE_TLV_CAPA_LAR_SUPPORT 1 #define IWX_UCODE_TLV_CAPA_UMAC_SCAN 2 #define IWX_UCODE_TLV_CAPA_BEAMFORMER 3 #define IWX_UCODE_TLV_CAPA_TOF_SUPPORT 5 #define IWX_UCODE_TLV_CAPA_TDLS_SUPPORT 6 #define IWX_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT 8 #define IWX_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT 9 #define IWX_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT 10 #define IWX_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT 11 #define IWX_UCODE_TLV_CAPA_DQA_SUPPORT 12 #define IWX_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH 13 #define IWX_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG 17 #define IWX_UCODE_TLV_CAPA_HOTSPOT_SUPPORT 18 #define IWX_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT 19 #define IWX_UCODE_TLV_CAPA_2G_COEX_SUPPORT 20 #define IWX_UCODE_TLV_CAPA_CSUM_SUPPORT 21 #define IWX_UCODE_TLV_CAPA_RADIO_BEACON_STATS 22 #define IWX_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD 26 #define IWX_UCODE_TLV_CAPA_BT_COEX_PLCR 28 #define IWX_UCODE_TLV_CAPA_LAR_MULTI_MCC 29 #define IWX_UCODE_TLV_CAPA_BT_COEX_RRC 30 #define IWX_UCODE_TLV_CAPA_GSCAN_SUPPORT 31 #define IWX_UCODE_TLV_CAPA_NAN_SUPPORT 34 #define IWX_UCODE_TLV_CAPA_UMAC_UPLOAD 35 #define IWX_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT 39 #define IWX_UCODE_TLV_CAPA_CDB_SUPPORT 40 #define IWX_UCODE_TLV_CAPA_TLC_OFFLOAD 43 #define IWX_UCODE_TLV_CAPA_DYNAMIC_QUOTA 44 #define IWX_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS 48 #define IWX_UCODE_TLV_CAPA_CS_MODIFY 49 #define IWX_UCODE_TLV_CAPA_SET_LTR_GEN2 50 #define IWX_UCODE_TLV_CAPA_SET_PPAG 52 #define IWX_UCODE_TLV_CAPA_SESSION_PROT_CMD 54 #define IWX_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE 64 #define IWX_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS 65 #define IWX_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT 67 #define IWX_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT 68 #define IWX_UCODE_TLV_CAPA_BEACON_ANT_SELECTION 71 #define IWX_UCODE_TLV_CAPA_BEACON_STORING 72 #define IWX_UCODE_TLV_CAPA_LAR_SUPPORT_V2 73 #define IWX_UCODE_TLV_CAPA_CT_KILL_BY_FW 74 #define IWX_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT 75 #define IWX_UCODE_TLV_CAPA_CTDP_SUPPORT 76 #define IWX_UCODE_TLV_CAPA_USNIFFER_UNIFIED 77 #define IWX_UCODE_TLV_CAPA_LMAC_UPLOAD 79 #define IWX_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG 80 #define IWX_UCODE_TLV_CAPA_LQM_SUPPORT 81 #define IWX_UCODE_TLV_CAPA_LED_CMD_SUPPORT 88 #define IWX_NUM_UCODE_TLV_CAPA 128 /* * For 16.0 uCode and above, there is no differentiation between sections, * just an offset to the HW address. */ #define IWX_CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC #define IWX_PAGING_SEPARATOR_SECTION 0xAAAABBBB /* uCode version contains 4 values: Major/Minor/API/Serial */ #define IWX_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) #define IWX_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) #define IWX_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) #define IWX_UCODE_SERIAL(ver) ((ver) & 0x000000FF) /* * Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to * flow triggers. * @event_trigger: bitmap for which calibrations to perform according to * event triggers. */ struct iwx_tlv_calib_ctrl { uint32_t flow_trigger; uint32_t event_trigger; } __packed; #define IWX_FW_PHY_CFG_RADIO_TYPE_POS 0 #define IWX_FW_PHY_CFG_RADIO_TYPE (0x3 << IWX_FW_PHY_CFG_RADIO_TYPE_POS) #define IWX_FW_PHY_CFG_RADIO_STEP_POS 2 #define IWX_FW_PHY_CFG_RADIO_STEP (0x3 << IWX_FW_PHY_CFG_RADIO_STEP_POS) #define IWX_FW_PHY_CFG_RADIO_DASH_POS 4 #define IWX_FW_PHY_CFG_RADIO_DASH (0x3 << IWX_FW_PHY_CFG_RADIO_DASH_POS) #define IWX_FW_PHY_CFG_TX_CHAIN_POS 16 #define IWX_FW_PHY_CFG_TX_CHAIN (0xf << IWX_FW_PHY_CFG_TX_CHAIN_POS) #define IWX_FW_PHY_CFG_RX_CHAIN_POS 20 #define IWX_FW_PHY_CFG_RX_CHAIN (0xf << IWX_FW_PHY_CFG_RX_CHAIN_POS) #define IWX_FW_PHY_CFG_CHAIN_SAD_POS 23 #define IWX_FW_PHY_CFG_CHAIN_SAD_ENABLED (0x1 << IWX_FW_PHY_CFG_CHAIN_SAD_POS) #define IWX_FW_PHY_CFG_CHAIN_SAD_ANT_A (0x2 << IWX_FW_PHY_CFG_CHAIN_SAD_POS) #define IWX_FW_PHY_CFG_CHAIN_SAD_ANT_B (0x4 << IWX_FW_PHY_CFG_CHAIN_SAD_POS) #define IWX_FW_PHY_CFG_SHARED_CLK (1 << 31) /** * struct iwx_fw_cipher_scheme - a cipher scheme supported by FW. * @cipher: a cipher suite selector * @flags: cipher scheme flags (currently reserved for a future use) * @hdr_len: a size of MPDU security header * @pn_len: a size of PN * @pn_off: an offset of pn from the beginning of the security header * @key_idx_off: an offset of key index byte in the security header * @key_idx_mask: a bit mask of key_idx bits * @key_idx_shift: bit shift needed to get key_idx * @mic_len: mic length in bytes * @hw_cipher: a HW cipher index used in host commands */ struct iwx_fw_cipher_scheme { uint32_t cipher; uint8_t flags; uint8_t hdr_len; uint8_t pn_len; uint8_t pn_off; uint8_t key_idx_off; uint8_t key_idx_mask; uint8_t key_idx_shift; uint8_t mic_len; uint8_t hw_cipher; } __packed; /** * struct iwx_fw_cscheme_list - a cipher scheme list * @size: a number of entries * @cs: cipher scheme entries */ struct iwx_fw_cscheme_list { uint8_t size; struct iwx_fw_cipher_scheme cs[]; } __packed; /* v1/v2 uCode file layout */ struct iwx_ucode_header { uint32_t ver; /* major/minor/API/serial */ union { struct { uint32_t inst_size; /* bytes of runtime code */ uint32_t data_size; /* bytes of runtime data */ uint32_t init_size; /* bytes of init code */ uint32_t init_data_size; /* bytes of init data */ uint32_t boot_size; /* bytes of bootstrap code */ uint8_t data[0]; /* in same order as sizes */ } v1; struct { uint32_t build; /* build number */ uint32_t inst_size; /* bytes of runtime code */ uint32_t data_size; /* bytes of runtime data */ uint32_t init_size; /* bytes of init code */ uint32_t init_data_size; /* bytes of init data */ uint32_t boot_size; /* bytes of bootstrap code */ uint8_t data[0]; /* in same order as sizes */ } v2; } u; }; /* * new TLV uCode file layout * * The new TLV file format contains TLVs, that each specify * some piece of data. */ #define IWX_UCODE_TLV_INVALID 0 /* unused */ #define IWX_UCODE_TLV_INST 1 #define IWX_UCODE_TLV_DATA 2 #define IWX_UCODE_TLV_INIT 3 #define IWX_UCODE_TLV_INIT_DATA 4 #define IWX_UCODE_TLV_BOOT 5 #define IWX_UCODE_TLV_PROBE_MAX_LEN 6 /* a uint32_t value */ #define IWX_UCODE_TLV_PAN 7 #define IWX_UCODE_TLV_RUNT_EVTLOG_PTR 8 #define IWX_UCODE_TLV_RUNT_EVTLOG_SIZE 9 #define IWX_UCODE_TLV_RUNT_ERRLOG_PTR 10 #define IWX_UCODE_TLV_INIT_EVTLOG_PTR 11 #define IWX_UCODE_TLV_INIT_EVTLOG_SIZE 12 #define IWX_UCODE_TLV_INIT_ERRLOG_PTR 13 #define IWX_UCODE_TLV_ENHANCE_SENS_TBL 14 #define IWX_UCODE_TLV_PHY_CALIBRATION_SIZE 15 #define IWX_UCODE_TLV_WOWLAN_INST 16 #define IWX_UCODE_TLV_WOWLAN_DATA 17 #define IWX_UCODE_TLV_FLAGS 18 #define IWX_UCODE_TLV_SEC_RT 19 #define IWX_UCODE_TLV_SEC_INIT 20 #define IWX_UCODE_TLV_SEC_WOWLAN 21 #define IWX_UCODE_TLV_DEF_CALIB 22 #define IWX_UCODE_TLV_PHY_SKU 23 #define IWX_UCODE_TLV_SECURE_SEC_RT 24 #define IWX_UCODE_TLV_SECURE_SEC_INIT 25 #define IWX_UCODE_TLV_SECURE_SEC_WOWLAN 26 #define IWX_UCODE_TLV_NUM_OF_CPU 27 #define IWX_UCODE_TLV_CSCHEME 28 #define IWX_UCODE_TLV_API_CHANGES_SET 29 #define IWX_UCODE_TLV_ENABLED_CAPABILITIES 30 #define IWX_UCODE_TLV_N_SCAN_CHANNELS 31 #define IWX_UCODE_TLV_PAGING 32 #define IWX_UCODE_TLV_SEC_RT_USNIFFER 34 #define IWX_UCODE_TLV_SDIO_ADMA_ADDR 35 #define IWX_UCODE_TLV_FW_VERSION 36 #define IWX_UCODE_TLV_FW_DBG_DEST 38 #define IWX_UCODE_TLV_FW_DBG_CONF 39 #define IWX_UCODE_TLV_FW_DBG_TRIGGER 40 #define IWX_UCODE_TLV_CMD_VERSIONS 48 #define IWX_UCODE_TLV_FW_GSCAN_CAPA 50 #define IWX_UCODE_TLV_FW_MEM_SEG 51 #define IWX_UCODE_TLV_IML 52 #define IWX_UCODE_TLV_FW_FMAC_API_VERSION 53 #define IWX_UCODE_TLV_UMAC_DEBUG_ADDRS 54 #define IWX_UCODE_TLV_LMAC_DEBUG_ADDRS 55 #define IWX_UCODE_TLV_FW_RECOVERY_INFO 57 #define IWX_UCODE_TLV_HW_TYPE 58 #define IWX_UCODE_TLV_FW_FMAC_RECOVERY_INFO 59 #define IWX_UCODE_TLV_FW_FSEQ_VERSION 60 #define IWX_UCODE_PHY_INTEGRATION_VERSION 61 #define IWX_UCODE_TLV_PNVM_VERSION 62 #define IWX_UCODE_TLV_PNVM_SKU 64 #define IWX_UCODE_TLV_DEBUG_BASE 0x1000005 #define IWX_UCODE_TLV_CONST_BASE 0x100 #define IWX_UCODE_TLV_FW_NUM_STATIONS (IWX_UCODE_TLV_CONST_BASE + 0) #define IWX_UCODE_TLV_TYPE_DEBUG_INFO (IWX_UCODE_TLV_DEBUG_BASE + 0) #define IWX_UCODE_TLV_TYPE_BUFFER_ALLOCATION (IWX_UCODE_TLV_DEBUG_BASE + 1) #define IWX_UCODE_TLV_TYPE_HCMD (IWX_UCODE_TLV_DEBUG_BASE + 2) #define IWX_UCODE_TLV_TYPE_REGIONS (IWX_UCODE_TLV_DEBUG_BASE + 3) #define IWX_UCODE_TLV_TYPE_TRIGGERS (IWX_UCODE_TLV_DEBUG_BASE + 4) #define IWX_UCODE_TLV_TYPE_CONF_SET (IWX_UCODE_TLV_DEBUG_BASE + 5) #define IWX_UCODE_TLV_DEBUG_MAX IWX_UCODE_TLV_TYPE_CONF_SET struct iwx_ucode_tlv { uint32_t type; /* see above */ uint32_t length; /* not including type/length fields */ uint8_t data[0]; }; struct iwx_ucode_api { uint32_t api_index; uint32_t api_flags; } __packed; struct iwx_ucode_capa { uint32_t api_index; uint32_t api_capa; } __packed; #define IWX_TLV_UCODE_MAGIC 0x0a4c5749 struct iwx_tlv_ucode_header { /* * The TLV style ucode header is distinguished from * the v1/v2 style header by first four bytes being * zero, as such is an invalid combination of * major/minor/API/serial versions. */ uint32_t zero; uint32_t magic; uint8_t human_readable[64]; uint32_t ver; /* major/minor/API/serial */ uint32_t build; uint64_t ignore; /* * The data contained herein has a TLV layout, * see above for the TLV header and types. * Note that each TLV is padded to a length * that is a multiple of 4 for alignment. */ uint8_t data[0]; }; /* * Registers in this file are internal, not PCI bus memory mapped. * Driver accesses these via IWX_HBUS_TARG_PRPH_* registers. */ #define IWX_PRPH_BASE (0x00000) #define IWX_PRPH_END (0xFFFFF) /****************************/ /* Flow Handler Definitions */ /****************************/ /** * struct iwx_rb_status - receive buffer status * host memory mapped FH registers * @closed_rb_num [0:11] - Indicates the index of the RB which was closed * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed * @finished_rb_num [0:11] - Indicates the index of the current RB * in which the last frame was written to * @finished_fr_num [0:11] - Indicates the index of the RX Frame * which was transferred */ struct iwx_rb_status { uint16_t closed_rb_num; uint16_t closed_fr_num; uint16_t finished_rb_num; uint16_t finished_fr_nam; uint32_t unused; } __packed; /** * struct iwx_rx_completion_desc - completion descriptor * @reserved1: reserved * @rbid: unique tag of the received buffer * @flags: flags (0: fragmented, all others: reserved) * @reserved2: reserved */ struct iwx_rx_completion_desc { uint32_t reserved1; uint16_t rbid; uint8_t flags; uint8_t reserved2[25]; } __packed; #define IWX_TFD_QUEUE_SIZE_MAX (256) #define IWX_TFD_QUEUE_SIZE_MAX_GEN3 (65536) /* cb size is the exponent - 3 */ #define IWX_TFD_QUEUE_CB_SIZE(x) (IWX_RX_QUEUE_CB_SIZE(x) - 3) #define IWX_TFD_QUEUE_SIZE_BC_DUP (64) #define IWX_TFD_QUEUE_BC_SIZE (IWX_TFD_QUEUE_SIZE_MAX + \ IWX_TFD_QUEUE_SIZE_BC_DUP) #define IWX_TFD_QUEUE_BC_SIZE_GEN3 1024 #define IWX_TFH_NUM_TBS 25 /** * struct iwx_tfh_tb transmit buffer descriptor within transmit frame descriptor * * This structure contains dma address and length of transmission address * * @tb_len length of the tx buffer * @addr 64 bits dma address */ struct iwx_tfh_tb { uint16_t tb_len; uint64_t addr; } __packed; /** * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. * Both driver and device share these circular buffers, each of which must be * contiguous 256 TFDs. * For pre 22000 HW it is 256 x 128 bytes-per-TFD = 32 KBytes * For 22000 HW and on it is 256 x 256 bytes-per-TFD = 65 KBytes * * Each TFD contains pointer/size information for up to 25 data buffers * in host DRAM. These buffers collectively contain the (one) frame described * by the TFD. Each buffer must be a single contiguous block of memory within * itself, but buffers may be scattered in host DRAM. Each buffer has max size * of (4K - 4). The concatenates all of a TFD's buffers into a single * Tx frame, up to 8 KBytes in size. * * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. */ /** * struct iwx_tfh_tfd - Transmit Frame Descriptor (TFD) * @ num_tbs 0-4 number of active tbs * 5 -15 reserved * @ tbs[25] transmit frame buffer descriptors * @ __pad padding */ struct iwx_tfh_tfd { uint16_t num_tbs; struct iwx_tfh_tb tbs[IWX_TFH_NUM_TBS]; uint32_t __pad; } __packed; /* Fixed (non-configurable) rx data from phy */ /** * struct iwx_agn_schedq_bc_tbl scheduler byte count table * base physical address provided by IWX_SCD_DRAM_BASE_ADDR * @tfd_offset 0-12 - tx command byte count * 12-16 - station index */ struct iwx_agn_scd_bc_tbl { uint16_t tfd_offset[IWX_TFD_QUEUE_BC_SIZE]; } __packed; /** * struct iwx_gen3_bc_tbl scheduler byte count table gen3 * For 22560 and on: * @tfd_offset: 0-12 - tx command byte count * 12-13 - number of 64 byte chunks * 14-16 - reserved */ struct iwx_gen3_bc_tbl { uint16_t tfd_offset[IWX_TFD_QUEUE_BC_SIZE_GEN3]; } __packed; /* Maximum number of Tx queues. */ #define IWX_MAX_QUEUES 31 #define IWX_MAX_TVQM_QUEUES 512 /** * DQA - Dynamic Queue Allocation -introduction * * Dynamic Queue Allocation (AKA "DQA") is a feature implemented in iwlwifi * to allow dynamic allocation of queues on-demand, rather than allocate them * statically ahead of time. Ideally, we would like to allocate one queue * per RA/TID, thus allowing an AP - for example - to send BE traffic to STA2 * even if it also needs to send traffic to a sleeping STA1, without being * blocked by the sleeping station. * * Although the queues in DQA mode are dynamically allocated, there are still * some queues that are statically allocated: * TXQ #0 - command queue * TXQ #1 - aux frames * TXQ #2 - P2P device frames * TXQ #3 - P2P GO/SoftAP GCAST/BCAST frames * TXQ #4 - BSS DATA frames queue * TXQ #5-8 - non-QoS data, QoS no-data, and MGMT frames queue pool * TXQ #9 - P2P GO/SoftAP probe responses * TXQ #10-31 - QoS DATA frames queue pool (for Tx aggregation) */ /* static DQA Tx queue numbers */ #define IWX_DQA_CMD_QUEUE 0 #define IWX_DQA_AUX_QUEUE 1 #define IWX_DQA_P2P_DEVICE_QUEUE 2 #define IWX_DQA_INJECT_MONITOR_QUEUE 2 #define IWX_DQA_GCAST_QUEUE 3 #define IWX_DQA_BSS_CLIENT_QUEUE 4 #define IWX_DQA_MIN_MGMT_QUEUE 5 #define IWX_DQA_MAX_MGMT_QUEUE 8 #define IWX_DQA_AP_PROBE_RESP_QUEUE 9 #define IWX_DQA_MIN_DATA_QUEUE 10 #define IWX_DQA_MAX_DATA_QUEUE 31 #define IWX_TX_FIFO_BK 0 #define IWX_TX_FIFO_BE 1 #define IWX_TX_FIFO_VI 2 #define IWX_TX_FIFO_VO 3 #define IWX_TX_FIFO_MCAST 5 #define IWX_TX_FIFO_CMD 7 enum iwx_gen2_tx_fifo { IWX_GEN2_TX_FIFO_CMD = 0, IWX_GEN2_EDCA_TX_FIFO_BK, IWX_GEN2_EDCA_TX_FIFO_BE, IWX_GEN2_EDCA_TX_FIFO_VI, IWX_GEN2_EDCA_TX_FIFO_VO, IWX_GEN2_TRIG_TX_FIFO_BK, IWX_GEN2_TRIG_TX_FIFO_BE, IWX_GEN2_TRIG_TX_FIFO_VI, IWX_GEN2_TRIG_TX_FIFO_VO, }; /** * TXQ config options * @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue * @TX_QUEUE_CFG_TFD_SHORT_FORMAT: use short TFD format */ #define IWX_TX_QUEUE_CFG_ENABLE_QUEUE (1 << 0) #define IWX_TX_QUEUE_CFG_TFD_SHORT_FORMAT (1 << 1) #define IWX_DEFAULT_QUEUE_SIZE IWX_TFD_QUEUE_SIZE_MAX #define IWX_CMD_QUEUE_SIZE 32 #define IWX_CMD_QUEUE_SIZE_GEN3 128 #define IWX_MIN_256_BA_QUEUE_SIZE_GEN3 1024 /** * struct iwx_tx_queue_cfg_cmd - txq hw scheduler config command * @sta_id: station id * @tid: tid of the queue * @flags: see &enum iwl_tx_queue_cfg_actions * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) * @byte_cnt_addr: address of byte count table * @tfdq_addr: address of TFD circular buffer */ struct iwx_tx_queue_cfg_cmd { uint8_t sta_id; uint8_t tid; uint16_t flags; uint32_t cb_size; uint64_t byte_cnt_addr; uint64_t tfdq_addr; } __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ /** * struct iwx_tx_queue_cfg_rsp - response to txq hw scheduler config * @queue_number: queue number assigned to this RA -TID * @flags: set on failure * @write_pointer: initial value for write pointer * @reserved: reserved */ struct iwx_tx_queue_cfg_rsp { uint16_t queue_number; uint16_t flags; uint16_t write_pointer; uint16_t reserved; } __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ /* * Commands */ #define IWX_ALIVE 0x1 #define IWX_REPLY_ERROR 0x2 #define IWX_INIT_COMPLETE_NOTIF 0x4 /* PHY context commands */ #define IWX_PHY_CONTEXT_CMD 0x8 #define IWX_DBG_CFG 0x9 /* UMAC scan commands */ #define IWX_SCAN_ITERATION_COMPLETE_UMAC 0xb5 #define IWX_SCAN_CFG_CMD 0xc #define IWX_SCAN_REQ_UMAC 0xd #define IWX_SCAN_ABORT_UMAC 0xe #define IWX_SCAN_COMPLETE_UMAC 0xf /* station table */ #define IWX_ADD_STA_KEY 0x17 #define IWX_ADD_STA 0x18 #define IWX_REMOVE_STA 0x19 /* TX */ #define IWX_TX_CMD 0x1c #define IWX_TXPATH_FLUSH 0x1e #define IWX_MGMT_MCAST_KEY 0x1f /* scheduler config */ #define IWX_SCD_QUEUE_CFG 0x1d /* global key */ #define IWX_WEP_KEY 0x20 #define IWX_SHARED_MEM_CFG 0x25 /* MAC and Binding commands */ #define IWX_MAC_CONTEXT_CMD 0x28 #define IWX_TIME_EVENT_CMD 0x29 /* both CMD and response */ #define IWX_TIME_EVENT_NOTIFICATION 0x2a #define IWX_BINDING_CONTEXT_CMD 0x2b #define IWX_TIME_QUOTA_CMD 0x2c #define IWX_NON_QOS_TX_COUNTER_CMD 0x2d /* Calibration */ #define IWX_TEMPERATURE_NOTIFICATION 0x62 #define IWX_CALIBRATION_CFG_CMD 0x65 #define IWX_CALIBRATION_RES_NOTIFICATION 0x66 #define IWX_CALIBRATION_COMPLETE_NOTIFICATION 0x67 #define IWX_RADIO_VERSION_NOTIFICATION 0x68 /* Phy */ #define IWX_PHY_CONFIGURATION_CMD 0x6a /* Power - legacy power table command */ #define IWX_POWER_TABLE_CMD 0x77 #define IWX_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION 0x78 #define IWX_LTR_CONFIG 0xee /* NVM */ #define IWX_NVM_ACCESS_CMD 0x88 #define IWX_SET_CALIB_DEFAULT_CMD 0x8e #define IWX_BEACON_NOTIFICATION 0x90 #define IWX_BEACON_TEMPLATE_CMD 0x91 #define IWX_TX_ANT_CONFIGURATION_CMD 0x98 #define IWX_BT_CONFIG 0x9b #define IWX_STATISTICS_CMD 0x9c #define IWX_STATISTICS_NOTIFICATION 0x9d #define IWX_REDUCE_TX_POWER_CMD 0x9f /* RF-KILL commands and notifications */ #define IWX_CARD_STATE_CMD 0xa0 #define IWX_CARD_STATE_NOTIFICATION 0xa1 #define IWX_MISSED_BEACONS_NOTIFICATION 0xa2 #define IWX_MFUART_LOAD_NOTIFICATION 0xb1 /* Power - new power table command */ #define IWX_MAC_PM_POWER_TABLE 0xa9 #define IWX_REPLY_RX_PHY_CMD 0xc0 #define IWX_REPLY_RX_MPDU_CMD 0xc1 #define IWX_BAR_FRAME_RELEASE 0xc2 #define IWX_BA_NOTIF 0xc5 /* Location Aware Regulatory */ #define IWX_MCC_UPDATE_CMD 0xc8 #define IWX_MCC_CHUB_UPDATE_CMD 0xc9 /* BT Coex */ #define IWX_BT_COEX_PRIO_TABLE 0xcc #define IWX_BT_COEX_PROT_ENV 0xcd #define IWX_BT_PROFILE_NOTIFICATION 0xce #define IWX_BT_COEX_CI 0x5d #define IWX_REPLY_SF_CFG_CMD 0xd1 #define IWX_REPLY_BEACON_FILTERING_CMD 0xd2 /* DTS measurements */ #define IWX_CMD_DTS_MEASUREMENT_TRIGGER 0xdc #define IWX_DTS_MEASUREMENT_NOTIFICATION 0xdd #define IWX_REPLY_DEBUG_CMD 0xf0 #define IWX_DEBUG_LOG_MSG 0xf7 #define IWX_MCAST_FILTER_CMD 0xd0 /* D3 commands/notifications */ #define IWX_D3_CONFIG_CMD 0xd3 #define IWX_PROT_OFFLOAD_CONFIG_CMD 0xd4 #define IWX_OFFLOADS_QUERY_CMD 0xd5 #define IWX_REMOTE_WAKE_CONFIG_CMD 0xd6 /* for WoWLAN in particular */ #define IWX_WOWLAN_PATTERNS 0xe0 #define IWX_WOWLAN_CONFIGURATION 0xe1 #define IWX_WOWLAN_TSC_RSC_PARAM 0xe2 #define IWX_WOWLAN_TKIP_PARAM 0xe3 #define IWX_WOWLAN_KEK_KCK_MATERIAL 0xe4 #define IWX_WOWLAN_GET_STATUSES 0xe5 #define IWX_WOWLAN_TX_POWER_PER_DB 0xe6 /* and for NetDetect */ #define IWX_NET_DETECT_CONFIG_CMD 0x54 #define IWX_NET_DETECT_PROFILES_QUERY_CMD 0x56 #define IWX_NET_DETECT_PROFILES_CMD 0x57 #define IWX_NET_DETECT_HOTSPOTS_CMD 0x58 #define IWX_NET_DETECT_HOTSPOTS_QUERY_CMD 0x59 /* system group command IDs */ #define IWX_FSEQ_VER_MISMATCH_NOTIFICATION 0xff #define IWX_REPLY_MAX 0xff /* PHY_OPS subcommand IDs */ #define IWX_CMD_DTS_MEASUREMENT_TRIGGER_WIDE 0x0 #define IWX_CTDP_CONFIG_CMD 0x03 #define IWX_TEMP_REPORTING_THRESHOLDS_CMD 0x04 #define IWX_CT_KILL_NOTIFICATION 0xFE #define IWX_DTS_MEASUREMENT_NOTIF_WIDE 0xFF /* command groups */ #define IWX_LEGACY_GROUP 0x0 #define IWX_LONG_GROUP 0x1 #define IWX_SYSTEM_GROUP 0x2 #define IWX_MAC_CONF_GROUP 0x3 #define IWX_PHY_OPS_GROUP 0x4 #define IWX_DATA_PATH_GROUP 0x5 #define IWX_PROT_OFFLOAD_GROUP 0xb #define IWX_REGULATORY_AND_NVM_GROUP 0xc /* SYSTEM_GROUP group subcommand IDs */ #define IWX_SHARED_MEM_CFG_CMD 0x00 #define IWX_SOC_CONFIGURATION_CMD 0x01 #define IWX_INIT_EXTENDED_CFG_CMD 0x03 #define IWX_FW_ERROR_RECOVERY_CMD 0x07 /* DATA_PATH group subcommand IDs */ #define IWX_DQA_ENABLE_CMD 0x00 #define IWX_TLC_MNG_CONFIG_CMD 0x0f #define IWX_RX_NO_DATA_NOTIF 0xf5 #define IWX_TLC_MNG_UPDATE_NOTIF 0xf7 /* REGULATORY_AND_NVM group subcommand IDs */ #define IWX_NVM_ACCESS_COMPLETE 0x00 #define IWX_NVM_GET_INFO 0x02 #define IWX_TAS_CONFIG 0x03 #define IWX_PNVM_INIT_COMPLETE_NTFY 0xFE /* * struct iwx_dqa_enable_cmd * @cmd_queue: the TXQ number of the command queue */ struct iwx_dqa_enable_cmd { uint32_t cmd_queue; } __packed; /* DQA_CONTROL_CMD_API_S_VER_1 */ struct iwx_sku_id { uint32_t data[3]; } __packed; /* SKU_ID_API_S_VER_1 */ /** * struct iwx_cmd_response - generic response struct for most commands * @status: status of the command asked, changes for each one */ struct iwx_cmd_response { uint32_t status; }; /* * struct iwx_tx_ant_cfg_cmd * @valid: valid antenna configuration */ struct iwx_tx_ant_cfg_cmd { uint32_t valid; } __packed; /* * Calibration control struct. * Sent as part of the phy configuration command. * @flow_trigger: bitmap for which calibrations to perform according to * flow triggers. * @event_trigger: bitmap for which calibrations to perform according to * event triggers. */ struct iwx_calib_ctrl { uint32_t flow_trigger; uint32_t event_trigger; } __packed; /* This defines the bitmap of various calibrations to enable in both * init ucode and runtime ucode through IWX_CALIBRATION_CFG_CMD. */ #define IWX_CALIB_CFG_XTAL_IDX (1 << 0) #define IWX_CALIB_CFG_TEMPERATURE_IDX (1 << 1) #define IWX_CALIB_CFG_VOLTAGE_READ_IDX (1 << 2) #define IWX_CALIB_CFG_PAPD_IDX (1 << 3) #define IWX_CALIB_CFG_TX_PWR_IDX (1 << 4) #define IWX_CALIB_CFG_DC_IDX (1 << 5) #define IWX_CALIB_CFG_BB_FILTER_IDX (1 << 6) #define IWX_CALIB_CFG_LO_LEAKAGE_IDX (1 << 7) #define IWX_CALIB_CFG_TX_IQ_IDX (1 << 8) #define IWX_CALIB_CFG_TX_IQ_SKEW_IDX (1 << 9) #define IWX_CALIB_CFG_RX_IQ_IDX (1 << 10) #define IWX_CALIB_CFG_RX_IQ_SKEW_IDX (1 << 11) #define IWX_CALIB_CFG_SENSITIVITY_IDX (1 << 12) #define IWX_CALIB_CFG_CHAIN_NOISE_IDX (1 << 13) #define IWX_CALIB_CFG_DISCONNECTED_ANT_IDX (1 << 14) #define IWX_CALIB_CFG_ANT_COUPLING_IDX (1 << 15) #define IWX_CALIB_CFG_DAC_IDX (1 << 16) #define IWX_CALIB_CFG_ABS_IDX (1 << 17) #define IWX_CALIB_CFG_AGC_IDX (1 << 18) /** * struct iwx_phy_specific_cfg - specific PHY filter configuration * * Sent as part of the phy configuration command (v3) to configure specific FW * defined PHY filters that can be applied to each antenna. * * @filter_cfg_chain_a: filter config id for LMAC1 chain A * @filter_cfg_chain_b: filter config id for LMAC1 chain B * @filter_cfg_chain_c: filter config id for LMAC2 chain A * @filter_cfg_chain_d: filter config id for LMAC2 chain B * values: 0 - no filter; 0xffffffff - reserved; otherwise - filter id */ struct iwx_phy_specific_cfg { uint32_t filter_cfg_chain_a; uint32_t filter_cfg_chain_b; uint32_t filter_cfg_chain_c; uint32_t filter_cfg_chain_d; } __packed; /* PHY_SPECIFIC_CONFIGURATION_API_VER_1*/ /** * struct iwx_phy_cfg_cmd - Phy configuration command * * @phy_cfg: PHY configuration value, uses &enum iwx_fw_phy_cfg * @calib_control: calibration control data */ struct iwx_phy_cfg_cmd_v1 { uint32_t phy_cfg; struct iwx_calib_ctrl calib_control; } __packed; /** * struct iwx_phy_cfg_cmd_v3 - Phy configuration command (v3) * * @phy_cfg: PHY configuration value, uses &enum iwx_fw_phy_cfg * @calib_control: calibration control data * @phy_specific_cfg: configure predefined PHY filters */ struct iwx_phy_cfg_cmd_v3 { uint32_t phy_cfg; struct iwx_calib_ctrl calib_control; struct iwx_phy_specific_cfg phy_specific_cfg; } __packed; /* PHY_CONFIGURATION_CMD_API_S_VER_3 */ #define IWX_PHY_CFG_RADIO_TYPE ((1 << 0) | (1 << 1)) #define IWX_PHY_CFG_RADIO_STEP ((1 << 2) | (1 << 3)) #define IWX_PHY_CFG_RADIO_DASH ((1 << 4) | (1 << 5)) #define IWX_PHY_CFG_PRODUCT_NUMBER ((1 << 6) | (1 << 7)) #define IWX_PHY_CFG_TX_CHAIN_A (1 << 8) #define IWX_PHY_CFG_TX_CHAIN_B (1 << 9) #define IWX_PHY_CFG_TX_CHAIN_C (1 << 10) #define IWX_PHY_CFG_RX_CHAIN_A (1 << 12) #define IWX_PHY_CFG_RX_CHAIN_B (1 << 13) #define IWX_PHY_CFG_RX_CHAIN_C (1 << 14) #define IWX_MAX_DTS_TRIPS 8 /** * struct iwx_ct_kill_notif - CT-kill entry notification * * @temperature: the current temperature in celsius * @reserved: reserved */ struct iwx_ct_kill_notif { uint16_t temperature; uint16_t reserved; } __packed; /* GRP_PHY_CT_KILL_NTF */ /** * struct iwx_temp_report_ths_cmd - set temperature thresholds * (IWX_TEMP_REPORTING_THRESHOLDS_CMD) * * @num_temps: number of temperature thresholds passed * @thresholds: array with the thresholds to be configured */ struct iwx_temp_report_ths_cmd { uint32_t num_temps; uint16_t thresholds[IWX_MAX_DTS_TRIPS]; } __packed; /* GRP_PHY_TEMP_REPORTING_THRESHOLDS_CMD */ /* * channel flags in NVM * @IWX_NVM_CHANNEL_VALID: channel is usable for this SKU/geo * @IWX_NVM_CHANNEL_IBSS: usable as an IBSS channel * @IWX_NVM_CHANNEL_ACTIVE: active scanning allowed * @IWX_NVM_CHANNEL_RADAR: radar detection required * @IWX_NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed * @IWX_NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS * on same channel on 2.4 or same UNII band on 5.2 * @IWX_NVM_CHANNEL_DFS: dynamic freq selection candidate * @IWX_NVM_CHANNEL_WIDE: 20 MHz channel okay (?) * @IWX_NVM_CHANNEL_40MHZ: 40 MHz channel okay (?) * @IWX_NVM_CHANNEL_80MHZ: 80 MHz channel okay (?) * @IWX_NVM_CHANNEL_160MHZ: 160 MHz channel okay (?) * @IWX_NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?) */ #define IWX_NVM_CHANNEL_VALID (1 << 0) #define IWX_NVM_CHANNEL_IBSS (1 << 1) #define IWX_NVM_CHANNEL_ACTIVE (1 << 3) #define IWX_NVM_CHANNEL_RADAR (1 << 4) #define IWX_NVM_CHANNEL_INDOOR_ONLY (1 << 5) #define IWX_NVM_CHANNEL_GO_CONCURRENT (1 << 6) #define IWX_NVM_CHANNEL_DFS (1 << 7) #define IWX_NVM_CHANNEL_WIDE (1 << 8) #define IWX_NVM_CHANNEL_40MHZ (1 << 9) #define IWX_NVM_CHANNEL_80MHZ (1 << 10) #define IWX_NVM_CHANNEL_160MHZ (1 << 11) #define IWX_NVM_CHANNEL_DC_HIGH (1 << 12) /** * struct iwx_nvm_access_complete_cmd - NVM_ACCESS commands are completed * @reserved: reserved */ struct iwx_nvm_access_complete_cmd { uint32_t reserved; } __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */ /* * struct iwx_nvm_get_info - request to get NVM data */ struct iwx_nvm_get_info { uint32_t reserved; } __packed; /* REGULATORY_NVM_GET_INFO_CMD_API_S_VER_1 */ /** * enum iwx_nvm_info_general_flags - flags in NVM_GET_INFO resp * @NVM_GENERAL_FLAGS_EMPTY_OTP: 1 if OTP is empty */ #define IWX_NVM_GENERAL_FLAGS_EMPTY_OTP (1 << 0) /** * struct iwx_nvm_get_info_general - general NVM data * @flags: bit 0: 1 - empty, 0 - non-empty * @nvm_version: nvm version * @board_type: board type * @n_hw_addrs: number of reserved MAC addresses */ struct iwx_nvm_get_info_general { uint32_t flags; uint16_t nvm_version; uint8_t board_type; uint8_t n_hw_addrs; } __packed; /* REGULATORY_NVM_GET_INFO_GENERAL_S_VER_2 */ /** * iwx_nvm_mac_sku_flags - flags in &iwl_nvm_get_info_sku * @NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED: true if 2.4 band enabled * @NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED: true if 5.2 band enabled * @NVM_MAC_SKU_FLAGS_802_11N_ENABLED: true if 11n enabled * @NVM_MAC_SKU_FLAGS_802_11AC_ENABLED: true if 11ac enabled * @NVM_MAC_SKU_FLAGS_802_11AX_ENABLED: true if 11ax enabled * @NVM_MAC_SKU_FLAGS_MIMO_DISABLED: true if MIMO disabled * @NVM_MAC_SKU_FLAGS_WAPI_ENABLED: true if WAPI enabled * @NVM_MAC_SKU_FLAGS_REG_CHECK_ENABLED: true if regulatory checker enabled * @NVM_MAC_SKU_FLAGS_API_LOCK_ENABLED: true if API lock enabled */ #define IWX_NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED (1 << 0) #define IWX_NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED (1 << 1) #define IWX_NVM_MAC_SKU_FLAGS_802_11N_ENABLED (1 << 2) #define IWX_NVM_MAC_SKU_FLAGS_802_11AC_ENABLED (1 << 3) #define IWX_NVM_MAC_SKU_FLAGS_802_11AX_ENABLED (1 << 4) #define IWX_NVM_MAC_SKU_FLAGS_MIMO_DISABLED (1 << 5) #define IWX_NVM_MAC_SKU_FLAGS_WAPI_ENABLED (1 << 8) #define IWX_NVM_MAC_SKU_FLAGS_REG_CHECK_ENABLED (1 << 14) #define IWX_NVM_MAC_SKU_FLAGS_API_LOCK_ENABLED (1 << 15) /** * struct iwx_nvm_get_info_sku - mac information * @mac_sku_flags: flags for SKU, see &enum iwl_nvm_mac_sku_flags */ struct iwx_nvm_get_info_sku { uint32_t mac_sku_flags; } __packed; /* REGULATORY_NVM_GET_INFO_MAC_SKU_SECTION_S_VER_2 */ /** * struct iwx_nvm_get_info_phy - phy information * @tx_chains: BIT 0 chain A, BIT 1 chain B * @rx_chains: BIT 0 chain A, BIT 1 chain B */ struct iwx_nvm_get_info_phy { uint32_t tx_chains; uint32_t rx_chains; } __packed; /* REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ #define IWX_NUM_CHANNELS_V1 51 #define IWX_NUM_CHANNELS 110 /** * struct iwx_nvm_get_info_regulatory - regulatory information * @lar_enabled: is LAR enabled * @channel_profile: regulatory data of this channel * @reserved: reserved */ struct iwx_nvm_get_info_regulatory_v1 { uint32_t lar_enabled; uint16_t channel_profile[IWX_NUM_CHANNELS_V1]; uint16_t reserved; } __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */ /** * struct iwx_nvm_get_info_regulatory - regulatory information * @lar_enabled: is LAR enabled * @n_channels: number of valid channels in the array * @channel_profile: regulatory data of this channel */ struct iwx_nvm_get_info_regulatory { uint32_t lar_enabled; uint32_t n_channels; uint32_t channel_profile[IWX_NUM_CHANNELS]; } __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_2 */ /** * struct iwx_nvm_get_info_rsp_v3 - response to get NVM data * @general: general NVM data * @mac_sku: data relating to MAC sku * @phy_sku: data relating to PHY sku * @regulatory: regulatory data */ struct iwx_nvm_get_info_rsp_v3 { struct iwx_nvm_get_info_general general; struct iwx_nvm_get_info_sku mac_sku; struct iwx_nvm_get_info_phy phy_sku; struct iwx_nvm_get_info_regulatory_v1 regulatory; } __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_3 */ /** * struct iwx_nvm_get_info_rsp - response to get NVM data * @general: general NVM data * @mac_sku: data relating to MAC sku * @phy_sku: data relating to PHY sku * @regulatory: regulatory data */ struct iwx_nvm_get_info_rsp { struct iwx_nvm_get_info_general general; struct iwx_nvm_get_info_sku mac_sku; struct iwx_nvm_get_info_phy phy_sku; struct iwx_nvm_get_info_regulatory regulatory; } __packed; /* REGULATORY_NVM_GET_INFO_RSP_API_S_VER_4 */ #define IWX_ALIVE_STATUS_ERR 0xDEAD #define IWX_ALIVE_STATUS_OK 0xCAFE struct iwx_lmac_debug_addrs { uint32_t error_event_table_ptr; /* SRAM address for error log */ uint32_t log_event_table_ptr; /* SRAM address for LMAC event log */ uint32_t cpu_register_ptr; uint32_t dbgm_config_ptr; uint32_t alive_counter_ptr; uint32_t scd_base_ptr; /* SRAM address for SCD */ uint32_t st_fwrd_addr; /* pointer to Store and forward */ uint32_t st_fwrd_size; } __packed; /* UCODE_DEBUG_ADDRS_API_S_VER_2 */ struct iwx_lmac_alive { uint32_t ucode_major; uint32_t ucode_minor; uint8_t ver_subtype; uint8_t ver_type; uint8_t mac; uint8_t opt; uint32_t timestamp; struct iwx_lmac_debug_addrs dbg_ptrs; } __packed; /* UCODE_ALIVE_NTFY_API_S_VER_3 */ struct iwx_umac_debug_addrs { uint32_t error_info_addr; /* SRAM address for UMAC error log */ uint32_t dbg_print_buff_addr; } __packed; /* UMAC_DEBUG_ADDRS_API_S_VER_1 */ struct iwx_umac_alive { uint32_t umac_major; /* UMAC version: major */ uint32_t umac_minor; /* UMAC version: minor */ struct iwx_umac_debug_addrs dbg_ptrs; } __packed; /* UMAC_ALIVE_DATA_API_S_VER_2 */ struct iwx_alive_resp_v4 { uint16_t status; uint16_t flags; struct iwx_lmac_alive lmac_data[2]; struct iwx_umac_alive umac_data; } __packed; /* ALIVE_RES_API_S_VER_4 */ struct iwx_alive_resp_v5 { uint16_t status; uint16_t flags; struct iwx_lmac_alive lmac_data[2]; struct iwx_umac_alive umac_data; struct iwx_sku_id sku_id; } __packed; /* UCODE_ALIVE_NTFY_API_S_VER_5 */ #define IWX_SOC_CONFIG_CMD_FLAGS_DISCRETE (1 << 0) #define IWX_SOC_CONFIG_CMD_FLAGS_LOW_LATENCY (1 << 1) #define IWX_SOC_FLAGS_LTR_APPLY_DELAY_MASK 0xc #define IWX_SOC_FLAGS_LTR_APPLY_DELAY_NONE 0 #define IWX_SOC_FLAGS_LTR_APPLY_DELAY_200 1 #define IWX_SOC_FLAGS_LTR_APPLY_DELAY_2500 2 #define IWX_SOC_FLAGS_LTR_APPLY_DELAY_1820 3 /** * struct iwx_soc_configuration_cmd - Set device stabilization latency * * @flags: soc settings flags. In VER_1, we can only set the DISCRETE * flag, because the FW treats the whole value as an integer. In * VER_2, we can set the bits independently. * @latency: time for SOC to ensure stable power & XTAL */ struct iwx_soc_configuration_cmd { uint32_t flags; uint32_t latency; } __packed; /* * SOC_CONFIGURATION_CMD_S_VER_1 (see description above) * SOC_CONFIGURATION_CMD_S_VER_2 */ /** * commands driver may send before finishing init flow * @IWX_INIT_DEBUG_CFG: driver is going to send debug config command * @IWX_INIT_NVM: driver is going to send NVM_ACCESS commands * @IWX_INIT_PHY: driver is going to send PHY_DB commands */ #define IWX_INIT_DEBUG_CFG (1 << 0) #define IWX_INIT_NVM (1 << 1) #define IWX_INIT_PHY (1 << 2) /** * struct iwx_extended_cfg_cmd - mark what commands ucode should wait for * before finishing init flows * @init_flags: IWX_INIT_* flag bits */ struct iwx_init_extended_cfg_cmd { uint32_t init_flags; } __packed; /* INIT_EXTENDED_CFG_CMD_API_S_VER_1 */ /* Error response/notification */ #define IWX_FW_ERR_UNKNOWN_CMD 0x0 #define IWX_FW_ERR_INVALID_CMD_PARAM 0x1 #define IWX_FW_ERR_SERVICE 0x2 #define IWX_FW_ERR_ARC_MEMORY 0x3 #define IWX_FW_ERR_ARC_CODE 0x4 #define IWX_FW_ERR_WATCH_DOG 0x5 #define IWX_FW_ERR_WEP_GRP_KEY_INDX 0x10 #define IWX_FW_ERR_WEP_KEY_SIZE 0x11 #define IWX_FW_ERR_OBSOLETE_FUNC 0x12 #define IWX_FW_ERR_UNEXPECTED 0xFE #define IWX_FW_ERR_FATAL 0xFF /** * struct iwx_error_resp - FW error indication * ( IWX_REPLY_ERROR = 0x2 ) * @error_type: one of IWX_FW_ERR_* * @cmd_id: the command ID for which the error occured * @bad_cmd_seq_num: sequence number of the erroneous command * @error_service: which service created the error, applicable only if * error_type = 2, otherwise 0 * @timestamp: TSF in usecs. */ struct iwx_error_resp { uint32_t error_type; uint8_t cmd_id; uint8_t reserved1; uint16_t bad_cmd_seq_num; uint32_t error_service; uint64_t timestamp; } __packed; enum iwx_fw_dbg_reg_operator { CSR_ASSIGN, CSR_SETBIT, CSR_CLEARBIT, PRPH_ASSIGN, PRPH_SETBIT, PRPH_CLEARBIT, INDIRECT_ASSIGN, INDIRECT_SETBIT, INDIRECT_CLEARBIT, PRPH_BLOCKBIT, }; /** * struct iwx_fw_dbg_reg_op - an operation on a register * * @op: &enum iwx_fw_dbg_reg_operator * @addr: offset of the register * @val: value */ struct iwx_fw_dbg_reg_op { uint8_t op; uint8_t reserved[3]; uint32_t addr; uint32_t val; } __packed; /** * enum iwx_fw_dbg_monitor_mode - available monitor recording modes * * @SMEM_MODE: monitor stores the data in SMEM * @EXTERNAL_MODE: monitor stores the data in allocated DRAM * @MARBH_MODE: monitor stores the data in MARBH buffer * @MIPI_MODE: monitor outputs the data through the MIPI interface */ enum iwx_fw_dbg_monitor_mode { SMEM_MODE = 0, EXTERNAL_MODE = 1, MARBH_MODE = 2, MIPI_MODE = 3, }; /** * struct iwx_fw_dbg_mem_seg_tlv - configures the debug data memory segments * * @data_type: the memory segment type to record * @ofs: the memory segment offset * @len: the memory segment length, in bytes * * This parses IWX_UCODE_TLV_FW_MEM_SEG */ struct iwx_fw_dbg_mem_seg_tlv { uint32_t data_type; uint32_t ofs; uint32_t len; } __packed; /** * struct iwx_fw_dbg_dest_tlv_v1 - configures the destination of the debug data * * @version: version of the TLV - currently 0 * @monitor_mode: &enum iwx_fw_dbg_monitor_mode * @size_power: buffer size will be 2^(size_power + 11) * @base_reg: addr of the base addr register (PRPH) * @end_reg: addr of the end addr register (PRPH) * @write_ptr_reg: the addr of the reg of the write pointer * @wrap_count: the addr of the reg of the wrap_count * @base_shift: shift right of the base addr reg * @end_shift: shift right of the end addr reg * @reg_ops: array of registers operations * * This parses IWX_UCODE_TLV_FW_DBG_DEST */ struct iwx_fw_dbg_dest_tlv_v1 { uint8_t version; uint8_t monitor_mode; uint8_t size_power; uint8_t reserved; uint32_t base_reg; uint32_t end_reg; uint32_t write_ptr_reg; uint32_t wrap_count; uint8_t base_shift; uint8_t end_shift; struct iwx_fw_dbg_reg_op reg_ops[0]; } __packed; /* Mask of the register for defining the LDBG MAC2SMEM buffer SMEM size */ #define IWX_LDBG_M2S_BUF_SIZE_MSK 0x0fff0000 /* Mask of the register for defining the LDBG MAC2SMEM SMEM base address */ #define IWX_LDBG_M2S_BUF_BA_MSK 0x00000fff /* The smem buffer chunks are in units of 256 bits */ #define IWX_M2S_UNIT_SIZE 0x100 struct iwx_fw_dbg_dest_tlv { uint8_t version; uint8_t monitor_mode; uint8_t size_power; uint8_t reserved; uint32_t cfg_reg; uint32_t write_ptr_reg; uint32_t wrap_count; uint8_t base_shift; uint8_t size_shift; struct iwx_fw_dbg_reg_op reg_ops[0]; } __packed; struct iwx_fw_dbg_conf_hcmd { uint8_t id; uint8_t reserved; uint16_t len; uint8_t data[0]; } __packed; /** * enum iwx_fw_dbg_trigger_mode - triggers functionalities * * @IWX_FW_DBG_TRIGGER_START: when trigger occurs re-conf the dbg mechanism * @IWX_FW_DBG_TRIGGER_STOP: when trigger occurs pull the dbg data * @IWX_FW_DBG_TRIGGER_MONITOR_ONLY: when trigger occurs trigger is set to * collect only monitor data */ enum iwx_fw_dbg_trigger_mode { IWX_FW_DBG_TRIGGER_START = (1 << 0), IWX_FW_DBG_TRIGGER_STOP = (1 << 1), IWX_FW_DBG_TRIGGER_MONITOR_ONLY = (1 << 2), }; /** * enum iwx_fw_dbg_trigger_flags - the flags supported by wrt triggers * @IWX_FW_DBG_FORCE_RESTART: force a firmware restart */ enum iwx_fw_dbg_trigger_flags { IWX_FW_DBG_FORCE_RESTART = (1 << 0), }; /** * enum iwx_fw_dbg_trigger_vif_type - define the VIF type for a trigger * @IWX_FW_DBG_CONF_VIF_ANY: any vif type * @IWX_FW_DBG_CONF_VIF_IBSS: IBSS mode * @IWX_FW_DBG_CONF_VIF_STATION: BSS mode * @IWX_FW_DBG_CONF_VIF_AP: AP mode * @IWX_FW_DBG_CONF_VIF_P2P_CLIENT: P2P Client mode * @IWX_FW_DBG_CONF_VIF_P2P_GO: P2P GO mode * @IWX_FW_DBG_CONF_VIF_P2P_DEVICE: P2P device * @IWX_FW_DBG_CONF_VIF_NAN: NAN device */ enum iwx_fw_dbg_trigger_vif_type { IWX_FW_DBG_CONF_VIF_ANY = 0, IWX_FW_DBG_CONF_VIF_IBSS = 1, IWX_FW_DBG_CONF_VIF_STATION = 2, IWX_FW_DBG_CONF_VIF_AP = 3, IWX_FW_DBG_CONF_VIF_P2P_CLIENT = 8, IWX_FW_DBG_CONF_VIF_P2P_GO = 9, IWX_FW_DBG_CONF_VIF_P2P_DEVICE = 10, IWX_FW_DBG_CONF_VIF_NAN = 12, }; /** * enum iwl_fw_dbg_trigger - triggers available * * @FW_DBG_TRIGGER_USER: trigger log collection by user * This should not be defined as a trigger to the driver, but a value the * driver should set to indicate that the trigger was initiated by the * user. * @FW_DBG_TRIGGER_FW_ASSERT: trigger log collection when the firmware asserts * @FW_DBG_TRIGGER_MISSED_BEACONS: trigger log collection when beacons are * missed. * @FW_DBG_TRIGGER_CHANNEL_SWITCH: trigger log collection upon channel switch. * @FW_DBG_TRIGGER_FW_NOTIF: trigger log collection when the firmware sends a * command response or a notification. * @FW_DBG_TRIGGER_MLME: trigger log collection upon MLME event. * @FW_DBG_TRIGGER_STATS: trigger log collection upon statistics threshold. * @FW_DBG_TRIGGER_RSSI: trigger log collection when the rssi of the beacon * goes below a threshold. * @FW_DBG_TRIGGER_TXQ_TIMERS: configures the timers for the Tx queue hang * detection. * @FW_DBG_TRIGGER_TIME_EVENT: trigger log collection upon time events related * events. * @FW_DBG_TRIGGER_BA: trigger log collection upon BlockAck related events. * @FW_DBG_TX_LATENCY: trigger log collection when the tx latency goes above a * threshold. * @FW_DBG_TDLS: trigger log collection upon TDLS related events. * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when * the firmware sends a tx reply. * @FW_DBG_TRIGGER_USER_EXTENDED: trigger log collection upon user space * request. * @FW_DBG_TRIGGER_ALIVE_TIMEOUT: trigger log collection if alive flow timeouts * @FW_DBG_TRIGGER_DRIVER: trigger log collection upon a flow failure * in the driver. */ enum iwx_fw_dbg_trigger { IWX_FW_DBG_TRIGGER_INVALID = 0, IWX_FW_DBG_TRIGGER_USER, IWX_FW_DBG_TRIGGER_FW_ASSERT, IWX_FW_DBG_TRIGGER_MISSED_BEACONS, IWX_FW_DBG_TRIGGER_CHANNEL_SWITCH, IWX_FW_DBG_TRIGGER_FW_NOTIF, IWX_FW_DBG_TRIGGER_MLME, IWX_FW_DBG_TRIGGER_STATS, IWX_FW_DBG_TRIGGER_RSSI, IWX_FW_DBG_TRIGGER_TXQ_TIMERS, IWX_FW_DBG_TRIGGER_TIME_EVENT, IWX_FW_DBG_TRIGGER_BA, IWX_FW_DBG_TRIGGER_TX_LATENCY, IWX_FW_DBG_TRIGGER_TDLS, IWX_FW_DBG_TRIGGER_TX_STATUS, IWX_FW_DBG_TRIGGER_USER_EXTENDED, IWX_FW_DBG_TRIGGER_ALIVE_TIMEOUT, IWX_FW_DBG_TRIGGER_DRIVER, /* must be last */ IWX_FW_DBG_TRIGGER_MAX, }; /** * struct iwx_fw_dbg_trigger_tlv - a TLV that describes the trigger * @id: &enum iwx_fw_dbg_trigger * @vif_type: &enum iwx_fw_dbg_trigger_vif_type * @stop_conf_ids: bitmap of configurations this trigger relates to. * if the mode is %IWX_FW_DBG_TRIGGER_STOP, then if the bit corresponding * to the currently running configuration is set, the data should be * collected. * @stop_delay: how many milliseconds to wait before collecting the data * after the STOP trigger fires. * @mode: &enum iwx_fw_dbg_trigger_mode - can be stop / start of both * @start_conf_id: if mode is %IWX_FW_DBG_TRIGGER_START, this defines what * configuration should be applied when the triggers kicks in. * @occurrences: number of occurrences. 0 means the trigger will never fire. * @trig_dis_ms: the time, in milliseconds, after an occurrence of this * trigger in which another occurrence should be ignored. * @flags: &enum iwx_fw_dbg_trigger_flags */ struct iwx_fw_dbg_trigger_tlv { uint32_t id; uint32_t vif_type; uint32_t stop_conf_ids; uint32_t stop_delay; uint8_t mode; uint8_t start_conf_id; uint16_t occurrences; uint16_t trig_dis_ms; uint8_t flags; uint8_t reserved[5]; uint8_t data[0]; } __packed; #define IWX_FW_DBG_START_FROM_ALIVE 0 #define IWX_FW_DBG_CONF_MAX 32 #define IWX_FW_DBG_INVALID 0xff /** * struct iwx_fw_dbg_trigger_missed_bcon - configures trigger for missed beacons * @stop_consec_missed_bcon: stop recording if threshold is crossed. * @stop_consec_missed_bcon_since_rx: stop recording if threshold is crossed. * @start_consec_missed_bcon: start recording if threshold is crossed. * @start_consec_missed_bcon_since_rx: start recording if threshold is crossed. * @reserved1: reserved * @reserved2: reserved */ struct iwx_fw_dbg_trigger_missed_bcon { uint32_t stop_consec_missed_bcon; uint32_t stop_consec_missed_bcon_since_rx; uint32_t reserved2[2]; uint32_t start_consec_missed_bcon; uint32_t start_consec_missed_bcon_since_rx; uint32_t reserved1[2]; } __packed; /** * struct iwx_fw_dbg_trigger_cmd - configures trigger for messages from FW. * cmds: the list of commands to trigger the collection on */ struct iwx_fw_dbg_trigger_cmd { struct cmd { uint8_t cmd_id; uint8_t group_id; } __packed cmds[16]; } __packed; /** * iwx_fw_dbg_trigger_stats - configures trigger for statistics * @stop_offset: the offset of the value to be monitored * @stop_threshold: the threshold above which to collect * @start_offset: the offset of the value to be monitored * @start_threshold: the threshold above which to start recording */ struct iwx_fw_dbg_trigger_stats { uint32_t stop_offset; uint32_t stop_threshold; uint32_t start_offset; uint32_t start_threshold; } __packed; /** * struct iwx_fw_dbg_trigger_low_rssi - trigger for low beacon RSSI * @rssi: RSSI value to trigger at */ struct iwx_fw_dbg_trigger_low_rssi { uint32_t rssi; } __packed; /** * struct iwx_fw_dbg_trigger_mlme - configures trigger for mlme events * @stop_auth_denied: number of denied authentication to collect * @stop_auth_timeout: number of authentication timeout to collect * @stop_rx_deauth: number of Rx deauth before to collect * @stop_tx_deauth: number of Tx deauth before to collect * @stop_assoc_denied: number of denied association to collect * @stop_assoc_timeout: number of association timeout to collect * @stop_connection_loss: number of connection loss to collect * @start_auth_denied: number of denied authentication to start recording * @start_auth_timeout: number of authentication timeout to start recording * @start_rx_deauth: number of Rx deauth to start recording * @start_tx_deauth: number of Tx deauth to start recording * @start_assoc_denied: number of denied association to start recording * @start_assoc_timeout: number of association timeout to start recording * @start_connection_loss: number of connection loss to start recording */ struct iwx_fw_dbg_trigger_mlme { uint8_t stop_auth_denied; uint8_t stop_auth_timeout; uint8_t stop_rx_deauth; uint8_t stop_tx_deauth; uint8_t stop_assoc_denied; uint8_t stop_assoc_timeout; uint8_t stop_connection_loss; uint8_t reserved; uint8_t start_auth_denied; uint8_t start_auth_timeout; uint8_t start_rx_deauth; uint8_t start_tx_deauth; uint8_t start_assoc_denied; uint8_t start_assoc_timeout; uint8_t start_connection_loss; uint8_t reserved2; } __packed; /** * struct iwx_fw_dbg_trigger_txq_timer - configures the Tx queue's timer * @command_queue: timeout for the command queue in ms * @bss: timeout for the queues of a BSS (except for TDLS queues) in ms * @softap: timeout for the queues of a softAP in ms * @p2p_go: timeout for the queues of a P2P GO in ms * @p2p_client: timeout for the queues of a P2P client in ms * @p2p_device: timeout for the queues of a P2P device in ms * @ibss: timeout for the queues of an IBSS in ms * @tdls: timeout for the queues of a TDLS station in ms */ struct iwx_fw_dbg_trigger_txq_timer { uint32_t command_queue; uint32_t bss; uint32_t softap; uint32_t p2p_go; uint32_t p2p_client; uint32_t p2p_device; uint32_t ibss; uint32_t tdls; uint32_t reserved[4]; } __packed; /** * struct iwx_fw_dbg_trigger_time_event - configures a time event trigger * time_Events: a list of tuples . The driver will issue a * trigger each time a time event notification that relates to time event * id with one of the actions in the bitmap is received and * BIT(notif->status) is set in status_bitmap. * */ struct iwx_fw_dbg_trigger_time_event { struct { uint32_t id; uint32_t action_bitmap; uint32_t status_bitmap; } __packed time_events[16]; } __packed; /** * struct iwx_fw_dbg_trigger_ba - configures BlockAck related trigger * rx_ba_start: tid bitmap to configure on what tid the trigger should occur * when an Rx BlockAck session is started. * rx_ba_stop: tid bitmap to configure on what tid the trigger should occur * when an Rx BlockAck session is stopped. * tx_ba_start: tid bitmap to configure on what tid the trigger should occur * when a Tx BlockAck session is started. * tx_ba_stop: tid bitmap to configure on what tid the trigger should occur * when a Tx BlockAck session is stopped. * rx_bar: tid bitmap to configure on what tid the trigger should occur * when a BAR is received (for a Tx BlockAck session). * tx_bar: tid bitmap to configure on what tid the trigger should occur * when a BAR is send (for an Rx BlocAck session). * frame_timeout: tid bitmap to configure on what tid the trigger should occur * when a frame times out in the reodering buffer. */ struct iwx_fw_dbg_trigger_ba { uint16_t rx_ba_start; uint16_t rx_ba_stop; uint16_t tx_ba_start; uint16_t tx_ba_stop; uint16_t rx_bar; uint16_t tx_bar; uint16_t frame_timeout; } __packed; /** * struct iwx_fw_dbg_trigger_tx_latency - configures tx latency related trigger * @thrshold: the wanted threshold. * @tid_bitmap: the tid to apply the threshold on * @mode: recording mode (Internal buffer or continues recording) * @window: the size of the window before collecting. * @reserved: reserved. */ struct iwx_fw_dbg_trigger_tx_latency { uint32_t thrshold; uint16_t tid_bitmap; uint16_t mode; uint32_t window; uint32_t reserved[4]; } __packed; /** * struct iwx_fw_dbg_trigger_tdls - configures trigger for TDLS events. * @action_bitmap: the TDLS action to trigger the collection upon * @peer_mode: trigger on specific peer or all * @peer: the TDLS peer to trigger the collection on */ struct iwx_fw_dbg_trigger_tdls { uint8_t action_bitmap; uint8_t peer_mode; uint8_t peer[ETHER_ADDR_LEN]; uint8_t reserved[4]; } __packed; /** * struct iwx_fw_dbg_trigger_tx_status - configures trigger for tx response * status. * @statuses: the list of statuses to trigger the collection on */ struct iwx_fw_dbg_trigger_tx_status { struct tx_status { uint8_t status; uint8_t reserved[3]; } __packed statuses[16]; uint32_t reserved[2]; } __packed; /** * struct iwx_fw_dbg_conf_tlv - a TLV that describes a debug configuration. * @id: conf id * @usniffer: should the uSniffer image be used * @num_of_hcmds: how many HCMDs to send are present here * @hcmd: a variable length host command to be sent to apply the configuration. * If there is more than one HCMD to send, they will appear one after the * other and be sent in the order that they appear in. * This parses IWX_UCODE_TLV_FW_DBG_CONF. The user can add up-to * %IWX_FW_DBG_CONF_MAX configuration per run. */ struct iwx_fw_dbg_conf_tlv { uint8_t id; uint8_t usniffer; uint8_t reserved; uint8_t num_of_hcmds; struct iwx_fw_dbg_conf_hcmd hcmd; } __packed; #define IWX_FW_CMD_VER_UNKNOWN 99 /** * struct iwx_fw_cmd_version - firmware command version entry * @cmd: command ID * @group: group ID * @cmd_ver: command version * @notif_ver: notification version */ struct iwx_fw_cmd_version { uint8_t cmd; uint8_t group; uint8_t cmd_ver; uint8_t notif_ver; } __packed; /* Common PHY, MAC and Bindings definitions */ #define IWX_MAX_MACS_IN_BINDING (3) #define IWX_MAX_BINDINGS (4) #define IWX_AUX_BINDING_INDEX (3) #define IWX_MAX_PHYS (4) /* Used to extract ID and color from the context dword */ #define IWX_FW_CTXT_ID_POS (0) #define IWX_FW_CTXT_ID_MSK (0xff << IWX_FW_CTXT_ID_POS) #define IWX_FW_CTXT_COLOR_POS (8) #define IWX_FW_CTXT_COLOR_MSK (0xff << IWX_FW_CTXT_COLOR_POS) #define IWX_FW_CTXT_INVALID (0xffffffff) #define IWX_FW_CMD_ID_AND_COLOR(_id, _color) ((_id << IWX_FW_CTXT_ID_POS) |\ (_color << IWX_FW_CTXT_COLOR_POS)) /* Possible actions on PHYs, MACs and Bindings */ #define IWX_FW_CTXT_ACTION_STUB 0 #define IWX_FW_CTXT_ACTION_ADD 1 #define IWX_FW_CTXT_ACTION_MODIFY 2 #define IWX_FW_CTXT_ACTION_REMOVE 3 #define IWX_FW_CTXT_ACTION_NUM 4 /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ /* Time Events */ /* Time Event types, according to MAC type */ /* BSS Station Events */ #define IWX_TE_BSS_STA_AGGRESSIVE_ASSOC 0 #define IWX_TE_BSS_STA_ASSOC 1 #define IWX_TE_BSS_EAP_DHCP_PROT 2 #define IWX_TE_BSS_QUIET_PERIOD 3 /* P2P Device Events */ #define IWX_TE_P2P_DEVICE_DISCOVERABLE 4 #define IWX_TE_P2P_DEVICE_LISTEN 5 #define IWX_TE_P2P_DEVICE_ACTION_SCAN 6 #define IWX_TE_P2P_DEVICE_FULL_SCAN 7 /* P2P Client Events */ #define IWX_TE_P2P_CLIENT_AGGRESSIVE_ASSOC 8 #define IWX_TE_P2P_CLIENT_ASSOC 9 #define IWX_TE_P2P_CLIENT_QUIET_PERIOD 10 /* P2P GO Events */ #define IWX_TE_P2P_GO_ASSOC_PROT 11 #define IWX_TE_P2P_GO_REPETITIVE_NOA 12 #define IWX_TE_P2P_GO_CT_WINDOW 13 /* WiDi Sync Events */ #define IWX_TE_WIDI_TX_SYNC 14 /* Time event - defines for command API */ /** * DOC: Time Events - what is it? * * Time Events are a fw feature that allows the driver to control the presence * of the device on the channel. Since the fw supports multiple channels * concurrently, the fw may choose to jump to another channel at any time. * In order to make sure that the fw is on a specific channel at a certain time * and for a certain duration, the driver needs to issue a time event. * * The simplest example is for BSS association. The driver issues a time event, * waits for it to start, and only then tells mac80211 that we can start the * association. This way, we make sure that the association will be done * smoothly and won't be interrupted by channel switch decided within the fw. */ /** * DOC: The flow against the fw * * When the driver needs to make sure we are in a certain channel, at a certain * time and for a certain duration, it sends a Time Event. The flow against the * fw goes like this: * 1) Driver sends a TIME_EVENT_CMD to the fw * 2) Driver gets the response for that command. This response contains the * Unique ID (UID) of the event. * 3) The fw sends notification when the event starts. * * Of course the API provides various options that allow to cover parameters * of the flow. * What is the duration of the event? * What is the start time of the event? * Is there an end-time for the event? * How much can the event be delayed? * Can the event be split? * If yes what is the maximal number of chunks? * etc... */ /* * @IWX_TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed. * @IWX_TE_V2_FRAG_SINGLE: fragmentation of the time event is allowed, but only * the first fragment is scheduled. * @IWX_TE_V2_FRAG_DUAL: fragmentation of the time event is allowed, but only * the first 2 fragments are scheduled. * @IWX_TE_V2_FRAG_ENDLESS: fragmentation of the time event is allowed, and any * number of fragments are valid. * * Other than the constant defined above, specifying a fragmentation value 'x' * means that the event can be fragmented but only the first 'x' will be * scheduled. */ #define IWX_TE_V2_FRAG_NONE 0 #define IWX_TE_V2_FRAG_SINGLE 1 #define IWX_TE_V2_FRAG_DUAL 2 #define IWX_TE_V2_FRAG_MAX 0xfe #define IWX_TE_V2_FRAG_ENDLESS 0xff /* Repeat the time event endlessly (until removed) */ #define IWX_TE_V2_REPEAT_ENDLESS 0xff /* If a Time Event has bounded repetitions, this is the maximal value */ #define IWX_TE_V2_REPEAT_MAX 0xfe #define IWX_TE_V2_PLACEMENT_POS 12 #define IWX_TE_V2_ABSENCE_POS 15 /* Time event policy values * A notification (both event and fragment) includes a status indicating weather * the FW was able to schedule the event or not. For fragment start/end * notification the status is always success. There is no start/end fragment * notification for monolithic events. * * @IWX_TE_V2_DEFAULT_POLICY: independent, social, present, unoticable * @IWX_TE_V2_NOTIF_HOST_EVENT_START: request/receive notification on event start * @IWX_TE_V2_NOTIF_HOST_EVENT_END:request/receive notification on event end * @IWX_TE_V2_NOTIF_INTERNAL_EVENT_START: internal FW use * @IWX_TE_V2_NOTIF_INTERNAL_EVENT_END: internal FW use. * @IWX_TE_V2_NOTIF_HOST_FRAG_START: request/receive notification on frag start * @IWX_TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end * @IWX_TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. * @IWX_TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. * @IWX_TE_V2_DEP_OTHER: depends on another time event * @IWX_TE_V2_DEP_TSF: depends on a specific time * @IWX_TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC * @IWX_TE_V2_ABSENCE: are we present or absent during the Time Event. */ #define IWX_TE_V2_DEFAULT_POLICY 0x0 /* notifications (event start/stop, fragment start/stop) */ #define IWX_TE_V2_NOTIF_HOST_EVENT_START (1 << 0) #define IWX_TE_V2_NOTIF_HOST_EVENT_END (1 << 1) #define IWX_TE_V2_NOTIF_INTERNAL_EVENT_START (1 << 2) #define IWX_TE_V2_NOTIF_INTERNAL_EVENT_END (1 << 3) #define IWX_TE_V2_NOTIF_HOST_FRAG_START (1 << 4) #define IWX_TE_V2_NOTIF_HOST_FRAG_END (1 << 5) #define IWX_TE_V2_NOTIF_INTERNAL_FRAG_START (1 << 6) #define IWX_TE_V2_NOTIF_INTERNAL_FRAG_END (1 << 7) #define IWX_T2_V2_START_IMMEDIATELY (1 << 11) #define IWX_TE_V2_NOTIF_MSK 0xff /* placement characteristics */ #define IWX_TE_V2_DEP_OTHER (1 << IWX_TE_V2_PLACEMENT_POS) #define IWX_TE_V2_DEP_TSF (1 << (IWX_TE_V2_PLACEMENT_POS + 1)) #define IWX_TE_V2_EVENT_SOCIOPATHIC (1 << (IWX_TE_V2_PLACEMENT_POS + 2)) /* are we present or absent during the Time Event. */ #define IWX_TE_V2_ABSENCE (1 << IWX_TE_V2_ABSENCE_POS) /** * struct iwx_time_event_cmd_api - configuring Time Events * with struct IWX_MAC_TIME_EVENT_DATA_API_S_VER_2 (see also * with version 1. determined by IWX_UCODE_TLV_FLAGS) * ( IWX_TIME_EVENT_CMD = 0x29 ) * @id_and_color: ID and color of the relevant MAC * @action: action to perform, one of IWX_FW_CTXT_ACTION_* * @id: this field has two meanings, depending on the action: * If the action is ADD, then it means the type of event to add. * For all other actions it is the unique event ID assigned when the * event was added by the FW. * @apply_time: When to start the Time Event (in GP2) * @max_delay: maximum delay to event's start (apply time), in TU * @depends_on: the unique ID of the event we depend on (if any) * @interval: interval between repetitions, in TU * @duration: duration of event in TU * @repeat: how many repetitions to do, can be IWX_TE_REPEAT_ENDLESS * @max_frags: maximal number of fragments the Time Event can be divided to * @policy: defines whether uCode shall notify the host or other uCode modules * on event and/or fragment start and/or end * using one of IWX_TE_INDEPENDENT, IWX_TE_DEP_OTHER, IWX_TE_DEP_TSF * IWX_TE_EVENT_SOCIOPATHIC * using IWX_TE_ABSENCE and using IWX_TE_NOTIF_* */ struct iwx_time_event_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; uint32_t id; /* IWX_MAC_TIME_EVENT_DATA_API_S_VER_2 */ uint32_t apply_time; uint32_t max_delay; uint32_t depends_on; uint32_t interval; uint32_t duration; uint8_t repeat; uint8_t max_frags; uint16_t policy; } __packed; /* IWX_MAC_TIME_EVENT_CMD_API_S_VER_2 */ /** * struct iwx_time_event_resp - response structure to iwx_time_event_cmd * @status: bit 0 indicates success, all others specify errors * @id: the Time Event type * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE * @id_and_color: ID and color of the relevant MAC */ struct iwx_time_event_resp { uint32_t status; uint32_t id; uint32_t unique_id; uint32_t id_and_color; } __packed; /* IWX_MAC_TIME_EVENT_RSP_API_S_VER_1 */ /** * struct iwx_time_event_notif - notifications of time event start/stop * ( IWX_TIME_EVENT_NOTIFICATION = 0x2a ) * @timestamp: action timestamp in GP2 * @session_id: session's unique id * @unique_id: unique id of the Time Event itself * @id_and_color: ID and color of the relevant MAC * @action: one of IWX_TE_NOTIF_START or IWX_TE_NOTIF_END * @status: true if scheduled, false otherwise (not executed) */ struct iwx_time_event_notif { uint32_t timestamp; uint32_t session_id; uint32_t unique_id; uint32_t id_and_color; uint32_t action; uint32_t status; } __packed; /* IWX_MAC_TIME_EVENT_NTFY_API_S_VER_1 */ #define IWX_SESSION_PROTECTION_CMD 0x5 #define IWX_SESSION_PROTECTION_NOTIF 0xFB #define IWX_SESSION_PROTECT_CONF_ASSOC 0 #define IWX_SESSION_PROTECT_CONF_GO_CLIENT_ASSOC 1 #define IWX_SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV 2 #define IWX_SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION 3 #define IWX_SESSION_PROTECT_CONF_MAX_ID 4 /** * struct iwx_session_prot_cmd - configure a session protection * @id_and_color: the id and color of the mac for which this session protection * is sent * @action: can be either FW_CTXT_ACTION_ADD or FW_CTXT_ACTION_REMOVE * @conf_id: see &enum iwl_mvm_session_prot_conf_id * @duration_tu: the duration of the whole protection in TUs. * @repetition_count: not used * @interval: not used * * Note: the session protection will always be scheduled to start as * early as possible, but the maximum delay is configuration dependent. * The firmware supports only one concurrent session protection per vif. * Adding a new session protection will remove any currently running session. */ struct iwx_session_prot_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 hdr */ uint32_t id_and_color; uint32_t action; uint32_t conf_id; uint32_t duration_tu; uint32_t repetition_count; uint32_t interval; } __packed; /* SESSION_PROTECTION_CMD_API_S_VER_1 */ /** * struct iwx_session_prot_notif - session protection started / ended * @mac_id: the mac id for which the session protection started / ended * @status: 1 means success, 0 means failure * @start: 1 means the session protection started, 0 means it ended * @conf_id: see &enum iwl_mvm_session_prot_conf_id * * Note that any session protection will always get two notifications: start * and end even the firmware could not schedule it. */ struct iwx_session_prot_notif { uint32_t mac_id; uint32_t status; uint32_t start; uint32_t conf_id; } __packed; /* SESSION_PROTECTION_NOTIFICATION_API_S_VER_2 */ /* Bindings and Time Quota */ /** * struct iwx_binding_cmd - configuring bindings * ( IWX_BINDING_CONTEXT_CMD = 0x2b ) * @id_and_color: ID and color of the relevant Binding * @action: action to perform, one of IWX_FW_CTXT_ACTION_* * @macs: array of MAC id and colors which belong to the binding * @phy: PHY id and color which belongs to the binding * @lmac_id: the lmac id the binding belongs to */ struct iwx_binding_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWX_BINDING_DATA_API_S_VER_1 */ uint32_t macs[IWX_MAX_MACS_IN_BINDING]; uint32_t phy; uint32_t lmac_id; } __packed; /* IWX_BINDING_CMD_API_S_VER_2 */ #define IWX_LMAC_24G_INDEX 0 #define IWX_LMAC_5G_INDEX 1 /* The maximal number of fragments in the FW's schedule session */ #define IWX_MAX_QUOTA 128 /** * struct iwx_time_quota_data - configuration of time quota per binding * @id_and_color: ID and color of the relevant Binding * @quota: absolute time quota in TU. The scheduler will try to divide the * remainig quota (after Time Events) according to this quota. * @max_duration: max uninterrupted context duration in TU */ struct iwx_time_quota_data { uint32_t id_and_color; uint32_t quota; uint32_t max_duration; } __packed; /* IWX_TIME_QUOTA_DATA_API_S_VER_1 */ /** * struct iwx_time_quota_cmd - configuration of time quota between bindings * ( IWX_TIME_QUOTA_CMD = 0x2c ) * @quotas: allocations per binding */ struct iwx_time_quota_cmd { struct iwx_time_quota_data quotas[IWX_MAX_BINDINGS]; } __packed; /* IWX_TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */ /* PHY context */ /* Supported bands */ #define IWX_PHY_BAND_5 (0) #define IWX_PHY_BAND_24 (1) /* Supported channel width, vary if there is VHT support */ #define IWX_PHY_VHT_CHANNEL_MODE20 (0x0) #define IWX_PHY_VHT_CHANNEL_MODE40 (0x1) #define IWX_PHY_VHT_CHANNEL_MODE80 (0x2) #define IWX_PHY_VHT_CHANNEL_MODE160 (0x3) /* * Control channel position: * For legacy set bit means upper channel, otherwise lower. * For VHT - bit-2 marks if the control is lower/upper relative to center-freq * bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0. * center_freq * | * 40Mhz |_______|_______| * 80Mhz |_______|_______|_______|_______| * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______| * code 011 010 001 000 | 100 101 110 111 */ #define IWX_PHY_VHT_CTRL_POS_1_BELOW (0x0) #define IWX_PHY_VHT_CTRL_POS_2_BELOW (0x1) #define IWX_PHY_VHT_CTRL_POS_3_BELOW (0x2) #define IWX_PHY_VHT_CTRL_POS_4_BELOW (0x3) #define IWX_PHY_VHT_CTRL_POS_1_ABOVE (0x4) #define IWX_PHY_VHT_CTRL_POS_2_ABOVE (0x5) #define IWX_PHY_VHT_CTRL_POS_3_ABOVE (0x6) #define IWX_PHY_VHT_CTRL_POS_4_ABOVE (0x7) /* * @band: IWX_PHY_BAND_* * @channel: channel number * @width: PHY_[VHT|LEGACY]_CHANNEL_* * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* */ struct iwx_fw_channel_info_v1 { uint8_t band; uint8_t channel; uint8_t width; uint8_t ctrl_pos; } __packed; /* CHANNEL_CONFIG_API_S_VER_1 */ /* * struct iwx_fw_channel_info - channel information * * @channel: channel number * @band: PHY_BAND_* * @width: PHY_[VHT|LEGACY]_CHANNEL_* * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* * @reserved: for future use and alignment */ struct iwx_fw_channel_info { uint32_t channel; uint8_t band; uint8_t width; uint8_t ctrl_pos; uint8_t reserved; } __packed; /*CHANNEL_CONFIG_API_S_VER_2 */ #define IWX_PHY_RX_CHAIN_DRIVER_FORCE_POS (0) #define IWX_PHY_RX_CHAIN_DRIVER_FORCE_MSK \ (0x1 << IWX_PHY_RX_CHAIN_DRIVER_FORCE_POS) #define IWX_PHY_RX_CHAIN_VALID_POS (1) #define IWX_PHY_RX_CHAIN_VALID_MSK \ (0x7 << IWX_PHY_RX_CHAIN_VALID_POS) #define IWX_PHY_RX_CHAIN_FORCE_SEL_POS (4) #define IWX_PHY_RX_CHAIN_FORCE_SEL_MSK \ (0x7 << IWX_PHY_RX_CHAIN_FORCE_SEL_POS) #define IWX_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS (7) #define IWX_PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK \ (0x7 << IWX_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS) #define IWX_PHY_RX_CHAIN_CNT_POS (10) #define IWX_PHY_RX_CHAIN_CNT_MSK \ (0x3 << IWX_PHY_RX_CHAIN_CNT_POS) #define IWX_PHY_RX_CHAIN_MIMO_CNT_POS (12) #define IWX_PHY_RX_CHAIN_MIMO_CNT_MSK \ (0x3 << IWX_PHY_RX_CHAIN_MIMO_CNT_POS) #define IWX_PHY_RX_CHAIN_MIMO_FORCE_POS (14) #define IWX_PHY_RX_CHAIN_MIMO_FORCE_MSK \ (0x1 << IWX_PHY_RX_CHAIN_MIMO_FORCE_POS) /* TODO: fix the value, make it depend on firmware at runtime? */ #define IWX_NUM_PHY_CTX 3 #define IWX_LMAC_24G_INDEX 0 #define IWX_LMAC_5G_INDEX 1 /* TODO: complete missing documentation */ /** * struct iwx_phy_context_cmd - config of the PHY context * ( IWX_PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding * @action: action to perform, one of IWX_FW_CTXT_ACTION_* * @apply_time: 0 means immediate apply and context switch. * other value means apply new params after X usecs * @tx_param_color: ??? * @channel_info: * @txchain_info: ??? * @rxchain_info: ??? * @acquisition_data: ??? * @dsp_cfg_flags: set to 0 */ /* * XXX Intel forgot to bump the PHY_CONTEXT command API when they increased * the size of fw_channel_info from v1 to v2. * To keep things simple we define two versions of this struct, and both * are labled as CMD_API_VER_1. (The Linux iwlwifi driver performs dark * magic with pointers to struct members instead.) */ /* This version must be used if IWX_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS is set: */ struct iwx_phy_context_cmd_uhb { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWX_PHY_CONTEXT_DATA_API_S_VER_1 */ uint32_t apply_time; uint32_t tx_param_color; struct iwx_fw_channel_info ci; uint32_t txchain_info; uint32_t rxchain_info; uint32_t acquisition_data; uint32_t dsp_cfg_flags; } __packed; /* IWX_PHY_CONTEXT_CMD_API_VER_1 */ /* This version must be used otherwise: */ struct iwx_phy_context_cmd_v1 { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWX_PHY_CONTEXT_DATA_API_S_VER_1 */ uint32_t apply_time; uint32_t tx_param_color; struct iwx_fw_channel_info_v1 ci; uint32_t txchain_info; uint32_t rxchain_info; uint32_t acquisition_data; uint32_t dsp_cfg_flags; } __packed; /* IWX_PHY_CONTEXT_CMD_API_VER_1 */ /** * struct iwx_phy_context_cmd - config of the PHY context * ( PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding * @action: action to perform, one of FW_CTXT_ACTION_* * @lmac_id: the lmac id the phy context belongs to * @ci: channel info * @rxchain_info: ??? * @dsp_cfg_flags: set to 0 * @reserved: reserved to align to 64 bit */ struct iwx_phy_context_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* PHY_CONTEXT_DATA_API_S_VER_3 */ struct iwx_fw_channel_info ci; uint32_t lmac_id; uint32_t rxchain_info; uint32_t dsp_cfg_flags; uint32_t reserved; } __packed; /* PHY_CONTEXT_CMD_API_VER_3 */ #define IWX_RX_INFO_PHY_CNT 8 #define IWX_RX_INFO_ENERGY_ANT_ABC_IDX 1 #define IWX_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff #define IWX_RX_INFO_ENERGY_ANT_B_MSK 0x0000ff00 #define IWX_RX_INFO_ENERGY_ANT_C_MSK 0x00ff0000 #define IWX_RX_INFO_ENERGY_ANT_A_POS 0 #define IWX_RX_INFO_ENERGY_ANT_B_POS 8 #define IWX_RX_INFO_ENERGY_ANT_C_POS 16 #define IWX_RX_INFO_AGC_IDX 1 #define IWX_RX_INFO_RSSI_AB_IDX 2 #define IWX_OFDM_AGC_A_MSK 0x0000007f #define IWX_OFDM_AGC_A_POS 0 #define IWX_OFDM_AGC_B_MSK 0x00003f80 #define IWX_OFDM_AGC_B_POS 7 #define IWX_OFDM_AGC_CODE_MSK 0x3fe00000 #define IWX_OFDM_AGC_CODE_POS 20 #define IWX_OFDM_RSSI_INBAND_A_MSK 0x00ff #define IWX_OFDM_RSSI_A_POS 0 #define IWX_OFDM_RSSI_ALLBAND_A_MSK 0xff00 #define IWX_OFDM_RSSI_ALLBAND_A_POS 8 #define IWX_OFDM_RSSI_INBAND_B_MSK 0xff0000 #define IWX_OFDM_RSSI_B_POS 16 #define IWX_OFDM_RSSI_ALLBAND_B_MSK 0xff000000 #define IWX_OFDM_RSSI_ALLBAND_B_POS 24 /** * struct iwx_rx_phy_info - phy info * (IWX_REPLY_RX_PHY_CMD = 0xc0) * @non_cfg_phy_cnt: non configurable DSP phy data byte count * @cfg_phy_cnt: configurable DSP phy data byte count * @stat_id: configurable DSP phy data set ID * @reserved1: * @system_timestamp: GP2 at on air rise * @timestamp: TSF at on air rise * @beacon_time_stamp: beacon at on-air rise * @phy_flags: general phy flags: band, modulation, ... * @channel: channel number * @non_cfg_phy_buf: for various implementations of non_cfg_phy * @rate_n_flags: IWX_RATE_MCS_* * @byte_count: frame's byte-count * @frame_time: frame's time on the air, based on byte count and frame rate * calculation * @mac_active_msk: what MACs were active when the frame was received * * Before each Rx, the device sends this data. It contains PHY information * about the reception of the packet. */ struct iwx_rx_phy_info { uint8_t non_cfg_phy_cnt; uint8_t cfg_phy_cnt; uint8_t stat_id; uint8_t reserved1; uint32_t system_timestamp; uint64_t timestamp; uint32_t beacon_time_stamp; uint16_t phy_flags; #define IWX_PHY_INFO_FLAG_SHPREAMBLE (1 << 2) uint16_t channel; uint32_t non_cfg_phy[IWX_RX_INFO_PHY_CNT]; uint32_t rate_n_flags; uint32_t byte_count; uint16_t mac_active_msk; uint16_t frame_time; } __packed; struct iwx_rx_mpdu_res_start { uint16_t byte_count; uint16_t reserved; } __packed; /** * Values to parse %iwx_rx_phy_info phy_flags * @IWX_RX_RES_PHY_FLAGS_BAND_24: true if the packet was received on 2.4 band * @IWX_RX_RES_PHY_FLAGS_MOD_CCK: * @IWX_RX_RES_PHY_FLAGS_SHORT_PREAMBLE: true if packet's preamble was short * @IWX_RX_RES_PHY_FLAGS_NARROW_BAND: * @IWX_RX_RES_PHY_FLAGS_ANTENNA: antenna on which the packet was received * @IWX_RX_RES_PHY_FLAGS_AGG: set if the packet was part of an A-MPDU * @IWX_RX_RES_PHY_FLAGS_OFDM_HT: The frame was an HT frame * @IWX_RX_RES_PHY_FLAGS_OFDM_GF: The frame used GF preamble * @IWX_RX_RES_PHY_FLAGS_OFDM_VHT: The frame was a VHT frame */ #define IWX_RX_RES_PHY_FLAGS_BAND_24 (1 << 0) #define IWX_RX_RES_PHY_FLAGS_MOD_CCK (1 << 1) #define IWX_RX_RES_PHY_FLAGS_SHORT_PREAMBLE (1 << 2) #define IWX_RX_RES_PHY_FLAGS_NARROW_BAND (1 << 3) #define IWX_RX_RES_PHY_FLAGS_ANTENNA (0x7 << 4) #define IWX_RX_RES_PHY_FLAGS_ANTENNA_POS 4 #define IWX_RX_RES_PHY_FLAGS_AGG (1 << 7) #define IWX_RX_RES_PHY_FLAGS_OFDM_HT (1 << 8) #define IWX_RX_RES_PHY_FLAGS_OFDM_GF (1 << 9) #define IWX_RX_RES_PHY_FLAGS_OFDM_VHT (1 << 10) /** * Values written by fw for each Rx packet * @IWX_RX_MPDU_RES_STATUS_CRC_OK: CRC is fine * @IWX_RX_MPDU_RES_STATUS_OVERRUN_OK: there was no RXE overflow * @IWX_RX_MPDU_RES_STATUS_SRC_STA_FOUND: * @IWX_RX_MPDU_RES_STATUS_KEY_VALID: * @IWX_RX_MPDU_RES_STATUS_KEY_PARAM_OK: * @IWX_RX_MPDU_RES_STATUS_ICV_OK: ICV is fine, if not, the packet is destroyed * @IWX_RX_MPDU_RES_STATUS_MIC_OK: used for CCM alg only. TKIP MIC is checked * in the driver. * @IWX_RX_MPDU_RES_STATUS_TTAK_OK: TTAK is fine * @IWX_RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR: valid for alg = CCM_CMAC or * alg = CCM only. Checks replay attack for 11w frames. Relevant only if * %IWX_RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME is set. * @IWX_RX_MPDU_RES_STATUS_SEC_NO_ENC: this frame is not encrypted * @IWX_RX_MPDU_RES_STATUS_SEC_WEP_ENC: this frame is encrypted using WEP * @IWX_RX_MPDU_RES_STATUS_SEC_CCM_ENC: this frame is encrypted using CCM * @IWX_RX_MPDU_RES_STATUS_SEC_TKIP_ENC: this frame is encrypted using TKIP * @IWX_RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC: this frame is encrypted using CCM_CMAC * @IWX_RX_MPDU_RES_STATUS_SEC_ENC_ERR: this frame couldn't be decrypted * @IWX_RX_MPDU_RES_STATUS_SEC_ENC_MSK: bitmask of the encryption algorithm * @IWX_RX_MPDU_RES_STATUS_DEC_DONE: this frame has been successfully decrypted * @IWX_RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP: * @IWX_RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: * @IWX_RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: * @IWX_RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame * @IWX_RX_MPDU_RES_STATUS_HASH_INDEX_MSK: * @IWX_RX_MPDU_RES_STATUS_STA_ID_MSK: * @IWX_RX_MPDU_RES_STATUS_RRF_KILL: * @IWX_RX_MPDU_RES_STATUS_FILTERING_MSK: * @IWX_RX_MPDU_RES_STATUS2_FILTERING_MSK: */ #define IWX_RX_MPDU_RES_STATUS_CRC_OK (1 << 0) #define IWX_RX_MPDU_RES_STATUS_OVERRUN_OK (1 << 1) #define IWX_RX_MPDU_RES_STATUS_SRC_STA_FOUND (1 << 2) #define IWX_RX_MPDU_RES_STATUS_KEY_VALID (1 << 3) #define IWX_RX_MPDU_RES_STATUS_KEY_PARAM_OK (1 << 4) #define IWX_RX_MPDU_RES_STATUS_ICV_OK (1 << 5) #define IWX_RX_MPDU_RES_STATUS_MIC_OK (1 << 6) #define IWX_RX_MPDU_RES_STATUS_TTAK_OK (1 << 7) #define IWX_RX_MPDU_RES_STATUS_MNG_FRAME_REPLAY_ERR (1 << 7) #define IWX_RX_MPDU_RES_STATUS_SEC_NO_ENC (0 << 8) #define IWX_RX_MPDU_RES_STATUS_SEC_WEP_ENC (1 << 8) #define IWX_RX_MPDU_RES_STATUS_SEC_CCM_ENC (2 << 8) #define IWX_RX_MPDU_RES_STATUS_SEC_TKIP_ENC (3 << 8) #define IWX_RX_MPDU_RES_STATUS_SEC_EXT_ENC (4 << 8) #define IWX_RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC (6 << 8) #define IWX_RX_MPDU_RES_STATUS_SEC_ENC_ERR (7 << 8) #define IWX_RX_MPDU_RES_STATUS_SEC_ENC_MSK (7 << 8) #define IWX_RX_MPDU_RES_STATUS_DEC_DONE (1 << 11) #define IWX_RX_MPDU_RES_STATUS_PROTECT_FRAME_BIT_CMP (1 << 12) #define IWX_RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP (1 << 13) #define IWX_RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT (1 << 14) #define IWX_RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME (1 << 15) #define IWX_RX_MPDU_RES_STATUS_HASH_INDEX_MSK (0x3F0000) #define IWX_RX_MPDU_RES_STATUS_STA_ID_MSK (0x1f000000) #define IWX_RX_MPDU_RES_STATUS_RRF_KILL (1 << 29) #define IWX_RX_MPDU_RES_STATUS_FILTERING_MSK (0xc00000) #define IWX_RX_MPDU_RES_STATUS2_FILTERING_MSK (0xc0000000) #define IWX_RX_MPDU_MFLG1_ADDRTYPE_MASK 0x03 #define IWX_RX_MPDU_MFLG1_MIC_CRC_LEN_MASK 0xf0 #define IWX_RX_MPDU_MFLG1_MIC_CRC_LEN_SHIFT 3 #define IWX_RX_MPDU_MFLG2_HDR_LEN_MASK 0x1f #define IWX_RX_MPDU_MFLG2_PAD 0x20 #define IWX_RX_MPDU_MFLG2_AMSDU 0x40 #define IWX_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK 0x7f #define IWX_RX_MPDU_AMSDU_LAST_SUBFRAME 0x80 #define IWX_RX_MPDU_PHY_AMPDU (1 << 5) #define IWX_RX_MPDU_PHY_AMPDU_TOGGLE (1 << 6) #define IWX_RX_MPDU_PHY_SHORT_PREAMBLE (1 << 7) #define IWX_RX_MPDU_PHY_NCCK_ADDTL_NTFY (1 << 7) #define IWX_RX_MPDU_PHY_TSF_OVERLOAD (1 << 8) #define IWX_RX_REORDER_DATA_INVALID_BAID 0x7f #define IWX_RX_MPDU_REORDER_NSSN_MASK 0x00000fff #define IWX_RX_MPDU_REORDER_SN_MASK 0x00fff000 #define IWX_RX_MPDU_REORDER_SN_SHIFT 12 #define IWX_RX_MPDU_REORDER_BAID_MASK 0x7f000000 #define IWX_RX_MPDU_REORDER_BAID_SHIFT 24 #define IWX_RX_MPDU_REORDER_BA_OLD_SN 0x80000000 struct iwx_rx_mpdu_desc_v1 { union { uint32_t rss_hash; uint32_t phy_data2; }; union { uint32_t filter_match; uint32_t phy_data3; }; uint32_t rate_n_flags; uint8_t energy_a; uint8_t energy_b; uint8_t channel; uint8_t mac_context; uint32_t gp2_on_air_rise; union { uint64_t tsf_on_air_rise; struct { uint32_t phy_data0; uint32_t phy_data1; }; }; } __packed; /** * struct iwx_rx_mpdu_desc_v3 - RX MPDU descriptor */ struct iwx_rx_mpdu_desc_v3 { /* DW7 - carries filter_match only when rpa_en == 1 */ union { /** * @filter_match: filter match value */ __le32 filter_match; /** * @phy_data3: depends on info type (see @phy_data1) */ __le32 phy_data3; }; /* DW8 - carries rss_hash only when rpa_en == 1 */ union { /** * @rss_hash: RSS hash value */ __le32 rss_hash; /** * @phy_data2: depends on info type (see @phy_data1) */ __le32 phy_data2; }; /* DW9 */ /** * @partial_hash: 31:0 ip/tcp header hash * w/o some fields (such as IP SRC addr) */ __le32 partial_hash; /* DW10 */ /** * @raw_xsum: raw xsum value */ __be16 raw_xsum; /** * @reserved_xsum: reserved high bits in the raw checksum */ __le16 reserved_xsum; /* DW11 */ /** * @rate_n_flags: RX rate/flags encoding */ __le32 rate_n_flags; /* DW12 */ /** * @energy_a: energy chain A */ u8 energy_a; /** * @energy_b: energy chain B */ u8 energy_b; /** * @channel: channel number */ u8 channel; /** * @mac_context: MAC context mask */ u8 mac_context; /* DW13 */ /** * @gp2_on_air_rise: GP2 timer value on air rise (INA) */ __le32 gp2_on_air_rise; /* DW14 & DW15 */ union { /** * @tsf_on_air_rise: * TSF value on air rise (INA), only valid if * %IWL_RX_MPDU_PHY_TSF_OVERLOAD isn't set */ __le64 tsf_on_air_rise; struct { /** * @phy_data0: depends on info_type, see @phy_data1 */ __le32 phy_data0; /** * @phy_data1: valid only if * %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set, * see &enum iwl_rx_phy_data1. */ __le32 phy_data1; }; }; /* DW16 & DW17 */ /** * @reserved: reserved */ __le32 reserved[2]; } __packed; /* RX_MPDU_RES_START_API_S_VER_3 */ /** * struct iwl_rx_mpdu_desc - RX MPDU descriptor */ struct iwx_rx_mpdu_desc { /* DW2 */ /** * @mpdu_len: MPDU length */ __le16 mpdu_len; /** * @mac_flags1: &enum iwl_rx_mpdu_mac_flags1 */ u8 mac_flags1; /** * @mac_flags2: &enum iwl_rx_mpdu_mac_flags2 */ u8 mac_flags2; /* DW3 */ /** * @amsdu_info: &enum iwl_rx_mpdu_amsdu_info */ u8 amsdu_info; /** * @phy_info: &enum iwl_rx_mpdu_phy_info */ __le16 phy_info; /** * @mac_phy_idx: MAC/PHY index */ u8 mac_phy_idx; /* DW4 - carries csum data only when rpa_en == 1 */ /** * @raw_csum: raw checksum (alledgedly unreliable) */ __le16 raw_csum; union { /** * @l3l4_flags: &enum iwl_rx_l3l4_flags */ __le16 l3l4_flags; /** * @phy_data4: depends on info type, see phy_data1 */ __le16 phy_data4; }; /* DW5 */ /** * @status: &enum iwl_rx_mpdu_status */ __le32 status; /* DW6 */ /** * @reorder_data: &enum iwl_rx_mpdu_reorder_data */ __le32 reorder_data; union { struct iwx_rx_mpdu_desc_v1 v1; struct iwx_rx_mpdu_desc_v3 v3; }; } __packed; /* RX_MPDU_RES_START_API_S_VER_3 */ #define IWX_RX_DESC_SIZE_V1 offsetofend(struct iwx_rx_mpdu_desc, v1) #define IWX_RX_NO_DATA_CHAIN_A_POS 0 #define IWX_RX_NO_DATA_CHAIN_A_MSK (0xff << IWX_RX_NO_DATA_CHAIN_A_POS) #define IWX_RX_NO_DATA_CHAIN_B_POS 8 #define IWX_RX_NO_DATA_CHAIN_B_MSK (0xff << IWX_RX_NO_DATA_CHAIN_B_POS) #define IWX_RX_NO_DATA_CHANNEL_POS 16 #define IWX_RX_NO_DATA_CHANNEL_MSK (0xff << IWX_RX_NO_DATA_CHANNEL_POS) #define IWX_RX_NO_DATA_INFO_TYPE_POS 0 #define IWX_RX_NO_DATA_INFO_TYPE_MSK (0xff << IWX_RX_NO_DATA_INFO_TYPE_POS) #define IWX_RX_NO_DATA_INFO_TYPE_NONE 0 #define IWX_RX_NO_DATA_INFO_TYPE_RX_ERR 1 #define IWX_RX_NO_DATA_INFO_TYPE_NDP 2 #define IWX_RX_NO_DATA_INFO_TYPE_MU_UNMATCHED 3 #define IWX_RX_NO_DATA_INFO_TYPE_HE_TB_UNMATCHED 4 #define IWX_RX_NO_DATA_INFO_ERR_POS 8 #define IWX_RX_NO_DATA_INFO_ERR_MSK (0xff << IWX_RX_NO_DATA_INFO_ERR_POS) #define IWX_RX_NO_DATA_INFO_ERR_NONE 0 #define IWX_RX_NO_DATA_INFO_ERR_BAD_PLCP 1 #define IWX_RX_NO_DATA_INFO_ERR_UNSUPPORTED_RATE 2 #define IWX_RX_NO_DATA_INFO_ERR_NO_DELIM 3 #define IWX_RX_NO_DATA_INFO_ERR_BAD_MAC_HDR 4 #define IWX_RX_NO_DATA_FRAME_TIME_POS 0 #define IWX_RX_NO_DATA_FRAME_TIME_MSK (0xfffff << IWX_RX_NO_DATA_FRAME_TIME_POS) #define IWX_RX_NO_DATA_RX_VEC0_HE_NSTS_MSK 0x03800000 #define IWX_RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK 0x38000000 /** * struct iwx_rx_no_data - RX no data descriptor * @info: 7:0 frame type, 15:8 RX error type * @rssi: 7:0 energy chain-A, * 15:8 chain-B, measured at FINA time (FINA_ENERGY), 16:23 channel * @on_air_rise_time: GP2 during on air rise * @fr_time: frame time * @rate: rate/mcs of frame * @phy_info: &enum iwl_rx_phy_data0 and &enum iwl_rx_phy_info_type * @rx_vec: DW-12:9 raw RX vectors from DSP according to modulation type. * for VHT: OFDM_RX_VECTOR_SIGA1_OUT, OFDM_RX_VECTOR_SIGA2_OUT * for HE: OFDM_RX_VECTOR_HE_SIGA1_OUT, OFDM_RX_VECTOR_HE_SIGA2_OUT */ struct iwx_rx_no_data { uint32_t info; uint32_t rssi; uint32_t on_air_rise_time; uint32_t fr_time; uint32_t rate; uint32_t phy_info[2]; uint32_t rx_vec[2]; } __packed; /* RX_NO_DATA_NTFY_API_S_VER_1 */ struct iwx_frame_release { uint8_t baid; uint8_t reserved; uint16_t nssn; }; #define IWX_BAR_FRAME_RELEASE_TID_MASK 0x0000000f #define IWX_BAR_FRAME_RELEASE_STA_MASK 0x000001f0 #define IWX_BAR_FRAME_RELEASE_NSSN_MASK 0x00000fff #define IWX_BAR_FRAME_RELEASE_SN_MASK 0x00fff000 #define IWX_BAR_FRAME_RELEASE_BAID_MASK 0x3f000000 /** * struct iwx_bar_frame_release - frame release from BAR info * @sta_tid: STA & TID information, see &enum iwl_bar_frame_release_sta_tid. * @ba_info: BA information, see &enum iwl_bar_frame_release_ba_info. */ struct iwx_bar_frame_release { uint32_t sta_tid; uint32_t ba_info; } __packed; /* RX_BAR_TO_FRAME_RELEASE_API_S_VER_1 */ /** * struct iwx_radio_version_notif - information on the radio version * ( IWX_RADIO_VERSION_NOTIFICATION = 0x68 ) * @radio_flavor: * @radio_step: * @radio_dash: */ struct iwx_radio_version_notif { uint32_t radio_flavor; uint32_t radio_step; uint32_t radio_dash; } __packed; /* IWX_RADIO_VERSION_NOTOFICATION_S_VER_1 */ #define IWX_CARD_ENABLED 0x00 #define IWX_HW_CARD_DISABLED 0x01 #define IWX_SW_CARD_DISABLED 0x02 #define IWX_CT_KILL_CARD_DISABLED 0x04 #define IWX_HALT_CARD_DISABLED 0x08 #define IWX_CARD_DISABLED_MSK 0x0f #define IWX_CARD_IS_RX_ON 0x10 /** * struct iwx_radio_version_notif - information on the radio version * (IWX_CARD_STATE_NOTIFICATION = 0xa1 ) * @flags: %iwx_card_state_flags */ struct iwx_card_state_notif { uint32_t flags; } __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ /** * struct iwx_missed_beacons_notif - information on missed beacons * ( IWX_MISSED_BEACONS_NOTIFICATION = 0xa2 ) * @mac_id: interface ID * @consec_missed_beacons_since_last_rx: number of consecutive missed * beacons since last RX. * @consec_missed_beacons: number of consecutive missed beacons * @num_expected_beacons: * @num_recvd_beacons: */ struct iwx_missed_beacons_notif { uint32_t mac_id; uint32_t consec_missed_beacons_since_last_rx; uint32_t consec_missed_beacons; uint32_t num_expected_beacons; uint32_t num_recvd_beacons; } __packed; /* IWX_MISSED_BEACON_NTFY_API_S_VER_3 */ /** * struct iwx_mfuart_load_notif - mfuart image version & status * ( IWX_MFUART_LOAD_NOTIFICATION = 0xb1 ) * @installed_ver: installed image version * @external_ver: external image version * @status: MFUART loading status * @duration: MFUART loading time */ struct iwx_mfuart_load_notif { uint32_t installed_ver; uint32_t external_ver; uint32_t status; uint32_t duration; } __packed; /*MFU_LOADER_NTFY_API_S_VER_1*/ /** * struct iwx_set_calib_default_cmd - set default value for calibration. * ( IWX_SET_CALIB_DEFAULT_CMD = 0x8e ) * @calib_index: the calibration to set value for * @length: of data * @data: the value to set for the calibration result */ struct iwx_set_calib_default_cmd { uint16_t calib_index; uint16_t length; uint8_t data[0]; } __packed; /* IWX_PHY_CALIB_OVERRIDE_VALUES_S */ #define IWX_MAX_PORT_ID_NUM 2 #define IWX_MAX_MCAST_FILTERING_ADDRESSES 256 /** * struct iwx_mcast_filter_cmd - configure multicast filter. * @filter_own: Set 1 to filter out multicast packets sent by station itself * @port_id: Multicast MAC addresses array specifier. This is a strange way * to identify network interface adopted in host-device IF. * It is used by FW as index in array of addresses. This array has * IWX_MAX_PORT_ID_NUM members. * @count: Number of MAC addresses in the array * @pass_all: Set 1 to pass all multicast packets. * @bssid: current association BSSID. * @addr_list: Place holder for array of MAC addresses. * IMPORTANT: add padding if necessary to ensure DWORD alignment. */ struct iwx_mcast_filter_cmd { uint8_t filter_own; uint8_t port_id; uint8_t count; uint8_t pass_all; uint8_t bssid[6]; uint8_t reserved[2]; uint8_t addr_list[0]; } __packed; /* IWX_MCAST_FILTERING_CMD_API_S_VER_1 */ struct iwx_statistics_dbg { uint32_t burst_check; uint32_t burst_count; uint32_t wait_for_silence_timeout_cnt; uint8_t reserved[12]; } __packed; /* IWX_STATISTICS_DEBUG_API_S_VER_2 */ struct iwx_statistics_div { uint32_t tx_on_a; uint32_t tx_on_b; uint32_t exec_time; uint32_t probe_time; uint32_t rssi_ant; uint32_t reserved2; } __packed; /* IWX_STATISTICS_SLOW_DIV_API_S_VER_2 */ /** * struct mvm_statistics_rx_non_phy * @bogus_cts: CTS received when not expecting CTS * @bogus_ack: ACK received when not expecting ACK * @non_channel_beacons: beacons with our bss id but not on our serving channel * @channel_beacons: beacons with our bss id and in our serving channel * @num_missed_bcon: number of missed beacons * @adc_rx_saturation_time: count in 0.8us units the time the ADC was in * saturation * @ina_detection_search_time: total time (in 0.8us) searched for INA * @beacon_silence_rssi_a: RSSI silence after beacon frame * @beacon_silence_rssi_b: RSSI silence after beacon frame * @beacon_silence_rssi_c: RSSI silence after beacon frame * @interference_data_flag: flag for interference data availability. 1 when data * is available. * @channel_load: counts RX Enable time in uSec * @beacon_rssi_a: beacon RSSI on anntena A * @beacon_rssi_b: beacon RSSI on antenna B * @beacon_rssi_c: beacon RSSI on antenna C * @beacon_energy_a: beacon energy on antenna A * @beacon_energy_b: beacon energy on antenna B * @beacon_energy_c: beacon energy on antenna C * @num_bt_kills: number of BT "kills" (frame TX aborts) * @mac_id: mac ID */ struct iwx_statistics_rx_non_phy { __le32 bogus_cts; __le32 bogus_ack; __le32 non_channel_beacons; __le32 channel_beacons; __le32 num_missed_bcon; __le32 adc_rx_saturation_time; __le32 ina_detection_search_time; __le32 beacon_silence_rssi_a; __le32 beacon_silence_rssi_b; __le32 beacon_silence_rssi_c; __le32 interference_data_flag; __le32 channel_load; __le32 beacon_rssi_a; __le32 beacon_rssi_b; __le32 beacon_rssi_c; __le32 beacon_energy_a; __le32 beacon_energy_b; __le32 beacon_energy_c; __le32 num_bt_kills; __le32 mac_id; } __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_4 */ struct iwx_statistics_rx_non_phy_v3 { __le32 bogus_cts; /* CTS received when not expecting CTS */ __le32 bogus_ack; /* ACK received when not expecting ACK */ __le32 non_bssid_frames; /* number of frames with BSSID that * doesn't belong to the STA BSSID */ __le32 filtered_frames; /* count frames that were dumped in the * filtering process */ __le32 non_channel_beacons; /* beacons with our bss id but not on * our serving channel */ __le32 channel_beacons; /* beacons with our bss id and in our * serving channel */ __le32 num_missed_bcon; /* number of missed beacons */ __le32 adc_rx_saturation_time; /* count in 0.8us units the time the * ADC was in saturation */ __le32 ina_detection_search_time;/* total time (in 0.8us) searched * for INA */ __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ __le32 interference_data_flag; /* flag for interference data * availability. 1 when data is * available. */ __le32 channel_load; /* counts RX Enable time in uSec */ __le32 dsp_false_alarms; /* DSP false alarm (both OFDM * and CCK) counter */ __le32 beacon_rssi_a; __le32 beacon_rssi_b; __le32 beacon_rssi_c; __le32 beacon_energy_a; __le32 beacon_energy_b; __le32 beacon_energy_c; __le32 num_bt_kills; __le32 mac_id; __le32 directed_data_mpdu; } __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */ struct iwx_statistics_rx_phy { __le32 unresponded_rts; __le32 rxe_frame_lmt_overrun; __le32 sent_ba_rsp_cnt; __le32 dsp_self_kill; __le32 reserved; } __packed; /* STATISTICS_RX_PHY_API_S_VER_3 */ struct iwx_statistics_rx_phy_v2 { uint32_t ina_cnt; uint32_t fina_cnt; uint32_t plcp_err; uint32_t crc32_err; uint32_t overrun_err; uint32_t early_overrun_err; uint32_t crc32_good; uint32_t false_alarm_cnt; uint32_t fina_sync_err_cnt; uint32_t sfd_timeout; uint32_t fina_timeout; uint32_t unresponded_rts; uint32_t rxe_frame_limit_overrun; uint32_t sent_ack_cnt; uint32_t sent_cts_cnt; uint32_t sent_ba_rsp_cnt; uint32_t dsp_self_kill; uint32_t mh_format_err; uint32_t re_acq_main_rssi_sum; uint32_t reserved; } __packed; /* IWX_STATISTICS_RX_PHY_API_S_VER_2 */ struct iwx_statistics_rx_ht_phy_v1 { uint32_t plcp_err; uint32_t overrun_err; uint32_t early_overrun_err; uint32_t crc32_good; uint32_t crc32_err; uint32_t mh_format_err; uint32_t agg_crc32_good; uint32_t agg_mpdu_cnt; uint32_t agg_cnt; uint32_t unsupport_mcs; } __packed; /* IWX_STATISTICS_HT_RX_PHY_API_S_VER_1 */ struct iwx_statistics_rx_ht_phy { __le32 mh_format_err; __le32 agg_mpdu_cnt; __le32 agg_cnt; __le32 unsupport_mcs; } __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_2 */ /* * The first MAC indices (starting from 0) * are available to the driver, AUX follows */ #define IWX_MAC_INDEX_AUX 4 #define IWX_MAC_INDEX_MIN_DRIVER 0 #define IWX_NUM_MAC_INDEX_DRIVER IWX_MAC_INDEX_AUX #define IWX_NUM_MAC_INDEX (IWX_NUM_MAC_INDEX_DRIVER + 1) #define IWX_NUM_MAC_INDEX_CDB (IWX_NUM_MAC_INDEX_DRIVER + 2) #define IWX_STATION_COUNT 16 struct iwx_statistics_tx_non_phy_v3 { __le32 preamble_cnt; __le32 rx_detected_cnt; __le32 bt_prio_defer_cnt; __le32 bt_prio_kill_cnt; __le32 few_bytes_cnt; __le32 cts_timeout; __le32 ack_timeout; __le32 expected_ack_cnt; __le32 actual_ack_cnt; __le32 dump_msdu_cnt; __le32 burst_abort_next_frame_mismatch_cnt; __le32 burst_abort_missing_next_frame_cnt; __le32 cts_timeout_collision; __le32 ack_or_ba_timeout_collision; } __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_3 */ struct iwx_statistics_tx_non_phy { __le32 bt_prio_defer_cnt; __le32 bt_prio_kill_cnt; __le32 few_bytes_cnt; __le32 cts_timeout; __le32 ack_timeout; __le32 dump_msdu_cnt; __le32 burst_abort_next_frame_mismatch_cnt; __le32 burst_abort_missing_next_frame_cnt; __le32 cts_timeout_collision; __le32 ack_or_ba_timeout_collision; } __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_4 */ #define IWX_MAX_CHAINS 3 struct iwx_statistics_tx_non_phy_agg { uint32_t ba_timeout; uint32_t ba_reschedule_frames; uint32_t scd_query_agg_frame_cnt; uint32_t scd_query_no_agg; uint32_t scd_query_agg; uint32_t scd_query_mismatch; uint32_t frame_not_ready; uint32_t underrun; uint32_t bt_prio_kill; uint32_t rx_ba_rsp_cnt; int8_t txpower[IWX_MAX_CHAINS]; int8_t reserved; uint32_t reserved2; } __packed; /* IWX_STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */ struct iwx_statistics_tx_channel_width { uint32_t ext_cca_narrow_ch20[1]; uint32_t ext_cca_narrow_ch40[2]; uint32_t ext_cca_narrow_ch80[3]; uint32_t ext_cca_narrow_ch160[4]; uint32_t last_tx_ch_width_indx; uint32_t rx_detected_per_ch_width[4]; uint32_t success_per_ch_width[4]; uint32_t fail_per_ch_width[4]; }; /* IWX_STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ struct iwx_statistics_tx_v4 { struct iwx_statistics_tx_non_phy_v3 general; struct iwx_statistics_tx_non_phy_agg agg; struct iwx_statistics_tx_channel_width channel_width; } __packed; /* STATISTICS_TX_API_S_VER_4 */ struct iwx_statistics_tx { struct iwx_statistics_tx_non_phy general; struct iwx_statistics_tx_non_phy_agg agg; struct iwx_statistics_tx_channel_width channel_width; } __packed; /* STATISTICS_TX_API_S_VER_5 */ struct iwx_statistics_bt_activity { __le32 hi_priority_tx_req_cnt; __le32 hi_priority_tx_denied_cnt; __le32 lo_priority_tx_req_cnt; __le32 lo_priority_tx_denied_cnt; __le32 hi_priority_rx_req_cnt; __le32 hi_priority_rx_denied_cnt; __le32 lo_priority_rx_req_cnt; __le32 lo_priority_rx_denied_cnt; } __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ struct iwx_statistics_general_common_v19 { __le32 radio_temperature; __le32 radio_voltage; struct iwx_statistics_dbg dbg; __le32 sleep_time; __le32 slots_out; __le32 slots_idle; __le32 ttl_timestamp; struct iwx_statistics_div slow_div; __le32 rx_enable_counter; /* * num_of_sos_states: * count the number of times we have to re-tune * in order to get out of bad PHY status */ __le32 num_of_sos_states; __le32 beacon_filtered; __le32 missed_beacons; u8 beacon_filter_average_energy; u8 beacon_filter_reason; u8 beacon_filter_current_energy; u8 beacon_filter_reserved; __le32 beacon_filter_delta_time; struct iwx_statistics_bt_activity bt_activity; __le64 rx_time; __le64 on_time_rf; __le64 on_time_scan; __le64 tx_time; } __packed; struct iwx_statistics_general_common { __le32 radio_temperature; struct iwx_statistics_dbg dbg; __le32 sleep_time; __le32 slots_out; __le32 slots_idle; __le32 ttl_timestamp; struct iwx_statistics_div slow_div; __le32 rx_enable_counter; /* * num_of_sos_states: * count the number of times we have to re-tune * in order to get out of bad PHY status */ __le32 num_of_sos_states; __le32 beacon_filtered; __le32 missed_beacons; u8 beacon_filter_average_energy; u8 beacon_filter_reason; u8 beacon_filter_current_energy; u8 beacon_filter_reserved; __le32 beacon_filter_delta_time; struct iwx_statistics_bt_activity bt_activity; __le64 rx_time; __le64 on_time_rf; __le64 on_time_scan; __le64 tx_time; } __packed; /* STATISTICS_GENERAL_API_S_VER_10 */ struct iwx_statistics_general_v8 { struct iwx_statistics_general_common_v19 common; __le32 beacon_counter[IWX_NUM_MAC_INDEX]; u8 beacon_average_energy[IWX_NUM_MAC_INDEX]; u8 reserved[4 - (IWX_NUM_MAC_INDEX % 4)]; } __packed; /* STATISTICS_GENERAL_API_S_VER_8 */ struct iwx_statistics_general { struct iwx_statistics_general_common common; uint32_t beacon_counter[IWX_MAC_INDEX_AUX]; uint8_t beacon_average_energy[IWX_MAC_INDEX_AUX]; uint8_t reserved[8 - IWX_MAC_INDEX_AUX]; } __packed; /* STATISTICS_GENERAL_API_S_VER_10 */ struct iwx_statistics_rx { struct iwx_statistics_rx_phy ofdm; struct iwx_statistics_rx_phy cck; struct iwx_statistics_rx_non_phy general; struct iwx_statistics_rx_ht_phy ofdm_ht; } __packed; /* IWX_STATISTICS_RX_API_S_VER_4 */ struct iwx_statistics_rx_v3 { struct iwx_statistics_rx_phy_v2 ofdm; struct iwx_statistics_rx_phy_v2 cck; struct iwx_statistics_rx_non_phy_v3 general; struct iwx_statistics_rx_ht_phy_v1 ofdm_ht; } __packed; /* IWX_STATISTICS_RX_API_S_VER_3 */ /* * IWX_STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) * * By default, uCode issues this notification after receiving a beacon * while associated. To disable this behavior, set DISABLE_NOTIF flag in the * IWX_REPLY_STATISTICS_CMD 0x9c, above. * * Statistics counters continue to increment beacon after beacon, but are * cleared when changing channels or when driver issues IWX_REPLY_STATISTICS_CMD * 0x9c with CLEAR_STATS bit set (see above). * * uCode also issues this notification during scans. uCode clears statistics * appropriately so that each notification contains statistics for only the * one channel that has just been scanned. */ /** * struct iwx_statistics_load - RX statistics for multi-queue devices * @air_time: accumulated air time, per mac * @byte_count: accumulated byte count, per mac * @pkt_count: accumulated packet count, per mac * @avg_energy: average RSSI, per station */ struct iwx_statistics_load { uint32_t air_time[IWX_MAC_INDEX_AUX]; uint32_t byte_count[IWX_MAC_INDEX_AUX]; uint32_t pkt_count[IWX_MAC_INDEX_AUX]; uint8_t avg_energy[IWX_STATION_COUNT]; } __packed; /* STATISTICS_RX_MAC_STATION_S_VER_4 */ struct iwx_statistics_load_v1 { uint32_t air_time[IWX_MAC_INDEX_AUX]; uint32_t byte_count[IWX_MAC_INDEX_AUX]; uint32_t pkt_count[IWX_MAC_INDEX_AUX]; uint8_t avg_energy[IWX_STATION_COUNT]; } __packed; /* STATISTICS_RX_MAC_STATION_S_VER_1 */ struct iwx_notif_statistics { uint32_t flag; struct iwx_statistics_rx rx; struct iwx_statistics_tx tx; struct iwx_statistics_general general; struct iwx_statistics_load load_stats; } __packed; /* STATISTICS_NTFY_API_S_VER_13 */ struct iwx_notif_statistics_v11 { __le32 flag; struct iwx_statistics_rx_v3 rx; struct iwx_statistics_tx_v4 tx; struct iwx_statistics_general_v8 general; struct iwx_statistics_load_v1 load_stats; } __packed; /* STATISTICS_NTFY_API_S_VER_11 */ /** * flags used in statistics notification * @IWX_STATISTICS_REPLY_FLG_CLEAR: statistics were cleared after this report */ #define IWX_STATISTICS_REPLY_FLG_CLEAR 0x01 /** * flags used in statistics command * @IWX_STATISTICS_FLG_CLEAR: request to clear statistics after the report * that's sent after this command * @IWX_STATISTICS_FLG_DISABLE_NOTIF: disable unilateral statistics * notifications */ #define IWX_STATISTICS_FLG_CLEAR 0x01 #define IWX_STATISTICS_FLG_DISABLE_NOTIF 0x02 /** * struct iwx_statistics_cmd - statistics config command * @flags: IWX_STATISTICS_* flags */ struct iwx_statistics_cmd { uint32_t flags; } __packed; /* STATISTICS_CMD_API_S_VER_1 */ /*********************************** * Smart Fifo API ***********************************/ /* Smart Fifo state */ #define IWX_SF_LONG_DELAY_ON 0 /* should never be called by driver */ #define IWX_SF_FULL_ON 1 #define IWX_SF_UNINIT 2 #define IWX_SF_INIT_OFF 3 #define IWX_SF_HW_NUM_STATES 4 /* Smart Fifo possible scenario */ #define IWX_SF_SCENARIO_SINGLE_UNICAST 0 #define IWX_SF_SCENARIO_AGG_UNICAST 1 #define IWX_SF_SCENARIO_MULTICAST 2 #define IWX_SF_SCENARIO_BA_RESP 3 #define IWX_SF_SCENARIO_TX_RESP 4 #define IWX_SF_NUM_SCENARIO 5 #define IWX_SF_TRANSIENT_STATES_NUMBER 2 /* IWX_SF_LONG_DELAY_ON and IWX_SF_FULL_ON */ #define IWX_SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */ /* smart FIFO default values */ #define IWX_SF_W_MARK_SISO 4096 #define IWX_SF_W_MARK_MIMO2 8192 #define IWX_SF_W_MARK_MIMO3 6144 #define IWX_SF_W_MARK_LEGACY 4096 #define IWX_SF_W_MARK_SCAN 4096 /* SF Scenarios timers for default configuration (aligned to 32 uSec) */ #define IWX_SF_SINGLE_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWX_SF_SINGLE_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWX_SF_AGG_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWX_SF_AGG_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWX_SF_MCAST_IDLE_TIMER_DEF 160 /* 150 mSec */ #define IWX_SF_MCAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWX_SF_BA_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWX_SF_BA_AGING_TIMER_DEF 400 /* 0.4 mSec */ #define IWX_SF_TX_RE_IDLE_TIMER_DEF 160 /* 150 uSec */ #define IWX_SF_TX_RE_AGING_TIMER_DEF 400 /* 0.4 mSec */ /* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */ #define IWX_SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */ #define IWX_SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */ #define IWX_SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */ #define IWX_SF_AGG_UNICAST_AGING_TIMER 2016 /* 2 mSec */ #define IWX_SF_MCAST_IDLE_TIMER 2016 /* 2 mSec */ #define IWX_SF_MCAST_AGING_TIMER 10016 /* 10 mSec */ #define IWX_SF_BA_IDLE_TIMER 320 /* 300 uSec */ #define IWX_SF_BA_AGING_TIMER 2016 /* 2 mSec */ #define IWX_SF_TX_RE_IDLE_TIMER 320 /* 300 uSec */ #define IWX_SF_TX_RE_AGING_TIMER 2016 /* 2 mSec */ #define IWX_SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ #define IWX_SF_CFG_DUMMY_NOTIF_OFF (1 << 16) /** * Smart Fifo configuration command. * @state: smart fifo state, types listed in enum %iwx_sf_state. * @watermark: Minimum allowed availabe free space in RXF for transient state. * @long_delay_timeouts: aging and idle timer values for each scenario * in long delay state. * @full_on_timeouts: timer values for each scenario in full on state. */ struct iwx_sf_cfg_cmd { uint32_t state; uint32_t watermark[IWX_SF_TRANSIENT_STATES_NUMBER]; uint32_t long_delay_timeouts[IWX_SF_NUM_SCENARIO][IWX_SF_NUM_TIMEOUT_TYPES]; uint32_t full_on_timeouts[IWX_SF_NUM_SCENARIO][IWX_SF_NUM_TIMEOUT_TYPES]; } __packed; /* IWX_SF_CFG_API_S_VER_2 */ #define IWX_AC_BK 0 #define IWX_AC_BE 1 #define IWX_AC_VI 2 #define IWX_AC_VO 3 #define IWX_AC_NUM 4 /** * MAC context flags * @IWX_MAC_PROT_FLG_TGG_PROTECT: 11g protection when transmitting OFDM frames, * this will require CCK RTS/CTS2self. * RTS/CTS will protect full burst time. * @IWX_MAC_PROT_FLG_HT_PROT: enable HT protection * @IWX_MAC_PROT_FLG_FAT_PROT: protect 40 MHz transmissions * @IWX_MAC_PROT_FLG_SELF_CTS_EN: allow CTS2self */ #define IWX_MAC_PROT_FLG_TGG_PROTECT (1 << 3) #define IWX_MAC_PROT_FLG_HT_PROT (1 << 23) #define IWX_MAC_PROT_FLG_FAT_PROT (1 << 24) #define IWX_MAC_PROT_FLG_SELF_CTS_EN (1 << 30) #define IWX_MAC_FLG_SHORT_SLOT (1 << 4) #define IWX_MAC_FLG_SHORT_PREAMBLE (1 << 5) /** * Supported MAC types * @IWX_FW_MAC_TYPE_FIRST: lowest supported MAC type * @IWX_FW_MAC_TYPE_AUX: Auxiliary MAC (internal) * @IWX_FW_MAC_TYPE_LISTENER: monitor MAC type (?) * @IWX_FW_MAC_TYPE_PIBSS: Pseudo-IBSS * @IWX_FW_MAC_TYPE_IBSS: IBSS * @IWX_FW_MAC_TYPE_BSS_STA: BSS (managed) station * @IWX_FW_MAC_TYPE_P2P_DEVICE: P2P Device * @IWX_FW_MAC_TYPE_P2P_STA: P2P client * @IWX_FW_MAC_TYPE_GO: P2P GO * @IWX_FW_MAC_TYPE_TEST: ? * @IWX_FW_MAC_TYPE_MAX: highest support MAC type */ #define IWX_FW_MAC_TYPE_FIRST 1 #define IWX_FW_MAC_TYPE_AUX IWX_FW_MAC_TYPE_FIRST #define IWX_FW_MAC_TYPE_LISTENER 2 #define IWX_FW_MAC_TYPE_PIBSS 3 #define IWX_FW_MAC_TYPE_IBSS 4 #define IWX_FW_MAC_TYPE_BSS_STA 5 #define IWX_FW_MAC_TYPE_P2P_DEVICE 6 #define IWX_FW_MAC_TYPE_P2P_STA 7 #define IWX_FW_MAC_TYPE_GO 8 #define IWX_FW_MAC_TYPE_TEST 9 #define IWX_FW_MAC_TYPE_MAX IWX_FW_MAC_TYPE_TEST /* IWX_MAC_CONTEXT_TYPE_API_E_VER_1 */ /** * TSF hw timer ID * @IWX_TSF_ID_A: use TSF A * @IWX_TSF_ID_B: use TSF B * @IWX_TSF_ID_C: use TSF C * @IWX_TSF_ID_D: use TSF D * @IWX_NUM_TSF_IDS: number of TSF timers available */ #define IWX_TSF_ID_A 0 #define IWX_TSF_ID_B 1 #define IWX_TSF_ID_C 2 #define IWX_TSF_ID_D 3 #define IWX_NUM_TSF_IDS 4 /* IWX_TSF_ID_API_E_VER_1 */ /** * struct iwx_mac_data_ap - configuration data for AP MAC context * @beacon_time: beacon transmit time in system time * @beacon_tsf: beacon transmit time in TSF * @bi: beacon interval in TU * @bi_reciprocal: 2^32 / bi * @dtim_interval: dtim transmit time in TU * @dtim_reciprocal: 2^32 / dtim_interval * @mcast_qid: queue ID for multicast traffic * NOTE: obsolete from VER2 and on * @beacon_template: beacon template ID */ struct iwx_mac_data_ap { uint32_t beacon_time; uint64_t beacon_tsf; uint32_t bi; uint32_t bi_reciprocal; uint32_t dtim_interval; uint32_t dtim_reciprocal; uint32_t mcast_qid; uint32_t beacon_template; } __packed; /* AP_MAC_DATA_API_S_VER_2 */ /** * struct iwx_mac_data_ibss - configuration data for IBSS MAC context * @beacon_time: beacon transmit time in system time * @beacon_tsf: beacon transmit time in TSF * @bi: beacon interval in TU * @bi_reciprocal: 2^32 / bi * @beacon_template: beacon template ID */ struct iwx_mac_data_ibss { uint32_t beacon_time; uint64_t beacon_tsf; uint32_t bi; uint32_t bi_reciprocal; uint32_t beacon_template; } __packed; /* IBSS_MAC_DATA_API_S_VER_1 */ /** * struct iwx_mac_data_sta - configuration data for station MAC context * @is_assoc: 1 for associated state, 0 otherwise * @dtim_time: DTIM arrival time in system time * @dtim_tsf: DTIM arrival time in TSF * @bi: beacon interval in TU, applicable only when associated * @bi_reciprocal: 2^32 / bi , applicable only when associated * @dtim_interval: DTIM interval in TU, applicable only when associated * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated * @listen_interval: in beacon intervals, applicable only when associated * @assoc_id: unique ID assigned by the AP during association */ struct iwx_mac_data_sta { uint32_t is_assoc; uint32_t dtim_time; uint64_t dtim_tsf; uint32_t bi; uint32_t bi_reciprocal; uint32_t dtim_interval; uint32_t dtim_reciprocal; uint32_t listen_interval; uint32_t assoc_id; uint32_t assoc_beacon_arrive_time; } __packed; /* IWX_STA_MAC_DATA_API_S_VER_1 */ /** * struct iwx_mac_data_go - configuration data for P2P GO MAC context * @ap: iwx_mac_data_ap struct with most config data * @ctwin: client traffic window in TU (period after TBTT when GO is present). * 0 indicates that there is no CT window. * @opp_ps_enabled: indicate that opportunistic PS allowed */ struct iwx_mac_data_go { struct iwx_mac_data_ap ap; uint32_t ctwin; uint32_t opp_ps_enabled; } __packed; /* GO_MAC_DATA_API_S_VER_1 */ /** * struct iwx_mac_data_p2p_sta - configuration data for P2P client MAC context * @sta: iwx_mac_data_sta struct with most config data * @ctwin: client traffic window in TU (period after TBTT when GO is present). * 0 indicates that there is no CT window. */ struct iwx_mac_data_p2p_sta { struct iwx_mac_data_sta sta; uint32_t ctwin; } __packed; /* P2P_STA_MAC_DATA_API_S_VER_1 */ /** * struct iwx_mac_data_pibss - Pseudo IBSS config data * @stats_interval: interval in TU between statistics notifications to host. */ struct iwx_mac_data_pibss { uint32_t stats_interval; } __packed; /* PIBSS_MAC_DATA_API_S_VER_1 */ /* * struct iwx_mac_data_p2p_dev - configuration data for the P2P Device MAC * context. * @is_disc_extended: if set to true, P2P Device discoverability is enabled on * other channels as well. This should be to true only in case that the * device is discoverable and there is an active GO. Note that setting this * field when not needed, will increase the number of interrupts and have * effect on the platform power, as this setting opens the Rx filters on * all macs. */ struct iwx_mac_data_p2p_dev { uint32_t is_disc_extended; } __packed; /* _P2P_DEV_MAC_DATA_API_S_VER_1 */ /** * MAC context filter flags * @IWX_MAC_FILTER_IN_PROMISC: accept all data frames * @IWX_MAC_FILTER_IN_CONTROL_AND_MGMT: pass all mangement and * control frames to the host * @IWX_MAC_FILTER_ACCEPT_GRP: accept multicast frames * @IWX_MAC_FILTER_DIS_DECRYPT: don't decrypt unicast frames * @IWX_MAC_FILTER_DIS_GRP_DECRYPT: don't decrypt multicast frames * @IWX_MAC_FILTER_IN_BEACON: transfer foreign BSS's beacons to host * (in station mode when associated) * @IWX_MAC_FILTER_OUT_BCAST: filter out all broadcast frames * @IWX_MAC_FILTER_IN_CRC32: extract FCS and append it to frames * @IWX_MAC_FILTER_IN_PROBE_REQUEST: pass probe requests to host */ #define IWX_MAC_FILTER_IN_PROMISC (1 << 0) #define IWX_MAC_FILTER_IN_CONTROL_AND_MGMT (1 << 1) #define IWX_MAC_FILTER_ACCEPT_GRP (1 << 2) #define IWX_MAC_FILTER_DIS_DECRYPT (1 << 3) #define IWX_MAC_FILTER_DIS_GRP_DECRYPT (1 << 4) #define IWX_MAC_FILTER_IN_BEACON (1 << 6) #define IWX_MAC_FILTER_OUT_BCAST (1 << 8) #define IWX_MAC_FILTER_IN_CRC32 (1 << 11) #define IWX_MAC_FILTER_IN_PROBE_REQUEST (1 << 12) #define IWX_MAC_FILTER_IN_11AX (1 << 14) /** * QoS flags * @IWX_MAC_QOS_FLG_UPDATE_EDCA: ? * @IWX_MAC_QOS_FLG_TGN: HT is enabled * @IWX_MAC_QOS_FLG_TXOP_TYPE: ? * */ #define IWX_MAC_QOS_FLG_UPDATE_EDCA (1 << 0) #define IWX_MAC_QOS_FLG_TGN (1 << 1) #define IWX_MAC_QOS_FLG_TXOP_TYPE (1 << 4) /** * struct iwx_ac_qos - QOS timing params for IWX_MAC_CONTEXT_CMD * @cw_min: Contention window, start value in numbers of slots. * Should be a power-of-2, minus 1. Device's default is 0x0f. * @cw_max: Contention window, max value in numbers of slots. * Should be a power-of-2, minus 1. Device's default is 0x3f. * @aifsn: Number of slots in Arbitration Interframe Space (before * performing random backoff timing prior to Tx). Device default 1. * @fifos_mask: FIFOs used by this MAC for this AC * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0. * * One instance of this config struct for each of 4 EDCA access categories * in struct iwx_qosparam_cmd. * * Device will automatically increase contention window by (2*CW) + 1 for each * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW * value, to cap the CW value. */ struct iwx_ac_qos { uint16_t cw_min; uint16_t cw_max; uint8_t aifsn; uint8_t fifos_mask; uint16_t edca_txop; } __packed; /* IWX_AC_QOS_API_S_VER_2 */ /** * struct iwx_mac_ctx_cmd - command structure to configure MAC contexts * ( IWX_MAC_CONTEXT_CMD = 0x28 ) * @id_and_color: ID and color of the MAC * @action: action to perform, one of IWX_FW_CTXT_ACTION_* * @mac_type: one of IWX_FW_MAC_TYPE_* * @tsf_id: TSF HW timer, one of IWX_TSF_ID_* * @node_addr: MAC address * @bssid_addr: BSSID * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM * @protection_flags: combination of IWX_MAC_PROT_FLG_FLAG_* * @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise * @short_slot: 0x10 for enabling short slots, 0 otherwise * @filter_flags: combination of IWX_MAC_FILTER_* * @qos_flags: from IWX_MAC_QOS_FLG_* * @ac: one iwx_mac_qos configuration for each AC * @mac_specific: one of struct iwx_mac_data_*, according to mac_type */ struct iwx_mac_ctx_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ uint32_t id_and_color; uint32_t action; /* IWX_MAC_CONTEXT_COMMON_DATA_API_S_VER_1 */ uint32_t mac_type; uint32_t tsf_id; uint8_t node_addr[6]; uint16_t reserved_for_node_addr; uint8_t bssid_addr[6]; uint16_t reserved_for_bssid_addr; uint32_t cck_rates; uint32_t ofdm_rates; uint32_t protection_flags; uint32_t cck_short_preamble; uint32_t short_slot; uint32_t filter_flags; /* IWX_MAC_QOS_PARAM_API_S_VER_1 */ uint32_t qos_flags; struct iwx_ac_qos ac[IWX_AC_NUM+1]; /* IWX_MAC_CONTEXT_COMMON_DATA_API_S */ union { struct iwx_mac_data_ap ap; struct iwx_mac_data_go go; struct iwx_mac_data_sta sta; struct iwx_mac_data_p2p_sta p2p_sta; struct iwx_mac_data_p2p_dev p2p_dev; struct iwx_mac_data_pibss pibss; struct iwx_mac_data_ibss ibss; }; } __packed; /* IWX_MAC_CONTEXT_CMD_API_S_VER_1 */ static inline uint32_t iwx_reciprocal(uint32_t v) { if (!v) return 0; return 0xFFFFFFFF / v; } /* Power Management Commands, Responses, Notifications */ /** * masks for LTR config command flags * @IWX_LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status * @IWX_LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow * memory access * @IWX_LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR * reg change * @IWX_LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from * D0 to D3 * @IWX_LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register * @IWX_LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register * @IWX_LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD */ #define IWX_LTR_CFG_FLAG_FEATURE_ENABLE 0x00000001 #define IWX_LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS 0x00000002 #define IWX_LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH 0x00000004 #define IWX_LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 0x00000008 #define IWX_LTR_CFG_FLAG_SW_SET_SHORT 0x00000010 #define IWX_LTR_CFG_FLAG_SW_SET_LONG 0x00000020 #define IWX_LTR_CFG_FLAG_DENIE_C10_ON_PD 0x00000040 #define IWX_LTR_VALID_STATES_NUM 4 /** * struct iwx_ltr_config_cmd - configures the LTR * @flags: See %enum iwx_ltr_config_flags * @static_long: * @static_short: * @ltr_cfg_values: * @ltr_short_idle_timeout: */ struct iwx_ltr_config_cmd { uint32_t flags; uint32_t static_long; uint32_t static_short; uint32_t ltr_cfg_values[IWX_LTR_VALID_STATES_NUM]; uint32_t ltr_short_idle_timeout; } __packed; /* LTR_CAPABLE_API_S_VER_2 */ /* Radio LP RX Energy Threshold measured in dBm */ #define IWX_POWER_LPRX_RSSI_THRESHOLD 75 #define IWX_POWER_LPRX_RSSI_THRESHOLD_MAX 94 #define IWX_POWER_LPRX_RSSI_THRESHOLD_MIN 30 /** * Masks for iwx_mac_power_cmd command flags * @IWX_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off * receiver and transmitter. '0' - does not allow. * @IWX_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, * '1' Driver enables PM (use rest of parameters) * @IWX_POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, * '1' PM could sleep over DTIM till listen Interval. * @IWX_POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all * access categories are both delivery and trigger enabled. * @IWX_POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and * PBW Snoozing enabled * @IWX_POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask * @IWX_POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. * @IWX_POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving * detection enablement */ #define IWX_POWER_FLAGS_POWER_SAVE_ENA_MSK (1 << 0) #define IWX_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK (1 << 1) #define IWX_POWER_FLAGS_SKIP_OVER_DTIM_MSK (1 << 2) #define IWX_POWER_FLAGS_SNOOZE_ENA_MSK (1 << 5) #define IWX_POWER_FLAGS_BT_SCO_ENA (1 << 8) #define IWX_POWER_FLAGS_ADVANCE_PM_ENA_MSK (1 << 9) #define IWX_POWER_FLAGS_LPRX_ENA_MSK (1 << 11) #define IWX_POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK (1 << 12) #define IWX_POWER_VEC_SIZE 5 /** * Masks for device power command flags * @IWX_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK: * '1' Allow to save power by turning off receiver and transmitter. * '0' Do not allow. This flag should be always set to '1' unless * one needs to disable actual power down for debug purposes. * @IWX_DEVICE_POWER_FLAGS_CAM_MSK: * '1' CAM (Continuous Active Mode) is set, power management is disabled. * '0' Power management is enabled, one of the power schemes is applied. */ #define IWX_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK (1 << 0) #define IWX_DEVICE_POWER_FLAGS_CAM_MSK (1 << 13) /** * struct iwx_device_power_cmd - device wide power command. * IWX_POWER_TABLE_CMD = 0x77 (command, has simple generic response) * * @flags: Power table command flags from IWX_DEVICE_POWER_FLAGS_* */ struct iwx_device_power_cmd { /* PM_POWER_TABLE_CMD_API_S_VER_6 */ uint16_t flags; uint16_t reserved; } __packed; /** * struct iwx_mac_power_cmd - New power command containing uAPSD support * IWX_MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) * @id_and_color: MAC contex identifier * @flags: Power table command flags from POWER_FLAGS_* * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. * Minimum allowed:- 3 * DTIM. Keep alive period must be * set regardless of power scheme or current power state. * FW use this value also when PM is disabled. * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to * PSM transition - legacy PM * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to * PSM transition - legacy PM * @sleep_interval: not in use * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag * is set. For example, if it is required to skip over * one DTIM, this value need to be set to 2 (DTIM periods). * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to * PSM transition - uAPSD * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to * PSM transition - uAPSD * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. * Default: 80dbm * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set * @snooze_interval: Maximum time between attempts to retrieve buffered data * from the AP [msec] * @snooze_window: A window of time in which PBW snoozing insures that all * packets received. It is also the minimum time from last * received unicast RX packet, before client stops snoozing * for data. [msec] * @snooze_step: TBD * @qndp_tid: TID client shall use for uAPSD QNDP triggers * @uapsd_ac_flags: Set trigger-enabled and delivery-enabled indication for * each corresponding AC. * Use IEEE80211_WMM_IE_STA_QOSINFO_AC* for correct values. * @uapsd_max_sp: Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct * values. * @heavy_tx_thld_packets: TX threshold measured in number of packets * @heavy_rx_thld_packets: RX threshold measured in number of packets * @heavy_tx_thld_percentage: TX threshold measured in load's percentage * @heavy_rx_thld_percentage: RX threshold measured in load's percentage * @limited_ps_threshold: */ struct iwx_mac_power_cmd { /* CONTEXT_DESC_API_T_VER_1 */ uint32_t id_and_color; /* CLIENT_PM_POWER_TABLE_S_VER_1 */ uint16_t flags; uint16_t keep_alive_seconds; uint32_t rx_data_timeout; uint32_t tx_data_timeout; uint32_t rx_data_timeout_uapsd; uint32_t tx_data_timeout_uapsd; uint8_t lprx_rssi_threshold; uint8_t skip_dtim_periods; uint16_t snooze_interval; uint16_t snooze_window; uint8_t snooze_step; uint8_t qndp_tid; uint8_t uapsd_ac_flags; uint8_t uapsd_max_sp; uint8_t heavy_tx_thld_packets; uint8_t heavy_rx_thld_packets; uint8_t heavy_tx_thld_percentage; uint8_t heavy_rx_thld_percentage; uint8_t limited_ps_threshold; uint8_t reserved; } __packed; #define IWX_DEFAULT_PS_TX_DATA_TIMEOUT (100 * 1000) #define IWX_DEFAULT_PS_RX_DATA_TIMEOUT (100 * 1000) /* * struct iwx_uapsd_misbehaving_ap_notif - FW sends this notification when * associated AP is identified as improperly implementing uAPSD protocol. * IWX_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78 * @sta_id: index of station in uCode's station table - associated AP ID in * this context. */ struct iwx_uapsd_misbehaving_ap_notif { uint32_t sta_id; uint8_t mac_id; uint8_t reserved[3]; } __packed; /** * struct iwx_beacon_filter_cmd * IWX_REPLY_BEACON_FILTERING_CMD = 0xd2 (command) * @id_and_color: MAC contex identifier * @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon * to driver if delta in Energy values calculated for this and last * passed beacon is greater than this threshold. Zero value means that * the Energy change is ignored for beacon filtering, and beacon will * not be forced to be sent to driver regardless of this delta. Typical * energy delta 5dB. * @bf_roaming_energy_delta: Used for RSSI filtering, if in 'roaming' state. * Send beacon to driver if delta in Energy values calculated for this * and last passed beacon is greater than this threshold. Zero value * means that the Energy change is ignored for beacon filtering while in * Roaming state, typical energy delta 1dB. * @bf_roaming_state: Used for RSSI filtering. If absolute Energy values * calculated for current beacon is less than the threshold, use * Roaming Energy Delta Threshold, otherwise use normal Energy Delta * Threshold. Typical energy threshold is -72dBm. * @bf_temp_threshold: This threshold determines the type of temperature * filtering (Slow or Fast) that is selected (Units are in Celsuis): * If the current temperature is above this threshold - Fast filter * will be used, If the current temperature is below this threshold - * Slow filter will be used. * @bf_temp_fast_filter: Send Beacon to driver if delta in temperature values * calculated for this and the last passed beacon is greater than this * threshold. Zero value means that the temperature change is ignored for * beacon filtering; beacons will not be forced to be sent to driver * regardless of whether its temerature has been changed. * @bf_temp_slow_filter: Send Beacon to driver if delta in temperature values * calculated for this and the last passed beacon is greater than this * threshold. Zero value means that the temperature change is ignored for * beacon filtering; beacons will not be forced to be sent to driver * regardless of whether its temerature has been changed. * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled. * @bf_escape_timer: Send beacons to driver if no beacons were passed * for a specific period of time. Units: Beacons. * @ba_escape_timer: Fully receive and parse beacon if no beacons were passed * for a longer period of time then this escape-timeout. Units: Beacons. * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled. * @bf_threshold_absolute_low: See below. * @bf_threshold_absolute_high: Send Beacon to driver if Energy value calculated * for this beacon crossed this absolute threshold. For the 'Increase' * direction the bf_energy_absolute_low[i] is used. For the 'Decrease' * direction the bf_energy_absolute_high[i] is used. Zero value means * that this specific threshold is ignored for beacon filtering, and * beacon will not be forced to be sent to driver due to this setting. */ struct iwx_beacon_filter_cmd { uint32_t bf_energy_delta; uint32_t bf_roaming_energy_delta; uint32_t bf_roaming_state; uint32_t bf_temp_threshold; uint32_t bf_temp_fast_filter; uint32_t bf_temp_slow_filter; uint32_t bf_enable_beacon_filter; uint32_t bf_debug_flag; uint32_t bf_escape_timer; uint32_t ba_escape_timer; uint32_t ba_enable_beacon_abort; uint32_t bf_threshold_absolute_low[2]; uint32_t bf_threshold_absolute_high[2]; } __packed; /* BEACON_FILTER_CONFIG_API_S_VER_4 */ /* Beacon filtering and beacon abort */ #define IWX_BF_ENERGY_DELTA_DEFAULT 5 #define IWX_BF_ENERGY_DELTA_MAX 255 #define IWX_BF_ENERGY_DELTA_MIN 0 #define IWX_BF_ROAMING_ENERGY_DELTA_DEFAULT 1 #define IWX_BF_ROAMING_ENERGY_DELTA_MAX 255 #define IWX_BF_ROAMING_ENERGY_DELTA_MIN 0 #define IWX_BF_ROAMING_STATE_DEFAULT 72 #define IWX_BF_ROAMING_STATE_MAX 255 #define IWX_BF_ROAMING_STATE_MIN 0 #define IWX_BF_TEMP_THRESHOLD_DEFAULT 112 #define IWX_BF_TEMP_THRESHOLD_MAX 255 #define IWX_BF_TEMP_THRESHOLD_MIN 0 #define IWX_BF_TEMP_FAST_FILTER_DEFAULT 1 #define IWX_BF_TEMP_FAST_FILTER_MAX 255 #define IWX_BF_TEMP_FAST_FILTER_MIN 0 #define IWX_BF_TEMP_SLOW_FILTER_DEFAULT 5 #define IWX_BF_TEMP_SLOW_FILTER_MAX 255 #define IWX_BF_TEMP_SLOW_FILTER_MIN 0 #define IWX_BF_ENABLE_BEACON_FILTER_DEFAULT 1 #define IWX_BF_DEBUG_FLAG_DEFAULT 0 #define IWX_BF_ESCAPE_TIMER_DEFAULT 50 #define IWX_BF_ESCAPE_TIMER_MAX 1024 #define IWX_BF_ESCAPE_TIMER_MIN 0 #define IWX_BA_ESCAPE_TIMER_DEFAULT 6 #define IWX_BA_ESCAPE_TIMER_D3 9 #define IWX_BA_ESCAPE_TIMER_MAX 1024 #define IWX_BA_ESCAPE_TIMER_MIN 0 #define IWX_BA_ENABLE_BEACON_ABORT_DEFAULT 1 #define IWX_BF_CMD_CONFIG_DEFAULTS \ .bf_energy_delta = htole32(IWX_BF_ENERGY_DELTA_DEFAULT), \ .bf_roaming_energy_delta = \ htole32(IWX_BF_ROAMING_ENERGY_DELTA_DEFAULT), \ .bf_roaming_state = htole32(IWX_BF_ROAMING_STATE_DEFAULT), \ .bf_temp_threshold = htole32(IWX_BF_TEMP_THRESHOLD_DEFAULT), \ .bf_temp_fast_filter = htole32(IWX_BF_TEMP_FAST_FILTER_DEFAULT), \ .bf_temp_slow_filter = htole32(IWX_BF_TEMP_SLOW_FILTER_DEFAULT), \ .bf_debug_flag = htole32(IWX_BF_DEBUG_FLAG_DEFAULT), \ .bf_escape_timer = htole32(IWX_BF_ESCAPE_TIMER_DEFAULT), \ .ba_escape_timer = htole32(IWX_BA_ESCAPE_TIMER_DEFAULT) /* uCode API values for HT/VHT bit rates */ #define IWX_RATE_HT_SISO_MCS_0_PLCP 0 #define IWX_RATE_HT_SISO_MCS_1_PLCP 1 #define IWX_RATE_HT_SISO_MCS_2_PLCP 2 #define IWX_RATE_HT_SISO_MCS_3_PLCP 3 #define IWX_RATE_HT_SISO_MCS_4_PLCP 4 #define IWX_RATE_HT_SISO_MCS_5_PLCP 5 #define IWX_RATE_HT_SISO_MCS_6_PLCP 6 #define IWX_RATE_HT_SISO_MCS_7_PLCP 7 #define IWX_RATE_HT_MIMO2_MCS_8_PLCP 0x8 #define IWX_RATE_HT_MIMO2_MCS_9_PLCP 0x9 #define IWX_RATE_HT_MIMO2_MCS_10_PLCP 0xA #define IWX_RATE_HT_MIMO2_MCS_11_PLCP 0xB #define IWX_RATE_HT_MIMO2_MCS_12_PLCP 0xC #define IWX_RATE_HT_MIMO2_MCS_13_PLCP 0xD #define IWX_RATE_HT_MIMO2_MCS_14_PLCP 0xE #define IWX_RATE_HT_MIMO2_MCS_15_PLCP 0xF #define IWX_RATE_VHT_SISO_MCS_0_PLCP 0 #define IWX_RATE_VHT_SISO_MCS_1_PLCP 1 #define IWX_RATE_VHT_SISO_MCS_2_PLCP 2 #define IWX_RATE_VHT_SISO_MCS_3_PLCP 3 #define IWX_RATE_VHT_SISO_MCS_4_PLCP 4 #define IWX_RATE_VHT_SISO_MCS_5_PLCP 5 #define IWX_RATE_VHT_SISO_MCS_6_PLCP 6 #define IWX_RATE_VHT_SISO_MCS_7_PLCP 7 #define IWX_RATE_VHT_SISO_MCS_8_PLCP 8 #define IWX_RATE_VHT_SISO_MCS_9_PLCP 9 #define IWX_RATE_VHT_MIMO2_MCS_0_PLCP 0x10 #define IWX_RATE_VHT_MIMO2_MCS_1_PLCP 0x11 #define IWX_RATE_VHT_MIMO2_MCS_2_PLCP 0x12 #define IWX_RATE_VHT_MIMO2_MCS_3_PLCP 0x13 #define IWX_RATE_VHT_MIMO2_MCS_4_PLCP 0x14 #define IWX_RATE_VHT_MIMO2_MCS_5_PLCP 0x15 #define IWX_RATE_VHT_MIMO2_MCS_6_PLCP 0x16 #define IWX_RATE_VHT_MIMO2_MCS_7_PLCP 0x17 #define IWX_RATE_VHT_MIMO2_MCS_8_PLCP 0x18 #define IWX_RATE_VHT_MIMO2_MCS_9_PLCP 0x19 #define IWX_RATE_HT_SISO_MCS_INV_PLCP 0x1A #define IWX_RATE_HT_MIMO2_MCS_INV_PLCP IWX_RATE_HT_SISO_MCS_INV_PLCP #define IWX_RATE_VHT_SISO_MCS_INV_PLCP IWX_RATE_HT_SISO_MCS_INV_PLCP #define IWX_RATE_VHT_MIMO2_MCS_INV_PLCP IWX_RATE_HT_SISO_MCS_INV_PLCP #define IWX_RATE_HT_SISO_MCS_8_PLCP IWX_RATE_HT_SISO_MCS_INV_PLCP #define IWX_RATE_HT_SISO_MCS_9_PLCP IWX_RATE_HT_SISO_MCS_INV_PLCP /* * These serve as indexes into struct iwx_rate iwx_rates[IWX_RIDX_MAX]. */ enum { IWX_RATE_1M_INDEX = 0, IWX_FIRST_CCK_RATE = IWX_RATE_1M_INDEX, IWX_RATE_2M_INDEX, IWX_RATE_5M_INDEX, IWX_RATE_11M_INDEX, IWX_LAST_CCK_RATE = IWX_RATE_11M_INDEX, IWX_RATE_6M_INDEX, IWX_FIRST_OFDM_RATE = IWX_RATE_6M_INDEX, IWX_RATE_MCS_0_INDEX = IWX_RATE_6M_INDEX, IWX_FIRST_HT_RATE = IWX_RATE_MCS_0_INDEX, IWX_FIRST_VHT_RATE = IWX_RATE_MCS_0_INDEX, IWX_RATE_9M_INDEX, IWX_RATE_12M_INDEX, IWX_RATE_MCS_1_INDEX = IWX_RATE_12M_INDEX, IWX_RATE_MCS_8_INDEX, IWX_FIRST_HT_MIMO2_RATE = IWX_RATE_MCS_8_INDEX, IWX_RATE_18M_INDEX, IWX_RATE_MCS_2_INDEX = IWX_RATE_18M_INDEX, IWX_RATE_24M_INDEX, IWX_RATE_MCS_3_INDEX = IWX_RATE_24M_INDEX, IWX_RATE_MCS_9_INDEX, IWX_RATE_36M_INDEX, IWX_RATE_MCS_4_INDEX = IWX_RATE_36M_INDEX, IWX_RATE_MCS_10_INDEX, IWX_RATE_48M_INDEX, IWX_RATE_MCS_5_INDEX = IWX_RATE_48M_INDEX, IWX_RATE_MCS_11_INDEX, IWX_RATE_54M_INDEX, IWX_RATE_MCS_6_INDEX = IWX_RATE_54M_INDEX, IWX_LAST_NON_HT_RATE = IWX_RATE_54M_INDEX, IWX_RATE_MCS_7_INDEX, IWX_LAST_HT_SISO_RATE = IWX_RATE_MCS_7_INDEX, IWX_RATE_MCS_12_INDEX, IWX_RATE_MCS_13_INDEX, IWX_RATE_MCS_14_INDEX, IWX_RATE_MCS_15_INDEX, IWX_LAST_HT_RATE = IWX_RATE_MCS_15_INDEX, IWX_LAST_VHT_RATE = IWX_RATE_MCS_9_INDEX, IWX_RATE_COUNT_LEGACY = IWX_LAST_NON_HT_RATE + 1, IWX_RATE_COUNT = IWX_LAST_HT_RATE + 1, }; #define IWX_RATE_BIT_MSK(r) (1 << (IWX_RATE_##r##M_INDEX)) /* fw API values for legacy bit rates, both OFDM and CCK */ #define IWX_RATE_6M_PLCP 13 #define IWX_RATE_9M_PLCP 15 #define IWX_RATE_12M_PLCP 5 #define IWX_RATE_18M_PLCP 7 #define IWX_RATE_24M_PLCP 9 #define IWX_RATE_36M_PLCP 11 #define IWX_RATE_48M_PLCP 1 #define IWX_RATE_54M_PLCP 3 #define IWX_RATE_1M_PLCP 10 #define IWX_RATE_2M_PLCP 20 #define IWX_RATE_5M_PLCP 55 #define IWX_RATE_11M_PLCP 110 #define IWX_RATE_INVM_PLCP 0xff /* * rate_n_flags bit fields * * The 32-bit value has different layouts in the low 8 bites depending on the * format. There are three formats, HT, VHT and legacy (11abg, with subformats * for CCK and OFDM). * * High-throughput (HT) rate format * bit 8 is 1, bit 26 is 0, bit 9 is 0 (OFDM) * Very High-throughput (VHT) rate format * bit 8 is 0, bit 26 is 1, bit 9 is 0 (OFDM) * Legacy OFDM rate format for bits 7:0 * bit 8 is 0, bit 26 is 0, bit 9 is 0 (OFDM) * Legacy CCK rate format for bits 7:0: * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK) */ /* Bit 8: (1) HT format, (0) legacy or VHT format */ #define IWX_RATE_MCS_HT_POS 8 #define IWX_RATE_MCS_HT_MSK_V1 (1 << IWX_RATE_MCS_HT_POS) /* Bit 9: (1) CCK, (0) OFDM. HT (bit 8) must be "0" for this bit to be valid */ #define IWX_RATE_MCS_CCK_POS_V1 9 #define IWX_RATE_MCS_CCK_MSK_V1 (1 << IWX_RATE_MCS_CCK_POS_V1) /* Bit 26: (1) VHT format, (0) legacy format in bits 8:0 */ #define IWX_RATE_MCS_VHT_POS_V1 26 #define IWX_RATE_MCS_VHT_MSK_V1 (1 << IWX_RATE_MCS_VHT_POS_V1) /* Bit 10 - OFDM HE */ #define IWX_RATE_MCS_HE_POS_V1 10 #define IWX_RATE_MCS_HE_MSK_V1 (1 << IWX_RATE_MCS_HE_POS_V1) /* * High-throughput (HT) rate format for bits 7:0 * * 2-0: MCS rate base * 0) 6 Mbps * 1) 12 Mbps * 2) 18 Mbps * 3) 24 Mbps * 4) 36 Mbps * 5) 48 Mbps * 6) 54 Mbps * 7) 60 Mbps * 4-3: 0) Single stream (SISO) * 1) Dual stream (MIMO) * 2) Triple stream (MIMO) * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps HT40 duplicate data * (bits 7-6 are zero) * * Together the low 5 bits work out to the MCS index because we don't * support MCSes above 15/23, and 0-7 have one stream, 8-15 have two * streams and 16-23 have three streams. We could also support MCS 32 * which is the duplicate 20 MHz MCS (bit 5 set, all others zero.) */ #define IWX_RATE_HT_MCS_RATE_CODE_MSK_V1 0x7 #define IWX_RATE_HT_MCS_NSS_POS_V1 3 #define IWX_RATE_HT_MCS_NSS_MSK_V1 (3 << IWX_RATE_HT_MCS_NSS_POS_V1) #define IWX_RATE_HT_MCS_MIMO2_MSK (1 << IWX_RATE_HT_MCS_NSS_POS_V1) /* Bit 10: (1) Use Green Field preamble */ #define IWX_RATE_HT_MCS_GF_POS 10 #define IWX_RATE_HT_MCS_GF_MSK (1 << IWX_RATE_HT_MCS_GF_POS) #define IWX_RATE_HT_MCS_INDEX_MSK_V1 0x3f /* * Very High-throughput (VHT) rate format for bits 7:0 * * 3-0: VHT MCS (0-9) * 5-4: number of streams - 1: * 0) Single stream (SISO) * 1) Dual stream (MIMO) * 2) Triple stream (MIMO) */ /* Bit 4-5: (0) SISO, (1) MIMO2 (2) MIMO3 */ #define IWX_RATE_VHT_MCS_RATE_CODE_MSK 0xf #define IWX_RATE_VHT_MCS_NSS_POS 4 #define IWX_RATE_VHT_MCS_NSS_MSK (3 << IWX_RATE_VHT_MCS_NSS_POS) #define IWX_RATE_VHT_MCS_MIMO2_MSK (1 << IWX_RATE_VHT_MCS_NSS_POS) /* * Legacy OFDM rate format for bits 7:0 * * 3-0: 0xD) 6 Mbps * 0xF) 9 Mbps * 0x5) 12 Mbps * 0x7) 18 Mbps * 0x9) 24 Mbps * 0xB) 36 Mbps * 0x1) 48 Mbps * 0x3) 54 Mbps * (bits 7-4 are 0) * * Legacy CCK rate format for bits 7:0: * bit 8 is 0, bit 26 is 0, bit 9 is 1 (CCK): * * 6-0: 10) 1 Mbps * 20) 2 Mbps * 55) 5.5 Mbps * 110) 11 Mbps * (bit 7 is 0) */ #define IWX_RATE_LEGACY_RATE_MSK_V1 0xff /* * Bit 11-12: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz * 0 and 1 are valid for HT and VHT, 2 and 3 only for VHT */ #define IWX_RATE_MCS_CHAN_WIDTH_POS 11 #define IWX_RATE_MCS_CHAN_WIDTH_MSK_V1 (3 << IWX_RATE_MCS_CHAN_WIDTH_POS) /* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */ #define IWX_RATE_MCS_SGI_POS_V1 13 #define IWX_RATE_MCS_SGI_MSK_V1 BIT(IWX_RATE_MCS_SGI_POS_V1) /* * Bits 13-11: (0) 20MHz, (1) 40MHz, (2) 80MHz, (3) 160MHz, (4) 320MHz */ #define IWX_RATE_MCS_CHAN_WIDTH_MSK (0x7 << IWX_RATE_MCS_CHAN_WIDTH_POS) #define IWX_RATE_MCS_CHAN_WIDTH_20 (0 << IWX_RATE_MCS_CHAN_WIDTH_POS) #define IWX_RATE_MCS_CHAN_WIDTH_40 (1 << IWX_RATE_MCS_CHAN_WIDTH_POS) #define IWX_RATE_MCS_CHAN_WIDTH_80 (2 << IWX_RATE_MCS_CHAN_WIDTH_POS) #define IWX_RATE_MCS_CHAN_WIDTH_160 (3 << IWX_RATE_MCS_CHAN_WIDTH_POS) #define IWX_RATE_MCS_CHAN_WIDTH_320 (4 << IWX_RATE_MCS_CHAN_WIDTH_POS) /* Bit 15-14: Antenna selection: * Bit 14: Ant A active * Bit 15: Ant B active * * All relevant definitions are same as in v1 */ /* Bit 16 (1) LDPC enables, (0) LDPC disabled */ #define IWX_RATE_MCS_LDPC_POS 16 #define IWX_RATE_MCS_LDPC_MSK (1 << IWX_RATE_MCS_LDPC_POS) /* Bit 17: (0) SS, (1) SS*2 (same as v1) */ /* Bit 18: OFDM-HE dual carrier mode (same as v1) */ /* Bit 19: (0) Beamforming is off, (1) Beamforming is on (same as v1) */ /* * Bit 22-20: HE LTF type and guard interval * CCK: * 0 long preamble * 1 short preamble * HT/VHT: * 0 0.8us * 1 0.4us * HE (ext) SU: * 0 1xLTF+0.8us * 1 2xLTF+0.8us * 2 2xLTF+1.6us * 3 4xLTF+3.2us * 4 4xLTF+0.8us * HE MU: * 0 4xLTF+0.8us * 1 2xLTF+0.8us * 2 2xLTF+1.6us * 3 4xLTF+3.2us * HE TRIG: * 0 1xLTF+1.6us * 1 2xLTF+1.6us * 2 4xLTF+3.2us * */ #define IWX_RATE_MCS_HE_GI_LTF_MSK (0x7 << IWX_RATE_MCS_HE_GI_LTF_POS) #define IWX_RATE_MCS_SGI_POS IWX_RATE_MCS_HE_GI_LTF_POS #define IWX_RATE_MCS_SGI_MSK (1 << IWX_RATE_MCS_SGI_POS) #define IWX_RATE_MCS_HE_SU_4_LTF 3 #define IWX_RATE_MCS_HE_SU_4_LTF_08_GI 4 /* Bit 24-23: HE type. (0) SU, (1) SU_EXT, (2) MU, (3) trigger based */ #define IWX_RATE_MCS_HE_TYPE_POS 23 #define IWX_RATE_MCS_HE_TYPE_SU (0 << IWX_RATE_MCS_HE_TYPE_POS) #define IWX_RATE_MCS_HE_TYPE_EXT_SU (1 << IWX_RATE_MCS_HE_TYPE_POS) #define IWX_RATE_MCS_HE_TYPE_MU (2 << IWX_RATE_MCS_HE_TYPE_POS) #define IWX_RATE_MCS_HE_TYPE_TRIG (3 << IWX_RATE_MCS_HE_TYPE_POS) #define IWX_RATE_MCS_HE_TYPE_MSK (3 << IWX_RATE_MCS_HE_TYPE_POS) /* Bit 25: duplicate channel enabled * * if this bit is set, duplicate is according to BW (bits 11-13): * * CCK: 2x 20MHz * OFDM Legacy: N x 20Mhz, (N = BW \ 2 , either 2, 4, 8, 16) * EHT: 2 x BW/2, (80 - 2x40, 160 - 2x80, 320 - 2x160) * */ #define IWX_RATE_MCS_DUP_POS 25 #define IWX_RATE_MCS_DUP_MSK (1 << IWX_RATE_MCS_DUP_POS) /* Bit 26: (1) 106-tone RX (8 MHz RU), (0) normal bandwidth */ #define IWX_RATE_MCS_HE_106T_POS 26 #define IWX_RATE_MCS_HE_106T_MSK (1 << IWX_RATE_MCS_HE_106T_POS) /* Bit 27: EHT extra LTF: * instead of 1 LTF for SISO use 2 LTFs, * instead of 2 LTFs for NSTS=2 use 4 LTFs*/ #define IWX_RATE_MCS_EHT_EXTRA_LTF_POS 27 #define IWX_RATE_MCS_EHT_EXTRA_LTF_MSK (1 << IWX_RATE_MCS_EHT_EXTRA_LTF_POS) /* Bit 14-16: Antenna selection (1) Ant A, (2) Ant B, (4) Ant C */ #define IWX_RATE_MCS_ANT_POS 14 #define IWX_RATE_MCS_ANT_A_MSK (1 << IWX_RATE_MCS_ANT_POS) #define IWX_RATE_MCS_ANT_B_MSK (2 << IWX_RATE_MCS_ANT_POS) #define IWX_RATE_MCS_ANT_C_MSK (4 << IWX_RATE_MCS_ANT_POS) #define IWX_RATE_MCS_ANT_AB_MSK (IWX_RATE_MCS_ANT_A_MSK | \ IWX_RATE_MCS_ANT_B_MSK) #define IWX_RATE_MCS_ANT_ABC_MSK (IWX_RATE_MCS_ANT_AB_MSK | \ IWX_RATE_MCS_ANT_C_MSK) #define IWX_RATE_MCS_ANT_MSK IWX_RATE_MCS_ANT_ABC_MSK #define IWX_RATE_MCS_ANT_NUM 3 /* Bit 17-18: (0) SS, (1) SS*2 */ #define IWX_RATE_MCS_STBC_POS 17 #define IWX_RATE_MCS_STBC_MSK (1 << IWX_RATE_MCS_STBC_POS) /* Bit 18: OFDM-HE dual carrier mode */ #define IWX_RATE_HE_DUAL_CARRIER_MODE 18 #define IWX_RATE_HE_DUAL_CARRIER_MODE_MSK (1 << IWX_RATE_HE_DUAL_CARRIER_MODE) /* Bit 19: (0) Beamforming is off, (1) Beamforming is on */ #define IWX_RATE_MCS_BF_POS 19 #define IWX_RATE_MCS_BF_MSK (1 << IWX_RATE_MCS_BF_POS) /* * Bit 20-21: HE LTF type and guard interval * HE (ext) SU: * 0 1xLTF+0.8us * 1 2xLTF+0.8us * 2 2xLTF+1.6us * 3 & SGI (bit 13) clear 4xLTF+3.2us * 3 & SGI (bit 13) set 4xLTF+0.8us * HE MU: * 0 4xLTF+0.8us * 1 2xLTF+0.8us * 2 2xLTF+1.6us * 3 4xLTF+3.2us * HE TRIG: * 0 1xLTF+1.6us * 1 2xLTF+1.6us * 2 4xLTF+3.2us * 3 (does not occur) */ #define IWX_RATE_MCS_HE_GI_LTF_POS 20 #define IWX_RATE_MCS_HE_GI_LTF_MSK_V1 (3 << IWX_RATE_MCS_HE_GI_LTF_POS) /* Bit 22-23: HE type. (0) SU, (1) SU_EXT, (2) MU, (3) trigger based */ #define IWX_RATE_MCS_HE_TYPE_POS_V1 22 #define IWX_RATE_MCS_HE_TYPE_SU_V1 (0 << IWX_RATE_MCS_HE_TYPE_POS_V1) #define IWX_RATE_MCS_HE_TYPE_EXT_SU_V1 BIT(IWX_RATE_MCS_HE_TYPE_POS_V1) #define IWX_RATE_MCS_HE_TYPE_MU_V1 (2 << IWX_RATE_MCS_HE_TYPE_POS_V1) #define IWX_RATE_MCS_HE_TYPE_TRIG_V1 (3 << IWX_RATE_MCS_HE_TYPE_POS_V1) #define IWX_RATE_MCS_HE_TYPE_MSK_V1 (3 << IWX_RATE_MCS_HE_TYPE_POS_V1) /* Bit 24-25: (0) 20MHz (no dup), (1) 2x20MHz, (2) 4x20MHz, 3 8x20MHz */ #define IWX_RATE_MCS_DUP_POS_V1 24 #define IWX_RATE_MCS_DUP_MSK_V1 (3 << IWX_RATE_MCS_DUP_POS_V1) /* Bit 27: (1) LDPC enabled, (0) LDPC disabled */ #define IWX_RATE_MCS_LDPC_POS_V1 27 #define IWX_RATE_MCS_LDPC_MSK_V1 BIT(IWX_RATE_MCS_LDPC_POS_V1) /* Bit 28: (1) 106-tone RX (8 MHz RU), (0) normal bandwidth */ #define IWX_RATE_MCS_HE_106T_POS_V1 28 #define IWX_RATE_MCS_HE_106T_MSK_V1 BIT(IWX_RATE_MCS_HE_106T_POS_V1) /* Bit 30-31: (1) RTS, (2) CTS */ #define IWX_RATE_MCS_RTS_REQUIRED_POS (30) #define IWX_RATE_MCS_RTS_REQUIRED_MSK (0x1 << IWX_RATE_MCS_RTS_REQUIRED_POS) #define IWX_RATE_MCS_CTS_REQUIRED_POS (31) #define IWX_RATE_MCS_CTS_REQUIRED_MSK (0x1 << IWX_RATE_MCS_CTS_REQUIRED_POS) /* Bits 10-8: rate format * (0) Legacy CCK (1) Legacy OFDM (2) High-throughput (HT) * (3) Very High-throughput (VHT) (4) High-efficiency (HE) * (5) Extremely High-throughput (EHT) */ #define IWX_RATE_MCS_MOD_TYPE_POS 8 #define IWX_RATE_MCS_MOD_TYPE_MSK (0x7 << IWX_RATE_MCS_MOD_TYPE_POS) #define IWX_RATE_MCS_CCK_MSK (0 << IWX_RATE_MCS_MOD_TYPE_POS) #define IWX_RATE_MCS_LEGACY_OFDM_MSK (1 << IWX_RATE_MCS_MOD_TYPE_POS) #define IWX_RATE_MCS_HT_MSK (2 << IWX_RATE_MCS_MOD_TYPE_POS) #define IWX_RATE_MCS_VHT_MSK (3 << IWX_RATE_MCS_MOD_TYPE_POS) #define IWX_RATE_MCS_HE_MSK (4 << IWX_RATE_MCS_MOD_TYPE_POS) #define IWX_RATE_MCS_EHT_MSK (5 << IWX_RATE_MCS_MOD_TYPE_POS) /* * Legacy CCK rate format for bits 0:3: * * (0) 0xa - 1 Mbps * (1) 0x14 - 2 Mbps * (2) 0x37 - 5.5 Mbps * (3) 0x6e - 11 nbps * * Legacy OFDM rate format for bis 3:0: * * (0) 6 Mbps * (1) 9 Mbps * (2) 12 Mbps * (3) 18 Mbps * (4) 24 Mbps * (5) 36 Mbps * (6) 48 Mbps * (7) 54 Mbps * */ #define IWX_RATE_LEGACY_RATE_MSK 0x7 /* * HT, VHT, HE, EHT rate format for bits 3:0 * 3-0: MCS * */ #define IWX_RATE_HT_MCS_CODE_MSK 0x7 #define IWX_RATE_MCS_NSS_POS 4 #define IWX_RATE_MCS_NSS_MSK (1 << IWX_RATE_MCS_NSS_POS) #define IWX_RATE_MCS_CODE_MSK 0xf #define IWX_RATE_HT_MCS_INDEX(r) ((((r) & IWX_RATE_MCS_NSS_MSK) >> 1) | \ ((r) & IWX_RATE_HT_MCS_CODE_MSK)) /* Link Quality definitions */ /* # entries in rate scale table to support Tx retries */ #define IWX_LQ_MAX_RETRY_NUM 16 /* Link quality command flags bit fields */ /* Bit 0: (0) Don't use RTS (1) Use RTS */ #define IWX_LQ_FLAG_USE_RTS_POS 0 #define IWX_LQ_FLAG_USE_RTS_MSK (1 << IWX_LQ_FLAG_USE_RTS_POS) /* Bit 1-3: LQ command color. Used to match responses to LQ commands */ #define IWX_LQ_FLAG_COLOR_POS 1 #define IWX_LQ_FLAG_COLOR_MSK (7 << IWX_LQ_FLAG_COLOR_POS) /* Bit 4-5: Tx RTS BW Signalling * (0) No RTS BW signalling * (1) Static BW signalling * (2) Dynamic BW signalling */ #define IWX_LQ_FLAG_RTS_BW_SIG_POS 4 #define IWX_LQ_FLAG_RTS_BW_SIG_NONE (0 << IWX_LQ_FLAG_RTS_BW_SIG_POS) #define IWX_LQ_FLAG_RTS_BW_SIG_STATIC (1 << IWX_LQ_FLAG_RTS_BW_SIG_POS) #define IWX_LQ_FLAG_RTS_BW_SIG_DYNAMIC (2 << IWX_LQ_FLAG_RTS_BW_SIG_POS) /* Bit 6: (0) No dynamic BW selection (1) Allow dynamic BW selection * Dyanmic BW selection allows Tx with narrower BW then requested in rates */ #define IWX_LQ_FLAG_DYNAMIC_BW_POS 6 #define IWX_LQ_FLAG_DYNAMIC_BW_MSK (1 << IWX_LQ_FLAG_DYNAMIC_BW_POS) /** * Options for TLC config flags * @IWX_TLC_MNG_CFG_FLAGS_STBC_MSK: enable STBC. For HE this enables STBC for * bandwidths <= 80MHz * @IWX_TLC_MNG_CFG_FLAGS_LDPC_MSK: enable LDPC * @IWX_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK: enable STBC in HE at 160MHz * bandwidth * @IWX_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK: enable HE Dual Carrier Modulation * for BPSK (MCS 0) with 1 spatial * stream * @IWX_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK: enable HE Dual Carrier Modulation * for BPSK (MCS 0) with 2 spatial * streams */ #define IWX_TLC_MNG_CFG_FLAGS_STBC_MSK (1 << 0) #define IWX_TLC_MNG_CFG_FLAGS_LDPC_MSK (1 << 1) #define IWX_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK (1 << 2) #define IWX_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK (1 << 3) #define IWX_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK (1 << 4) /** * enum iwx_tlc_mng_cfg_cw - channel width options * @IWX_TLC_MNG_CH_WIDTH_20MHZ: 20MHZ channel * @IWX_TLC_MNG_CH_WIDTH_40MHZ: 40MHZ channel * @IWX_TLC_MNG_CH_WIDTH_80MHZ: 80MHZ channel * @IWX_TLC_MNG_CH_WIDTH_160MHZ: 160MHZ channel * @IWX_TLC_MNG_CH_WIDTH_LAST: maximum value */ enum iwx_tlc_mng_cfg_cw { IWX_TLC_MNG_CH_WIDTH_20MHZ, IWX_TLC_MNG_CH_WIDTH_40MHZ, IWX_TLC_MNG_CH_WIDTH_80MHZ, IWX_TLC_MNG_CH_WIDTH_160MHZ, IWX_TLC_MNG_CH_WIDTH_LAST = IWX_TLC_MNG_CH_WIDTH_160MHZ, }; /** * @IWX_TLC_MNG_CHAIN_A_MSK: chain A * @IWX_TLC_MNG_CHAIN_B_MSK: chain B */ #define IWX_TLC_MNG_CHAIN_A_MSK (1 << 0) #define IWX_TLC_MNG_CHAIN_B_MSK (1 << 1) /** * enum iwx_tlc_mng_cfg_mode - supported modes * @IWX_TLC_MNG_MODE_CCK: enable CCK * @IWX_TLC_MNG_MODE_OFDM_NON_HT: enable OFDM (non HT) * @IWX_TLC_MNG_MODE_NON_HT: enable non HT * @IWX_TLC_MNG_MODE_HT: enable HT * @IWX_TLC_MNG_MODE_VHT: enable VHT * @IWX_TLC_MNG_MODE_HE: enable HE * @IWX_TLC_MNG_MODE_INVALID: invalid value * @IWX_TLC_MNG_MODE_NUM: a count of possible modes */ enum iwx_tlc_mng_cfg_mode { IWX_TLC_MNG_MODE_CCK = 0, IWX_TLC_MNG_MODE_OFDM_NON_HT = IWX_TLC_MNG_MODE_CCK, IWX_TLC_MNG_MODE_NON_HT = IWX_TLC_MNG_MODE_CCK, IWX_TLC_MNG_MODE_HT, IWX_TLC_MNG_MODE_VHT, IWX_TLC_MNG_MODE_HE, IWX_TLC_MNG_MODE_INVALID, IWX_TLC_MNG_MODE_NUM = IWX_TLC_MNG_MODE_INVALID, }; /** * @IWX_TLC_MNG_HT_RATE_MCS0: index of MCS0 * @IWX_TLC_MNG_HT_RATE_MCS1: index of MCS1 * @IWX_TLC_MNG_HT_RATE_MCS2: index of MCS2 * @IWX_TLC_MNG_HT_RATE_MCS3: index of MCS3 * @IWX_TLC_MNG_HT_RATE_MCS4: index of MCS4 * @IWX_TLC_MNG_HT_RATE_MCS5: index of MCS5 * @IWX_TLC_MNG_HT_RATE_MCS6: index of MCS6 * @IWX_TLC_MNG_HT_RATE_MCS7: index of MCS7 * @IWX_TLC_MNG_HT_RATE_MCS8: index of MCS8 * @IWX_TLC_MNG_HT_RATE_MCS9: index of MCS9 * @IWX_TLC_MNG_HT_RATE_MCS10: index of MCS10 * @IWX_TLC_MNG_HT_RATE_MCS11: index of MCS11 * @IWX_TLC_MNG_HT_RATE_MAX: maximal rate for HT/VHT */ enum iwx_tlc_mng_ht_rates { IWX_TLC_MNG_HT_RATE_MCS0 = 0, IWX_TLC_MNG_HT_RATE_MCS1, IWX_TLC_MNG_HT_RATE_MCS2, IWX_TLC_MNG_HT_RATE_MCS3, IWX_TLC_MNG_HT_RATE_MCS4, IWX_TLC_MNG_HT_RATE_MCS5, IWX_TLC_MNG_HT_RATE_MCS6, IWX_TLC_MNG_HT_RATE_MCS7, IWX_TLC_MNG_HT_RATE_MCS8, IWX_TLC_MNG_HT_RATE_MCS9, IWX_TLC_MNG_HT_RATE_MCS10, IWX_TLC_MNG_HT_RATE_MCS11, IWX_TLC_MNG_HT_RATE_MAX = IWX_TLC_MNG_HT_RATE_MCS11, }; #define IWX_TLC_NSS_1 0 #define IWX_TLC_NSS_2 1 #define IWX_TLC_NSS_MAX 2 #define IWX_TLC_MCS_PER_BW_80 0 #define IWX_TLC_MCS_PER_BW_160 1 #define IWX_TLC_MCS_PER_BW_320 2 #define IWX_TLC_MCS_PER_BW_NUM_V3 (IWX_TLC_MCS_PER_BW_160 + 1) #define IWX_TLC_MCS_PER_BW_NUM_V4 (IWX_TLC_MCS_PER_BW_320 + 1) /** * struct iwx_tlc_config_cmd - TLC configuration * @sta_id: station id * @reserved1: reserved * @max_ch_width: max supported channel width from @enum iwx_tlc_mng_cfg_cw * @mode: &enum iwx_tlc_mng_cfg_mode * @chains: bitmask of IWX_TLC_MNG_CHAIN_*_MSK * @amsdu: TX amsdu is supported * @flags: bitmask of IWX_TLC_MNG_CFG_* * @non_ht_rates: bitmap of supported legacy rates * @ht_rates: bitmap of &enum iwl_tlc_mng_ht_rates, per &enum IWL_TLC_MCS_PER_BW * pair (0 - 80mhz width and below, 1 - 160mhz). * @max_mpdu_len: max MPDU length, in bytes * @sgi_ch_width_supp: bitmap of SGI support per channel width * use (1 << @enum iwx_tlc_mng_cfg_cw) * @reserved2: reserved * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI), * set zero for no limit. */ struct iwl_tlc_config_cmd_v3 { uint8_t sta_id; uint8_t reserved1[3]; uint8_t max_ch_width; uint8_t mode; uint8_t chains; uint8_t amsdu; uint16_t flags; uint16_t non_ht_rates; uint16_t ht_rates[IWX_TLC_NSS_MAX][IWX_TLC_MCS_PER_BW_NUM_V3]; uint16_t max_mpdu_len; uint8_t sgi_ch_width_supp; uint8_t reserved2; uint32_t max_tx_op; } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_3 */ /** * struct iwx_tlc_config_cmd_v4 - TLC configuration * @sta_id: station id * @reserved1: reserved * @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw * @mode: &enum iwl_tlc_mng_cfg_mode * @chains: bitmask of &enum iwl_tlc_mng_cfg_chains * @sgi_ch_width_supp: bitmap of SGI support per channel width * use BIT(&enum iwl_tlc_mng_cfg_cw) * @flags: bitmask of &enum iwl_tlc_mng_cfg_flags * @non_ht_rates: bitmap of supported legacy rates * @ht_rates: bitmap of &enum iwl_tlc_mng_ht_rates, per * pair (0 - 80mhz width and below, 1 - 160mhz, 2 - 320mhz). * @max_mpdu_len: max MPDU length, in bytes * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI), * set zero for no limit. */ struct iwx_tlc_config_cmd_v4 { uint8_t sta_id; uint8_t reserved1[3]; uint8_t max_ch_width; uint8_t mode; uint8_t chains; uint8_t sgi_ch_width_supp; uint16_t flags; uint16_t non_ht_rates; uint16_t ht_rates[IWX_TLC_NSS_MAX][IWX_TLC_MCS_PER_BW_NUM_V4]; uint16_t max_mpdu_len; uint16_t max_tx_op; } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_4 */ /** * @IWX_TLC_NOTIF_FLAG_RATE: last initial rate update * @IWX_TLC_NOTIF_FLAG_AMSDU: umsdu parameters update */ #define IWX_TLC_NOTIF_FLAG_RATE (1 << 0) #define IWX_TLC_NOTIF_FLAG_AMSDU (1 << 1) /** * struct iwx_tlc_update_notif - TLC notification from FW * @sta_id: station id * @reserved: reserved * @flags: bitmap of notifications reported * @rate: current initial rate * @amsdu_size: Max AMSDU size, in bytes * @amsdu_enabled: bitmap for per-TID AMSDU enablement */ struct iwx_tlc_update_notif { uint8_t sta_id; uint8_t reserved[3]; uint32_t flags; uint32_t rate; uint32_t amsdu_size; uint32_t amsdu_enabled; } __packed; /* TLC_MNG_UPDATE_NTFY_API_S_VER_2 */ /* Antenna flags. */ #define IWX_ANT_NONE 0x0 #define IWX_ANT_INVALID 0xff #define IWX_ANT_A (1 << 0) #define IWX_ANT_B (1 << 1) #define IWX_ANT_C (1 << 2) /* Shortcuts. */ #define IWX_ANT_AB (IWX_ANT_A | IWX_ANT_B) #define IWX_ANT_AC (IWX_ANT_A | IWX_ANT_C) #define IWX_ANT_BC (IWX_ANT_B | IWX_ANT_C) #define IWX_ANT_ABC (IWX_ANT_A | IWX_ANT_B | IWX_ANT_C) #define IWX_MAX_ANT_NUM 3 /** * bitmasks for tx_flags in TX command * @IWX_TX_CMD_FLG_PROT_REQUIRE: use RTS or CTS-to-self to protect the frame * @IWX_TX_CMD_FLG_ACK: expect ACK from receiving station * @IWX_TX_CMD_FLG_STA_RATE: use RS table with initial index from the TX command. * Otherwise, use rate_n_flags from the TX command * @IWX_TX_CMD_FLG_BA: this frame is a block ack * @IWX_TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected * Must set IWX_TX_CMD_FLG_ACK with this flag. * @IWX_TX_CMD_FLG_TXOP_PROT: protect frame with full TXOP protection * @IWX_TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence * @IWX_TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence * @IWX_TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC) * @IWX_TX_CMD_FLG_BT_DIS: disable BT priority for this frame * @IWX_TX_CMD_FLG_SEQ_CTL: set if FW should override the sequence control. * Should be set for mgmt, non-QOS data, mcast, bcast and in scan command * @IWX_TX_CMD_FLG_MORE_FRAG: this frame is non-last MPDU * @IWX_TX_CMD_FLG_NEXT_FRAME: this frame includes information of the next frame * @IWX_TX_CMD_FLG_TSF: FW should calculate and insert TSF in the frame * Should be set for beacons and probe responses * @IWX_TX_CMD_FLG_CALIB: activate PA TX power calibrations * @IWX_TX_CMD_FLG_KEEP_SEQ_CTL: if seq_ctl is set, don't increase inner seq count * @IWX_TX_CMD_FLG_AGG_START: allow this frame to start aggregation * @IWX_TX_CMD_FLG_MH_PAD: driver inserted 2 byte padding after MAC header. * Should be set for 26/30 length MAC headers * @IWX_TX_CMD_FLG_RESP_TO_DRV: zero this if the response should go only to FW * @IWX_TX_CMD_FLG_CCMP_AGG: this frame uses CCMP for aggregation acceleration * @IWX_TX_CMD_FLG_TKIP_MIC_DONE: FW already performed TKIP MIC calculation * @IWX_TX_CMD_FLG_DUR: disable duration overwriting used in PS-Poll Assoc-id * @IWX_TX_CMD_FLG_FW_DROP: FW should mark frame to be dropped * @IWX_TX_CMD_FLG_EXEC_PAPD: execute PAPD * @IWX_TX_CMD_FLG_PAPD_TYPE: 0 for reference power, 1 for nominal power * @IWX_TX_CMD_FLG_HCCA_CHUNK: mark start of TSPEC chunk */ #define IWX_TX_CMD_FLG_PROT_REQUIRE (1 << 0) #define IWX_TX_CMD_FLG_ACK (1 << 3) #define IWX_TX_CMD_FLG_STA_RATE (1 << 4) #define IWX_TX_CMD_FLG_BA (1 << 5) #define IWX_TX_CMD_FLG_BAR (1 << 6) #define IWX_TX_CMD_FLG_TXOP_PROT (1 << 7) #define IWX_TX_CMD_FLG_VHT_NDPA (1 << 8) #define IWX_TX_CMD_FLG_HT_NDPA (1 << 9) #define IWX_TX_CMD_FLG_CSI_FDBK2HOST (1 << 10) #define IWX_TX_CMD_FLG_BT_DIS (1 << 12) #define IWX_TX_CMD_FLG_SEQ_CTL (1 << 13) #define IWX_TX_CMD_FLG_MORE_FRAG (1 << 14) #define IWX_TX_CMD_FLG_NEXT_FRAME (1 << 15) #define IWX_TX_CMD_FLG_TSF (1 << 16) #define IWX_TX_CMD_FLG_CALIB (1 << 17) #define IWX_TX_CMD_FLG_KEEP_SEQ_CTL (1 << 18) #define IWX_TX_CMD_FLG_AGG_START (1 << 19) #define IWX_TX_CMD_FLG_MH_PAD (1 << 20) #define IWX_TX_CMD_FLG_RESP_TO_DRV (1 << 21) #define IWX_TX_CMD_FLG_CCMP_AGG (1 << 22) #define IWX_TX_CMD_FLG_TKIP_MIC_DONE (1 << 23) #define IWX_TX_CMD_FLG_DUR (1 << 25) #define IWX_TX_CMD_FLG_FW_DROP (1 << 26) #define IWX_TX_CMD_FLG_EXEC_PAPD (1 << 27) #define IWX_TX_CMD_FLG_PAPD_TYPE (1 << 28) #define IWX_TX_CMD_FLG_HCCA_CHUNK (1U << 31) /* IWX_TX_FLAGS_BITS_API_S_VER_1 */ /* * TX command security control */ #define IWX_TX_CMD_SEC_WEP 0x01 #define IWX_TX_CMD_SEC_CCM 0x02 #define IWX_TX_CMD_SEC_TKIP 0x03 #define IWX_TX_CMD_SEC_EXT 0x04 #define IWX_TX_CMD_SEC_MSK 0x07 #define IWX_TX_CMD_SEC_WEP_KEY_IDX_POS 6 #define IWX_TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 #define IWX_TX_CMD_SEC_KEY128 0x08 /* TODO: how does these values are OK with only 16 bit variable??? */ /* * TX command next frame info * * bits 0:2 - security control (IWX_TX_CMD_SEC_*) * bit 3 - immediate ACK required * bit 4 - rate is taken from STA table * bit 5 - frame belongs to BA stream * bit 6 - immediate BA response expected * bit 7 - unused * bits 8:15 - Station ID * bits 16:31 - rate */ #define IWX_TX_CMD_NEXT_FRAME_ACK_MSK (0x8) #define IWX_TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10) #define IWX_TX_CMD_NEXT_FRAME_BA_MSK (0x20) #define IWX_TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40) #define IWX_TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8) #define IWX_TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00) #define IWX_TX_CMD_NEXT_FRAME_STA_ID_POS (8) #define IWX_TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000) #define IWX_TX_CMD_NEXT_FRAME_RATE_POS (16) /* * TX command Frame life time in us - to be written in pm_frame_timeout */ #define IWX_TX_CMD_LIFE_TIME_INFINITE 0xFFFFFFFF #define IWX_TX_CMD_LIFE_TIME_DEFAULT 2000000 /* 2000 ms*/ #define IWX_TX_CMD_LIFE_TIME_PROBE_RESP 40000 /* 40 ms */ #define IWX_TX_CMD_LIFE_TIME_EXPIRED_FRAME 0 #define IWX_MAX_TID_COUNT 8 /* * TID for non QoS frames - to be written in tid_tspec */ #define IWX_TID_NON_QOS 0 #define IWX_MGMT_TID 15 #define IWX_QID_MGMT EDCA_AC_BE + IWX_DQA_AUX_QUEUE + 1 /* * Limits on the retransmissions - to be written in {data,rts}_retry_limit */ #define IWX_DEFAULT_TX_RETRY 15 #define IWX_MGMT_DFAULT_RETRY_LIMIT 3 #define IWX_RTS_DFAULT_RETRY_LIMIT 3 #define IWX_BAR_DFAULT_RETRY_LIMIT 60 #define IWX_LOW_RETRY_LIMIT 7 /* * The FH will write back to the first TB only, so we need to copy some data * into the buffer regardless of whether it should be mapped or not. * This indicates how big the first TB must be to include the scratch buffer * and the assigned PN. * Since PN location is 8 bytes at offset 12, it's 20 now. * If we make it bigger then allocations will be bigger and copy slower, so * that's probably not useful. */ #define IWX_FIRST_TB_SIZE 20 #define IWX_FIRST_TB_SIZE_ALIGN ((IWX_FIRST_TB_SIZE + (64 - 1)) & ~(64 - 1)) /** * %iwl_tx_cmd offload_assist values * @TX_CMD_OFFLD_IP_HDR: offset to start of IP header (in words) * from mac header end. For normal case it is 4 words for SNAP. * note: tx_cmd, mac header and pad are not counted in the offset. * This is used to help the offload in case there is tunneling such as * IPv6 in IPv4, in such case the ip header offset should point to the * inner ip header and IPv4 checksum of the external header should be * calculated by driver. * @TX_CMD_OFFLD_L4_EN: enable TCP/UDP checksum * @TX_CMD_OFFLD_L3_EN: enable IP header checksum * @TX_CMD_OFFLD_MH_SIZE: size of the mac header in words. Includes the IV * field. Doesn't include the pad. * @TX_CMD_OFFLD_PAD: mark 2-byte pad was inserted after the mac header for * alignment * @TX_CMD_OFFLD_AMSDU: mark TX command is A-MSDU */ #define IWX_TX_CMD_OFFLD_IP_HDR(x) ((x) << 0) #define IWX_TX_CMD_OFFLD_L4_EN (1 << 6) #define IWX_TX_CMD_OFFLD_L3_EN (1 << 7) #define IWX_TX_CMD_OFFLD_MH_SIZE(x) ((x) << 8) #define IWX_TX_CMD_OFFLD_PAD (1 << 13) #define IWX_TX_CMD_OFFLD_AMSDU (1 << 14) #define IWX_TX_CMD_OFFLD_MH_MASK 0x1f #define IWX_TX_CMD_OFFLD_IP_HDR_MASK 0x3f struct iwx_dram_sec_info { uint32_t pn_low; uint16_t pn_high; uint16_t aux_info; } __packed; /* DRAM_SEC_INFO_API_S_VER_1 */ /** * bitmasks for tx_flags in TX command for 22000 * @IWX_TX_FLAGS_CMD_RATE: use rate from the TX command * @IWX_TX_FLAGS_ENCRYPT_DIS: frame should not be encrypted, even if it belongs * to a secured STA * @IWX_TX_FLAGS_HIGH_PRI: high priority frame (like EAPOL) - can affect rate * selection, retry limits and BT kill */ #define IWX_TX_FLAGS_CMD_RATE (1 << 0) #define IWX_TX_FLAGS_ENCRYPT_DIS (1 << 1) #define IWX_TX_FLAGS_HIGH_PRI (1 << 2) /* TX_FLAGS_BITS_API_S_VER_3 */ /** * struct iwx_tx_cmd_gen2 - TX command struct to FW for 22000 devices * ( TX_CMD = 0x1c ) * @len: in bytes of the payload, see below for details * @offload_assist: TX offload configuration * @flags: combination of TX_CMD_FLG_* * @dram_info: FW internal DRAM storage * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* * @hdr: 802.11 header */ struct iwx_tx_cmd_gen2 { uint16_t len; uint16_t offload_assist; uint32_t flags; struct iwx_dram_sec_info dram_info; uint32_t rate_n_flags; struct ieee80211_frame hdr[0]; } __packed; /* TX_CMD_API_S_VER_7 */ /** * struct iwx_tx_cmd_gen3 - TX command struct to FW for AX210+ devices * ( TX_CMD = 0x1c ) * @len: in bytes of the payload, see below for details * @flags: combination of &enum iwl_tx_cmd_flags * @offload_assist: TX offload configuration * @dram_info: FW internal DRAM storage * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* * @ttl: time to live - packet lifetime limit. The FW should drop if * passed. * @hdr: 802.11 header */ struct iwx_tx_cmd_gen3 { __le16 len; __le16 flags; __le32 offload_assist; struct iwx_dram_sec_info dram_info; __le32 rate_n_flags; __le64 ttl; struct ieee80211_frame hdr[0]; } __packed; /* TX_CMD_API_S_VER_8 */ /* For aggregation queues, index must be aligned to frame sequence number. */ #define IWX_AGG_SSN_TO_TXQ_IDX(x, a) ((x) & ((a) - 1)) /* * TX response related data */ /* * status that is returned by the fw after attempts to Tx * @IWX_TX_STATUS_FAIL_STA_COLOR_MISMATCH: mismatch between color of Tx cmd and * STA table * Valid only if frame_count =1 */ #define IWX_TX_STATUS_MSK 0x000000ff #define IWX_TX_STATUS_SUCCESS 0x01 #define IWX_TX_STATUS_DIRECT_DONE 0x02 /* postpone TX */ #define IWX_TX_STATUS_POSTPONE_DELAY 0x40 #define IWX_TX_STATUS_POSTPONE_FEW_BYTES 0x41 #define IWX_TX_STATUS_POSTPONE_BT_PRIO 0x42 #define IWX_TX_STATUS_POSTPONE_QUIET_PERIOD 0x43 #define IWX_TX_STATUS_POSTPONE_CALC_TTAK 0x44 /* abort TX */ #define IWX_TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY 0x81 #define IWX_TX_STATUS_FAIL_SHORT_LIMIT 0x82 #define IWX_TX_STATUS_FAIL_LONG_LIMIT 0x83 #define IWX_TX_STATUS_FAIL_UNDERRUN 0x84 #define IWX_TX_STATUS_FAIL_DRAIN_FLOW 0x85 #define IWX_TX_STATUS_FAIL_RFKILL_FLUSH 0x86 #define IWX_TX_STATUS_FAIL_LIFE_EXPIRE 0x87 #define IWX_TX_STATUS_FAIL_DEST_PS 0x88 #define IWX_TX_STATUS_FAIL_HOST_ABORTED 0x89 #define IWX_TX_STATUS_FAIL_BT_RETRY 0x8a #define IWX_TX_STATUS_FAIL_STA_INVALID 0x8b #define IWX_TX_STATUS_FAIL_FRAG_DROPPED 0x8c #define IWX_TX_STATUS_FAIL_TID_DISABLE 0x8d #define IWX_TX_STATUS_FAIL_FIFO_FLUSHED 0x8e #define IWX_TX_STATUS_FAIL_SMALL_CF_POLL 0x8f #define IWX_TX_STATUS_FAIL_FW_DROP 0x90 #define IWX_TX_STATUS_FAIL_STA_COLOR_MISMATCH 0x91 #define IWX_TX_STATUS_INTERNAL_ABORT 0x92 #define IWX_TX_MODE_MSK 0x00000f00 #define IWX_TX_MODE_NO_BURST 0x00000000 #define IWX_TX_MODE_IN_BURST_SEQ 0x00000100 #define IWX_TX_MODE_FIRST_IN_BURST 0x00000200 #define IWX_TX_QUEUE_NUM_MSK 0x0001f000 #define IWX_TX_NARROW_BW_MSK 0x00060000 #define IWX_TX_NARROW_BW_1DIV2 0x00020000 #define IWX_TX_NARROW_BW_1DIV4 0x00040000 #define IWX_TX_NARROW_BW_1DIV8 0x00060000 /* * TX aggregation status * @IWX_AGG_TX_STATE_TRY_CNT_MSK: Retry count for 1st frame in aggregation (retries * occur if tx failed for this frame when it was a member of a previous * aggregation block). If rate scaling is used, retry count indicates the * rate table entry used for all frames in the new agg. * @IWX_AGG_TX_STATE_SEQ_NUM_MSK: Command ID and sequence number of Tx command for * this frame */ #define IWX_AGG_TX_STATE_STATUS_MSK 0x0fff #define IWX_AGG_TX_STATE_TRANSMITTED 0x0000 #define IWX_AGG_TX_STATE_UNDERRUN 0x0001 #define IWX_AGG_TX_STATE_BT_PRIO 0x0002 #define IWX_AGG_TX_STATE_FEW_BYTES 0x0004 #define IWX_AGG_TX_STATE_ABORT 0x0008 #define IWX_AGG_TX_STATE_TX_ON_AIR_DROP 0x0010 #define IWX_AGG_TX_STATE_LAST_SENT_TRY_CNT 0x0020 #define IWX_AGG_TX_STATE_LAST_SENT_BT_KILL 0x0040 #define IWX_AGG_TX_STATE_SCD_QUERY 0x0080 #define IWX_AGG_TX_STATE_TEST_BAD_CRC32 0x0100 #define IWX_AGG_TX_STATE_RESPONSE 0x01ff #define IWX_AGG_TX_STATE_DUMP_TX 0x0200 #define IWX_AGG_TX_STATE_DELAY_TX 0x0400 #define IWX_AGG_TX_STATE_TRY_CNT_POS 12 #define IWX_AGG_TX_STATE_TRY_CNT_MSK (0xf << IWX_AGG_TX_STATE_TRY_CNT_POS) #define IWX_AGG_TX_STATE_LAST_SENT_MSK (IWX_AGG_TX_STATE_LAST_SENT_TTL| \ IWX_AGG_TX_STATE_LAST_SENT_TRY_CNT| \ IWX_AGG_TX_STATE_LAST_SENT_BT_KILL) /* * The mask below describes a status where we are absolutely sure that the MPDU * wasn't sent. For BA/Underrun we cannot be that sure. All we know that we've * written the bytes to the TXE, but we know nothing about what the DSP did. */ #define IWX_AGG_TX_STAT_FRAME_NOT_SENT (IWX_AGG_TX_STATE_FEW_BYTES | \ IWX_AGG_TX_STATE_ABORT | \ IWX_AGG_TX_STATE_SCD_QUERY) /* * IWX_REPLY_TX = 0x1c (response) * * This response may be in one of two slightly different formats, indicated * by the frame_count field: * * 1) No aggregation (frame_count == 1). This reports Tx results for a single * frame. Multiple attempts, at various bit rates, may have been made for * this frame. * * 2) Aggregation (frame_count > 1). This reports Tx results for two or more * frames that used block-acknowledge. All frames were transmitted at * same rate. Rate scaling may have been used if first frame in this new * agg block failed in previous agg block(s). * * Note that, for aggregation, ACK (block-ack) status is not delivered * here; block-ack has not been received by the time the device records * this status. * This status relates to reasons the tx might have been blocked or aborted * within the device, rather than whether it was received successfully by * the destination station. */ /** * struct iwx_agg_tx_status - per packet TX aggregation status * @status: enum iwx_tx_agg_status * @sequence: Sequence # for this frame's Tx cmd (not SSN!) */ struct iwx_agg_tx_status { uint16_t status; uint16_t sequence; } __packed; /* * definitions for initial rate index field * bits [3:0] initial rate index * bits [6:4] rate table color, used for the initial rate * bit-7 invalid rate indication */ #define IWX_TX_RES_INIT_RATE_INDEX_MSK 0x0f #define IWX_TX_RES_RATE_TABLE_COLOR_MSK 0x70 #define IWX_TX_RES_INV_RATE_INDEX_MSK 0x80 #define IWX_TX_RES_GET_TID(_ra_tid) ((_ra_tid) & 0x0f) #define IWX_TX_RES_GET_RA(_ra_tid) ((_ra_tid) >> 4) /** * struct iwx_tx_resp_v3 - notifies that fw is TXing a packet * ( IWX_REPLY_TX = 0x1c ) * @frame_count: 1 no aggregation, >1 aggregation * @bt_kill_count: num of times blocked by bluetooth (unused for agg) * @failure_rts: num of failures due to unsuccessful RTS * @failure_frame: num failures due to no ACK (unused for agg) * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the * Tx of all the batch. IWX_RATE_MCS_* * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK. * for agg: RTS + CTS + aggregation tx time + block-ack time. * in usec. * @pa_status: tx power info * @pa_integ_res_a: tx power info * @pa_integ_res_b: tx power info * @pa_integ_res_c: tx power info * @measurement_req_id: tx power info * @tfd_info: TFD information set by the FH * @seq_ctl: sequence control from the Tx cmd * @byte_cnt: byte count from the Tx cmd * @tlc_info: TLC rate info * @ra_tid: bits [3:0] = ra, bits [7:4] = tid * @frame_ctrl: frame control * @status: for non-agg: frame status IWX_TX_STATUS_* * for agg: status of 1st frame, IWX_AGG_TX_STATE_*; other frame status fields * follow this one, up to frame_count. * * After the array of statuses comes the SSN of the SCD. Look at * %iwx_get_scd_ssn for more details. */ struct iwx_tx_resp_v3 { uint8_t frame_count; uint8_t bt_kill_count; uint8_t failure_rts; uint8_t failure_frame; uint32_t initial_rate; uint16_t wireless_media_time; uint8_t pa_status; uint8_t pa_integ_res_a[3]; uint8_t pa_integ_res_b[3]; uint8_t pa_integ_res_c[3]; uint16_t measurement_req_id; uint16_t reserved; uint32_t tfd_info; uint16_t seq_ctl; uint16_t byte_cnt; uint8_t tlc_info; uint8_t ra_tid; uint16_t frame_ctrl; struct iwx_agg_tx_status status; } __packed; /* IWX_TX_RSP_API_S_VER_3 */ /** * struct iwx_tx_resp - notifies that fw is TXing a packet * ( REPLY_TX = 0x1c ) * @frame_count: 1 no aggregation, >1 aggregation * @bt_kill_count: num of times blocked by bluetooth (unused for agg) * @failure_rts: num of failures due to unsuccessful RTS * @failure_frame: num failures due to no ACK (unused for agg) * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the * Tx of all the batch. RATE_MCS_* * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK. * for agg: RTS + CTS + aggregation tx time + block-ack time. * in usec. * @pa_status: tx power info * @pa_integ_res_a: tx power info * @pa_integ_res_b: tx power info * @pa_integ_res_c: tx power info * @measurement_req_id: tx power info * @reduced_tpc: transmit power reduction used * @reserved: reserved * @tfd_info: TFD information set by the FH * @seq_ctl: sequence control from the Tx cmd * @byte_cnt: byte count from the Tx cmd * @tlc_info: TLC rate info * @ra_tid: bits [3:0] = ra, bits [7:4] = tid * @frame_ctrl: frame control * @tx_queue: TX queue for this response * @reserved2: reserved for padding/alignment * @status: for non-agg: frame status TX_STATUS_* * For version 6 TX response isn't received for aggregation at all. * * After the array of statuses comes the SSN of the SCD. Look at * %iwl_mvm_get_scd_ssn for more details. */ struct iwx_tx_resp { uint8_t frame_count; uint8_t bt_kill_count; uint8_t failure_rts; uint8_t failure_frame; uint32_t initial_rate; uint16_t wireless_media_time; uint8_t pa_status; uint8_t pa_integ_res_a[3]; uint8_t pa_integ_res_b[3]; uint8_t pa_integ_res_c[3]; uint16_t measurement_req_id; uint8_t reduced_tpc; uint8_t reserved; uint32_t tfd_info; uint16_t seq_ctl; uint16_t byte_cnt; uint8_t tlc_info; uint8_t ra_tid; uint16_t frame_ctrl; uint16_t tx_queue; uint16_t reserved2; struct iwx_agg_tx_status status; } __packed; /* TX_RSP_API_S_VER_6 */ /** * struct iwx_compressed_ba_tfd - progress of a TFD queue * @q_num: TFD queue number * @tfd_index: Index of first un-acked frame in the TFD queue * @scd_queue: For debug only - the physical queue the TFD queue is bound to * @tid: TID of the queue (0-7) * @reserved: reserved for alignment */ struct iwx_compressed_ba_tfd { __le16 q_num; __le16 tfd_index; u8 scd_queue; u8 tid; u8 reserved[2]; } __packed; /* COMPRESSED_BA_TFD_API_S_VER_1 */ /** * struct iwx_compressed_ba_ratid - progress of a RA TID queue * @q_num: RA TID queue number * @tid: TID of the queue * @ssn: BA window current SSN */ struct iwx_compressed_ba_ratid { u8 q_num; u8 tid; __le16 ssn; } __packed; /* COMPRESSED_BA_RATID_API_S_VER_1 */ /* * enum iwx_ba_resp_flags - TX aggregation status * @IWX_BA_RESP_TX_AGG: generated due to BA * @IWX_BA_RESP_TX_BAR: generated due to BA after BAR * @IWX_BA_RESP_TX_AGG_FAIL: aggregation didn't receive BA * @IWX_BA_RESP_TX_UNDERRUN: aggregation got underrun * @IWX_BA_RESP_TX_BT_KILL: aggregation got BT-kill * @IWX_BA_RESP_TX_DSP_TIMEOUT: aggregation didn't finish within the * expected time */ enum iwx_ba_resp_flags { IWX_BA_RESP_TX_AGG, IWX_BA_RESP_TX_BAR, IWX_BA_RESP_TX_AGG_FAIL, IWX_BA_RESP_TX_UNDERRUN, IWX_BA_RESP_TX_BT_KILL, IWX_BA_RESP_TX_DSP_TIMEOUT }; /** * struct iwl_mvm_compressed_ba_notif - notifies about reception of BA * ( BA_NOTIF = 0xc5 ) * @flags: status flag, see the &iwl_mvm_ba_resp_flags * @sta_id: Index of recipient (BA-sending) station in fw's station table * @reduced_txp: power reduced according to TPC. This is the actual value and * not a copy from the LQ command. Thus, if not the first rate was used * for Tx-ing then this value will be set to 0 by FW. * @tlc_rate_info: TLC rate info, initial rate index, TLC table color * @retry_cnt: retry count * @query_byte_cnt: SCD query byte count * @query_frame_cnt: SCD query frame count * @txed: number of frames sent in the aggregation (all-TIDs) * @done: number of frames that were Acked by the BA (all-TIDs) * @reserved: reserved (for alignment) * @wireless_time: Wireless-media time * @tx_rate: the rate the aggregation was sent at * @tfd_cnt: number of TFD-Q elements * @ra_tid_cnt: number of RATID-Q elements * @tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd * for details. Length in @tfd_cnt. * @ra_tid: array of RA-TID queue status updates. For debug purposes only. See * &iwl_mvm_compressed_ba_ratid for more details. Length in @ra_tid_cnt. */ struct iwx_compressed_ba_notif { __le32 flags; u8 sta_id; u8 reduced_txp; u8 tlc_rate_info; u8 retry_cnt; __le32 query_byte_cnt; __le16 query_frame_cnt; __le16 txed; __le16 done; __le16 reserved; __le32 wireless_time; __le32 tx_rate; __le16 tfd_cnt; __le16 ra_tid_cnt; struct iwx_compressed_ba_ratid ra_tid[0]; struct iwx_compressed_ba_tfd tfd[]; } __packed; /* COMPRESSED_BA_RES_API_S_VER_4 */ struct iwx_beacon_notif { struct iwx_tx_resp_v3 beacon_notify_hdr; uint64_t tsf; uint32_t ibss_mgr_status; } __packed; /** * dump (flush) control flags * @IWX_DUMP_TX_FIFO_FLUSH: Dump MSDUs until the FIFO is empty * and the TFD queues are empty. */ #define IWX_DUMP_TX_FIFO_FLUSH (1 << 1) /** * struct iwx_tx_path_flush_cmd -- queue/FIFO flush command * @queues_ctl: bitmap of queues to flush * @flush_ctl: control flags * @reserved: reserved */ struct iwx_tx_path_flush_cmd_v1 { uint32_t queues_ctl; uint16_t flush_ctl; uint16_t reserved; } __packed; /* IWX_TX_PATH_FLUSH_CMD_API_S_VER_1 */ /** * struct iwl_tx_path_flush_cmd -- queue/FIFO flush command * @sta_id: station ID to flush * @tid_mask: TID mask to flush * @reserved: reserved */ struct iwx_tx_path_flush_cmd { uint32_t sta_id; uint16_t tid_mask; uint16_t reserved; } __packed; /* TX_PATH_FLUSH_CMD_API_S_VER_2 */ #define IWX_TX_FLUSH_QUEUE_RSP 16 /** * struct iwx_flush_queue_info - virtual flush queue info * @queue_num: virtual queue id * @read_before_flush: read pointer before flush * @read_after_flush: read pointer after flush */ struct iwx_flush_queue_info { uint16_t tid; uint16_t queue_num; uint16_t read_before_flush; uint16_t read_after_flush; } __packed; /* TFDQ_FLUSH_INFO_API_S_VER_1 */ /** * struct iwx_tx_path_flush_cmd_rsp -- queue/FIFO flush command response * @num_flushed_queues: number of queues in queues array * @queues: all flushed queues */ struct iwx_tx_path_flush_cmd_rsp { uint16_t sta_id; uint16_t num_flushed_queues; struct iwx_flush_queue_info queues[IWX_TX_FLUSH_QUEUE_RSP]; } __packed; /* TX_PATH_FLUSH_CMD_RSP_API_S_VER_1 */ /** * iwx_get_scd_ssn - returns the SSN of the SCD * @tx_resp: the Tx response from the fw (agg or non-agg) * * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since * it can't know that everything will go well until the end of the AMPDU, it * can't know in advance the number of MPDUs that will be sent in the current * batch. This is why it writes the agg Tx response while it fetches the MPDUs. * Hence, it can't know in advance what the SSN of the SCD will be at the end * of the batch. This is why the SSN of the SCD is written at the end of the * whole struct at a variable offset. This function knows how to cope with the * variable offset and returns the SSN of the SCD. */ static inline uint32_t iwx_get_scd_ssn(struct iwx_tx_resp *tx_resp) { return le32_to_cpup((uint32_t *)&tx_resp->status + tx_resp->frame_count) & 0xfff; } /** * struct iwx_scd_txq_cfg_cmd - New txq hw scheduler config command * @token: * @sta_id: station id * @tid: * @scd_queue: scheduler queue to confiug * @enable: 1 queue enable, 0 queue disable * @aggregate: 1 aggregated queue, 0 otherwise * @tx_fifo: %enum iwx_tx_fifo * @window: BA window size * @ssn: SSN for the BA agreement */ struct iwx_scd_txq_cfg_cmd { uint8_t token; uint8_t sta_id; uint8_t tid; uint8_t scd_queue; uint8_t enable; uint8_t aggregate; uint8_t tx_fifo; uint8_t window; uint16_t ssn; uint16_t reserved; } __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */ /** * struct iwx_scd_txq_cfg_rsp * @token: taken from the command * @sta_id: station id from the command * @tid: tid from the command * @scd_queue: scd_queue from the command */ struct iwx_scd_txq_cfg_rsp { uint8_t token; uint8_t sta_id; uint8_t tid; uint8_t scd_queue; } __packed; /* SCD_QUEUE_CFG_RSP_API_S_VER_1 */ /* Scan Commands, Responses, Notifications */ /* Max number of IEs for direct SSID scans in a command */ #define IWX_PROBE_OPTION_MAX 20 #define IWX_SCAN_SHORT_SSID_MAX_SIZE 8 #define IWX_SCAN_BSSID_MAX_SIZE 16 /** * struct iwx_ssid_ie - directed scan network information element * * Up to 20 of these may appear in IWX_REPLY_SCAN_CMD, * selected by "type" bit field in struct iwx_scan_channel; * each channel may select different ssids from among the 20 entries. * SSID IEs get transmitted in reverse order of entry. */ struct iwx_ssid_ie { uint8_t id; uint8_t len; uint8_t ssid[IEEE80211_NWID_LEN]; } __packed; /* IWX_SCAN_DIRECT_SSID_IE_API_S_VER_1 */ /* scan offload */ #define IWX_SCAN_MAX_BLACKLIST_LEN 64 #define IWX_SCAN_SHORT_BLACKLIST_LEN 16 #define IWX_SCAN_MAX_PROFILES 11 #define IWX_SCAN_OFFLOAD_PROBE_REQ_SIZE 512 /* Default watchdog (in MS) for scheduled scan iteration */ #define IWX_SCHED_SCAN_WATCHDOG cpu_to_le16(15000) #define IWX_GOOD_CRC_TH_DEFAULT cpu_to_le16(1) #define IWX_CAN_ABORT_STATUS 1 #define IWX_FULL_SCAN_MULTIPLIER 5 #define IWX_FAST_SCHED_SCAN_ITERATIONS 3 #define IWX_MAX_SCHED_SCAN_PLANS 2 /** * iwx_scan_schedule_lmac - schedule of scan offload * @delay: delay between iterations, in seconds. * @iterations: num of scan iterations * @full_scan_mul: number of partial scans before each full scan */ struct iwx_scan_schedule_lmac { uint16_t delay; uint8_t iterations; uint8_t full_scan_mul; } __packed; /* SCAN_SCHEDULE_API_S */ /** * iwx_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S * @tx_flags: combination of TX_CMD_FLG_* * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_* * @sta_id: index of destination station in FW station table * @reserved: for alignment and future use */ struct iwx_scan_req_tx_cmd { uint32_t tx_flags; uint32_t rate_n_flags; uint8_t sta_id; uint8_t reserved[3]; } __packed; #define IWX_UNIFIED_SCAN_CHANNEL_FULL (1 << 27) #define IWX_UNIFIED_SCAN_CHANNEL_PARTIAL (1 << 28) /** * iwx_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2 * @flags: bits 1-20: directed scan to i'th ssid * other bits &enum iwx_scan_channel_flags_lmac * @channel_number: channel number 1-13 etc * @iter_count: scan iteration on this channel * @iter_interval: interval in seconds between iterations on one channel */ struct iwx_scan_channel_cfg_lmac { uint32_t flags; uint16_t channel_num; uint16_t iter_count; uint32_t iter_interval; } __packed; /* * iwx_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1 * @offset: offset in the data block * @len: length of the segment */ struct iwx_scan_probe_segment { uint16_t offset; uint16_t len; } __packed; /* iwx_scan_probe_req - PROBE_REQUEST_FRAME_API_S_VER_2 * @mac_header: first (and common) part of the probe * @band_data: band specific data * @common_data: last (and common) part of the probe * @buf: raw data block */ struct iwx_scan_probe_req_v1 { struct iwx_scan_probe_segment mac_header; struct iwx_scan_probe_segment band_data[2]; struct iwx_scan_probe_segment common_data; uint8_t buf[IWX_SCAN_OFFLOAD_PROBE_REQ_SIZE]; } __packed; /* iwl_scan_probe_req - PROBE_REQUEST_FRAME_API_S_VER_v2 * @mac_header: first (and common) part of the probe * @band_data: band specific data * @common_data: last (and common) part of the probe * @buf: raw data block */ struct iwx_scan_probe_req { struct iwx_scan_probe_segment mac_header; struct iwx_scan_probe_segment band_data[3]; struct iwx_scan_probe_segment common_data; uint8_t buf[IWX_SCAN_OFFLOAD_PROBE_REQ_SIZE]; } __packed; #define IWX_SCAN_CHANNEL_FLAG_EBS (1 << 0) #define IWX_SCAN_CHANNEL_FLAG_EBS_ACCURATE (1 << 1) #define IWX_SCAN_CHANNEL_FLAG_CACHE_ADD (1 << 2) #define IWX_SCAN_CHANNEL_FLAG_EBS_FRAG (1 << 3) #define IWX_SCAN_CHANNEL_FLAG_FORCE_EBS (1 << 4) #define IWX_SCAN_CHANNEL_FLAG_ENABLE_CHAN_ORDER (1 << 5) #define IWX_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER (1 << 6) /* iwx_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S * @flags: enum iwx_scan_channel_flags * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is * involved. * 1 - EBS is disabled. * 2 - every second scan will be full scan(and so on). */ struct iwx_scan_channel_opt { uint16_t flags; uint16_t non_ebs_ratio; } __packed; #define IWX_SCAN_PRIORITY_LOW 0 #define IWX_SCAN_PRIORITY_MEDIUM 1 #define IWX_SCAN_PRIORITY_HIGH 2 #define IWX_SCAN_PRIORITY_EXT_0_LOWEST 0 #define IWX_SCAN_PRIORITY_EXT_1 1 #define IWX_SCAN_PRIORITY_EXT_2 2 #define IWX_SCAN_PRIORITY_EXT_3 3 #define IWX_SCAN_PRIORITY_EXT_4 4 #define IWX_SCAN_PRIORITY_EXT_5 5 #define IWX_SCAN_PRIORITY_EXT_6 6 #define IWX_SCAN_PRIORITY_EXT_7_HIGHEST 7 /** * iwx_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 * @last_schedule_line: last schedule line executed (fast or regular) * @last_schedule_iteration: last scan iteration executed before scan abort * @status: enum iwx_scan_offload_complete_status * @ebs_status: EBS success status &enum iwx_scan_ebs_status * @time_after_last_iter; time in seconds elapsed after last iteration */ struct iwx_periodic_scan_complete { uint8_t last_schedule_line; uint8_t last_schedule_iteration; uint8_t status; uint8_t ebs_status; uint32_t time_after_last_iter; uint32_t reserved; } __packed; /** * struct iwx_scan_results_notif - scan results for one channel - * SCAN_RESULT_NTF_API_S_VER_3 * @channel: which channel the results are from * @band: 0 for 5.2 GHz, 1 for 2.4 GHz * @probe_status: IWX_SCAN_PROBE_STATUS_*, indicates success of probe request * @num_probe_not_sent: # of request that weren't sent due to not enough time * @duration: duration spent in channel, in usecs */ struct iwx_scan_results_notif { uint8_t channel; uint8_t band; uint8_t probe_status; uint8_t num_probe_not_sent; uint32_t duration; } __packed; #define IWX_SCAN_CLIENT_SCHED_SCAN (1 << 0) #define IWX_SCAN_CLIENT_NETDETECT (1 << 1) #define IWX_SCAN_CLIENT_ASSET_TRACKING (1 << 2) /** * iwx_scan_offload_blacklist - IWX_SCAN_OFFLOAD_BLACKLIST_S * @ssid: MAC address to filter out * @reported_rssi: AP rssi reported to the host * @client_bitmap: clients ignore this entry - enum scan_framework_client */ struct iwx_scan_offload_blacklist { uint8_t ssid[ETHER_ADDR_LEN]; uint8_t reported_rssi; uint8_t client_bitmap; } __packed; #define IWX_NETWORK_TYPE_BSS 1 #define IWX_NETWORK_TYPE_IBSS 2 #define IWX_NETWORK_TYPE_ANY 3 #define IWX_SCAN_OFFLOAD_SELECT_2_4 0x4 #define IWX_SCAN_OFFLOAD_SELECT_5_2 0x8 #define IWX_SCAN_OFFLOAD_SELECT_ANY 0xc /** * iwx_scan_offload_profile - IWX_SCAN_OFFLOAD_PROFILE_S * @ssid_index: index to ssid list in fixed part * @unicast_cipher: encryption olgorithm to match - bitmap * @aut_alg: authentication olgorithm to match - bitmap * @network_type: enum iwx_scan_offload_network_type * @band_selection: enum iwx_scan_offload_band_selection * @client_bitmap: clients waiting for match - enum scan_framework_client */ struct iwx_scan_offload_profile { uint8_t ssid_index; uint8_t unicast_cipher; uint8_t auth_alg; uint8_t network_type; uint8_t band_selection; uint8_t client_bitmap; uint8_t reserved[2]; } __packed; /** * iwx_scan_offload_profile_cfg - IWX_SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1 * @blaclist: AP list to filter off from scan results * @profiles: profiles to search for match * @blacklist_len: length of blacklist * @num_profiles: num of profiles in the list * @match_notify: clients waiting for match found notification * @pass_match: clients waiting for the results * @active_clients: active clients bitmap - enum scan_framework_client * @any_beacon_notify: clients waiting for match notification without match */ struct iwx_scan_offload_profile_cfg { struct iwx_scan_offload_profile profiles[IWX_SCAN_MAX_PROFILES]; uint8_t blacklist_len; uint8_t num_profiles; uint8_t match_notify; uint8_t pass_match; uint8_t active_clients; uint8_t any_beacon_notify; uint8_t reserved[2]; } __packed; #define IWX_SCAN_OFFLOAD_COMPLETED 1 #define IWX_SCAN_OFFLOAD_ABORTED 2 /* UMAC Scan API */ #define IWX_SCAN_CONFIG_FLAG_ACTIVATE (1 << 0) #define IWX_SCAN_CONFIG_FLAG_DEACTIVATE (1 << 1) #define IWX_SCAN_CONFIG_FLAG_FORBID_CHUB_REQS (1 << 2) #define IWX_SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS (1 << 3) #define IWX_SCAN_CONFIG_FLAG_SET_TX_CHAINS (1 << 8) #define IWX_SCAN_CONFIG_FLAG_SET_RX_CHAINS (1 << 9) #define IWX_SCAN_CONFIG_FLAG_SET_AUX_STA_ID (1 << 10) #define IWX_SCAN_CONFIG_FLAG_SET_ALL_TIMES (1 << 11) #define IWX_SCAN_CONFIG_FLAG_SET_EFFECTIVE_TIMES (1 << 12) #define IWX_SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS (1 << 13) #define IWX_SCAN_CONFIG_FLAG_SET_LEGACY_RATES (1 << 14) #define IWX_SCAN_CONFIG_FLAG_SET_MAC_ADDR (1 << 15) #define IWX_SCAN_CONFIG_FLAG_SET_FRAGMENTED (1 << 16) #define IWX_SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED (1 << 17) #define IWX_SCAN_CONFIG_FLAG_SET_CAM_MODE (1 << 18) #define IWX_SCAN_CONFIG_FLAG_CLEAR_CAM_MODE (1 << 19) #define IWX_SCAN_CONFIG_FLAG_SET_PROMISC_MODE (1 << 20) #define IWX_SCAN_CONFIG_FLAG_CLEAR_PROMISC_MODE (1 << 21) /* Bits 26-31 are for num of channels in channel_array */ #define IWX_SCAN_CONFIG_N_CHANNELS(n) ((n) << 26) /* OFDM basic rates */ #define IWX_SCAN_CONFIG_RATE_6M (1 << 0) #define IWX_SCAN_CONFIG_RATE_9M (1 << 1) #define IWX_SCAN_CONFIG_RATE_12M (1 << 2) #define IWX_SCAN_CONFIG_RATE_18M (1 << 3) #define IWX_SCAN_CONFIG_RATE_24M (1 << 4) #define IWX_SCAN_CONFIG_RATE_36M (1 << 5) #define IWX_SCAN_CONFIG_RATE_48M (1 << 6) #define IWX_SCAN_CONFIG_RATE_54M (1 << 7) /* CCK basic rates */ #define IWX_SCAN_CONFIG_RATE_1M (1 << 8) #define IWX_SCAN_CONFIG_RATE_2M (1 << 9) #define IWX_SCAN_CONFIG_RATE_5M (1 << 10) #define IWX_SCAN_CONFIG_RATE_11M (1 << 11) /* Bits 16-27 are for supported rates */ #define IWX_SCAN_CONFIG_SUPPORTED_RATE(rate) ((rate) << 16) #define IWX_CHANNEL_FLAG_EBS (1 << 0) #define IWX_CHANNEL_FLAG_ACCURATE_EBS (1 << 1) #define IWX_CHANNEL_FLAG_EBS_ADD (1 << 2) #define IWX_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE (1 << 3) /** * struct iwx_scan_dwell * @active: default dwell time for active scan * @passive: default dwell time for passive scan * @fragmented: default dwell time for fragmented scan * @extended: default dwell time for channels 1, 6 and 11 */ struct iwx_scan_dwell { uint8_t active; uint8_t passive; uint8_t fragmented; uint8_t extended; } __packed; #define IWX_SCAN_TWO_LMACS 2 #define IWX_SCAN_LB_LMAC_IDX 0 /* low-band */ #define IWX_SCAN_HB_LMAC_IDX 1 /* high-band */ /** * struct iwx_scan_config * @flags: enum scan_config_flags * @tx_chains: valid_tx antenna - ANT_* definitions * @rx_chains: valid_rx antenna - ANT_* definitions * @legacy_rates: default legacy rates - enum scan_config_rates * @out_of_channel_time: default max out of serving channel time * @suspend_time: default max suspend time * @dwell_active: default dwell time for active scan * @dwell_passive: default dwell time for passive scan * @dwell_fragmented: default dwell time for fragmented scan * @dwell_extended: default dwell time for channels 1, 6 and 11 * @mac_addr: default mac address to be used in probes * @bcast_sta_id: the index of the station in the fw * @channel_flags: default channel flags - enum iwx_channel_flags * scan_config_channel_flag * @channel_array: default supported channels */ struct iwx_scan_config_v2 { uint32_t flags; uint32_t tx_chains; uint32_t rx_chains; uint32_t legacy_rates; uint32_t out_of_channel_time[IWX_SCAN_TWO_LMACS]; uint32_t suspend_time[IWX_SCAN_TWO_LMACS]; struct iwx_scan_dwell dwell; uint8_t mac_addr[ETHER_ADDR_LEN]; uint8_t bcast_sta_id; uint8_t channel_flags; uint8_t channel_array[]; } __packed; /* SCAN_CONFIG_DB_CMD_API_S_2 */ /** * struct iwx_scan_config * @enable_cam_mode: whether to enable CAM mode. * @enable_promiscouos_mode: whether to enable promiscouos mode * @bcast_sta_id: the index of the station in the fw. Deprecated starting with * API version 5. * @reserved: reserved * @tx_chains: valid_tx antenna - ANT_* definitions * @rx_chains: valid_rx antenna - ANT_* definitions */ struct iwx_scan_config { uint8_t enable_cam_mode; uint8_t enable_promiscouos_mode; uint8_t bcast_sta_id; uint8_t reserved; uint32_t tx_chains; uint32_t rx_chains; } __packed; /* SCAN_CONFIG_DB_CMD_API_S_5 */ /** * iwx_umac_scan_flags *@IWX_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request * can be preempted by other scan requests with higher priority. * The low priority scan will be resumed when the higher proirity scan is * completed. *@IWX_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver * when scan starts. */ #define IWX_UMAC_SCAN_FLAG_PREEMPTIVE (1 << 0) #define IWX_UMAC_SCAN_FLAG_START_NOTIF (1 << 1) #define IWX_UMAC_SCAN_UID_TYPE_OFFSET 0 #define IWX_UMAC_SCAN_UID_SEQ_OFFSET 8 #define IWX_UMAC_SCAN_GEN_FLAGS_PERIODIC (1 << 0) #define IWX_UMAC_SCAN_GEN_FLAGS_OVER_BT (1 << 1) #define IWX_UMAC_SCAN_GEN_FLAGS_PASS_ALL (1 << 2) #define IWX_UMAC_SCAN_GEN_FLAGS_PASSIVE (1 << 3) #define IWX_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT (1 << 4) #define IWX_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE (1 << 5) #define IWX_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID (1 << 6) #define IWX_UMAC_SCAN_GEN_FLAGS_FRAGMENTED (1 << 7) #define IWX_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED (1 << 8) #define IWX_UMAC_SCAN_GEN_FLAGS_MATCH (1 << 9) #define IWX_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL (1 << 10) /* Extended dwell is obselete when adaptive dwell is used, making this * bit reusable. Hence, probe request defer is used only when adaptive * dwell is supported. */ #define IWX_UMAC_SCAN_GEN_FLAGS_PROB_REQ_DEFER_SUPP (1 << 10) #define IWX_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED (1 << 11) #define IWX_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL (1 << 13) #define IWX_UMAC_SCAN_GEN_FLAGS_MAX_CHNL_TIME (1 << 14) #define IWX_UMAC_SCAN_GEN_FLAGS_PROB_REQ_HIGH_TX_RATE (1 << 15) /** * UMAC scan general flags #2 * @IWX_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL: Whether to send a complete * notification per channel or not. * @IWX_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER: Whether to allow channel * reorder optimization or not. */ #define IWX_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL (1 << 0) #define IWX_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER (1 << 1) /** * UMAC scan general flags version 2 * * The FW flags were reordered and hence the driver introduce version 2 * * @IWX_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC: periodic or scheduled * @IWX_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL: pass all probe responses and beacons * during scan iterations * @IWX_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE: send complete notification * on every iteration instead of only once after the last iteration * @IWX_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1: fragmented scan LMAC1 * @IWX_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2: fragmented scan LMAC2 * @IWX_UMAC_SCAN_GEN_FLAGS_V2_MATCH: does this scan check for profile matching * @IWX_UMAC_SCAN_GEN_FLAGS_V2_USE_ALL_RX_CHAINS: use all valid chains for RX * @IWX_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL: works with adaptive dwell * for active channel * @IWX_UMAC_SCAN_GEN_FLAGS_V2_PREEMPTIVE: can be preempted by other requests * @IWX_UMAC_SCAN_GEN_FLAGS_V2_NTF_START: send notification of scan start * @IWX_UMAC_SCAN_GEN_FLAGS_V2_MULTI_SSID: matching on multiple SSIDs * @IWX_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE: all the channels scanned * as passive * @IWX_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN: at the end of 2.4GHz and * 5.2Ghz bands scan, trigger scan on 6GHz band to discover * the reported collocated APs */ #define IWX_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC (1 << 0) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL (1 << 1) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE (1 << 2) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1 (1 << 3) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2 (1 << 4) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_MATCH (1 << 5) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_USE_ALL_RX_CHAINS (1 << 6) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL (1 << 7) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_PREEMPTIVE (1 << 8) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_NTF_START (1 << 9) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_MULTI_SSID (1 << 10) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE (1 << 11) #define IWX_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN (1 << 12) /** * struct iwx_scan_channel_cfg_umac * @flags: bitmap - 0-19: directed scan to i'th ssid. * @channel_num: channel number 1-13 etc. * @iter_count: repetition count for the channel. * @iter_interval: interval between two scan iterations on one channel. */ struct iwx_scan_channel_cfg_umac { uint32_t flags; union { struct { uint8_t channel_num; uint8_t iter_count; uint16_t iter_interval; } v1; /* SCAN_CHANNEL_CFG_S_VER1 */ struct { uint8_t channel_num; uint8_t band; uint8_t iter_count; uint8_t iter_interval; } v2; /* SCAN_CHANNEL_CFG_S_VER{2,3,4} */ }; } __packed; /** * struct iwx_scan_umac_schedule * @interval: interval in seconds between scan iterations * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop * @reserved: for alignment and future use */ struct iwx_scan_umac_schedule { uint16_t interval; uint8_t iter_count; uint8_t reserved; } __packed; /* SCAN_SCHED_PARAM_API_S_VER_1 */ /** * struct iwx_scan_req_umac_tail - the rest of the UMAC scan request command * parameters following channels configuration array. * @schedule: two scheduling plans. * @delay: delay in TUs before starting the first scan iteration * @reserved: for future use and alignment * @preq: probe request with IEs blocks * @direct_scan: list of SSIDs for directed active scan */ struct iwx_scan_req_umac_tail_v1 { /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ struct iwx_scan_umac_schedule schedule[IWX_MAX_SCHED_SCAN_PLANS]; uint16_t delay; uint16_t reserved; /* SCAN_PROBE_PARAMS_API_S_VER_1 */ struct iwx_scan_probe_req_v1 preq; struct iwx_ssid_ie direct_scan[IWX_PROBE_OPTION_MAX]; } __packed; /** * struct iwx_scan_req_umac_tail - the rest of the UMAC scan request command * parameters following channels configuration array. * @schedule: two scheduling plans. * @delay: delay in TUs before starting the first scan iteration * @reserved: for future use and alignment * @preq: probe request with IEs blocks * @direct_scan: list of SSIDs for directed active scan */ struct iwx_scan_req_umac_tail_v2 { /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ struct iwx_scan_umac_schedule schedule[IWX_MAX_SCHED_SCAN_PLANS]; uint16_t delay; uint16_t reserved; /* SCAN_PROBE_PARAMS_API_S_VER_2 */ struct iwx_scan_probe_req preq; struct iwx_ssid_ie direct_scan[IWX_PROBE_OPTION_MAX]; } __packed; /** * struct iwx_scan_umac_chan_param * @flags: channel flags &enum iwl_scan_channel_flags * @count: num of channels in scan request * @reserved: for future use and alignment */ struct iwx_scan_umac_chan_param { uint8_t flags; uint8_t count; uint16_t reserved; } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ #define IWX_SCAN_LB_LMAC_IDX 0 #define IWX_SCAN_HB_LMAC_IDX 1 /** * struct iwx_scan_req_umac * @flags: &enum iwl_umac_scan_flags * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @general_flags: &enum iwl_umac_scan_general_flags * @scan_start_mac_id: report the scan start TSF time according to this mac TSF * @extended_dwell: dwell time for channels 1, 6 and 11 * @active_dwell: dwell time for active scan per LMAC * @passive_dwell: dwell time for passive scan per LMAC * @fragmented_dwell: dwell time for fragmented passive scan * @adwell_default_n_aps: for adaptive dwell the default number of APs * per channel * @adwell_default_n_aps_social: for adaptive dwell the default * number of APs per social (1,6,11) channel * @general_flags2: &enum iwl_umac_scan_general_flags2 * @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added * to total scan time * @max_out_time: max out of serving channel time, per LMAC - for CDB there * are 2 LMACs (high band and low band) * @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs * @scan_priority: scan internal prioritization &enum iwl_scan_priority * @num_of_fragments: Number of fragments needed for full coverage per band. * Relevant only for fragmented scan. * @channel: &struct iwx_scan_umac_chan_param * @reserved: for future use and alignment * @reserved3: for future use and alignment * @data: &struct iwx_scan_channel_cfg_umac and * &struct iwx_scan_req_umac_tail */ struct iwx_scan_req_umac { uint32_t flags; uint32_t uid; uint32_t ooc_priority; /* SCAN_GENERAL_PARAMS_API_S_VER_1 */ uint16_t general_flags; uint8_t reserved; uint8_t scan_start_mac_id; union { struct { uint8_t extended_dwell; uint8_t active_dwell; uint8_t passive_dwell; uint8_t fragmented_dwell; uint32_t max_out_time; uint32_t suspend_time; uint32_t scan_priority; struct iwx_scan_umac_chan_param channel; uint8_t data[]; } v1; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ struct { uint8_t extended_dwell; uint8_t active_dwell; uint8_t passive_dwell; uint8_t fragmented_dwell; uint32_t max_out_time[2]; uint32_t suspend_time[2]; uint32_t scan_priority; struct iwx_scan_umac_chan_param channel; uint8_t data[]; } v6; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_6 */ struct { uint8_t active_dwell; uint8_t passive_dwell; uint8_t fragmented_dwell; uint8_t adwell_default_n_aps; uint8_t adwell_default_n_aps_social; uint8_t reserved3; uint16_t adwell_max_budget; uint32_t max_out_time[2]; uint32_t suspend_time[2]; uint32_t scan_priority; struct iwx_scan_umac_chan_param channel; uint8_t data[]; } v7; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_7 */ struct { uint8_t active_dwell[2]; uint8_t reserved2; uint8_t adwell_default_n_aps; uint8_t adwell_default_n_aps_social; uint8_t general_flags2; uint16_t adwell_max_budget; uint32_t max_out_time[2]; uint32_t suspend_time[2]; uint32_t scan_priority; uint8_t passive_dwell[2]; uint8_t num_of_fragments[2]; struct iwx_scan_umac_chan_param channel; uint8_t data[]; } v8; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_8 */ struct { uint8_t active_dwell[2]; uint8_t adwell_default_hb_n_aps; uint8_t adwell_default_lb_n_aps; uint8_t adwell_default_n_aps_social; uint8_t general_flags2; uint16_t adwell_max_budget; uint32_t max_out_time[2]; uint32_t suspend_time[2]; uint32_t scan_priority; uint8_t passive_dwell[2]; uint8_t num_of_fragments[2]; struct iwx_scan_umac_chan_param channel; uint8_t data[]; } v9; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_9 */ }; } __packed; #define IWX_SCAN_REQ_UMAC_SIZE_V8 sizeof(struct iwx_scan_req_umac) #define IWX_SCAN_REQ_UMAC_SIZE_V7 48 #define IWX_SCAN_REQ_UMAC_SIZE_V6 44 #define IWX_SCAN_REQ_UMAC_SIZE_V1 36 /** * struct iwx_scan_probe_params_v3 * @preq: scan probe request params * @ssid_num: number of valid SSIDs in direct scan array * @short_ssid_num: number of valid short SSIDs in short ssid array * @bssid_num: number of valid bssid in bssids array * @reserved: reserved * @direct_scan: list of ssids * @short_ssid: array of short ssids * @bssid_array: array of bssids */ struct iwx_scan_probe_params_v3 { struct iwx_scan_probe_req preq; uint8_t ssid_num; uint8_t short_ssid_num; uint8_t bssid_num; uint8_t reserved; struct iwx_ssid_ie direct_scan[IWX_PROBE_OPTION_MAX]; uint32_t short_ssid[IWX_SCAN_SHORT_SSID_MAX_SIZE]; uint8_t bssid_array[IWX_SCAN_BSSID_MAX_SIZE][ETHER_ADDR_LEN]; } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_3 */ /** * struct iwx_scan_probe_params_v4 * @preq: scan probe request params * @short_ssid_num: number of valid short SSIDs in short ssid array * @bssid_num: number of valid bssid in bssids array * @reserved: reserved * @direct_scan: list of ssids * @short_ssid: array of short ssids * @bssid_array: array of bssids */ struct iwx_scan_probe_params_v4 { struct iwx_scan_probe_req preq; uint8_t short_ssid_num; uint8_t bssid_num; uint16_t reserved; struct iwx_ssid_ie direct_scan[IWX_PROBE_OPTION_MAX]; uint32_t short_ssid[IWX_SCAN_SHORT_SSID_MAX_SIZE]; u8 bssid_array[IWX_SCAN_BSSID_MAX_SIZE][ETHER_ADDR_LEN]; } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */ #define IWX_SCAN_MAX_NUM_CHANS_V3 67 /** * struct iwx_scan_channel_params_v4 * @flags: channel flags &enum iwl_scan_channel_flags * @count: num of channels in scan request * @num_of_aps_override: override the number of APs the FW uses to calculate * dwell time when adaptive dwell is used * @reserved: for future use and alignment * @channel_config: array of explicit channel configurations * for 2.4Ghz and 5.2Ghz bands * @adwell_ch_override_bitmap: when using adaptive dwell, override the number * of APs value with &num_of_aps_override for the channel. * To cast channel to index, use &iwl_mvm_scan_ch_and_band_to_idx */ struct iwx_scan_channel_params_v4 { uint8_t flags; uint8_t count; uint8_t num_of_aps_override; uint8_t reserved; struct iwx_scan_channel_cfg_umac channel_config[IWX_SCAN_MAX_NUM_CHANS_V3]; uint8_t adwell_ch_override_bitmap[16]; } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_4 also SCAN_CHANNEL_PARAMS_API_S_VER_5 */ /** * struct iwx_scan_channel_params_v6 * @flags: channel flags &enum iwl_scan_channel_flags * @count: num of channels in scan request * @n_aps_override: override the number of APs the FW uses to calculate dwell * time when adaptive dwell is used. * Channel k will use n_aps_override[i] when BIT(20 + i) is set in * channel_config[k].flags * @channel_config: array of explicit channel configurations * for 2.4Ghz and 5.2Ghz bands */ struct iwx_scan_channel_params_v6 { uint8_t flags; uint8_t count; uint8_t n_aps_override[2]; struct iwx_scan_channel_cfg_umac channel_config[IWX_SCAN_MAX_NUM_CHANS_V3]; } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_6 */ /** * struct iwl_scan_general_params_v10 * @flags: &enum iwl_umac_scan_flags * @reserved: reserved for future * @scan_start_mac_id: report the scan start TSF time according to this mac TSF * @active_dwell: dwell time for active scan per LMAC * @adwell_default_2g: adaptive dwell default number of APs * for 2.4GHz channel * @adwell_default_5g: adaptive dwell default number of APs * for 5GHz channels * @adwell_default_social_chn: adaptive dwell default number of * APs per social channel * @reserved1: reserved for future * @adwell_max_budget: the maximal number of TUs that adaptive dwell * can add to the total scan time * @max_out_of_time: max out of serving channel time, per LMAC * @suspend_time: max suspend time, per LMAC * @scan_priority: priority of the request * @passive_dwell: continues dwell time for passive channel * (without adaptive dwell) * @num_of_fragments: number of fragments needed for full fragmented * scan coverage. */ struct iwx_scan_general_params_v10 { uint16_t flags; uint8_t reserved; uint8_t scan_start_mac_id; uint8_t active_dwell[IWX_SCAN_TWO_LMACS]; uint8_t adwell_default_2g; uint8_t adwell_default_5g; uint8_t adwell_default_social_chn; uint8_t reserved1; uint16_t adwell_max_budget; uint32_t max_out_of_time[IWX_SCAN_TWO_LMACS]; uint32_t suspend_time[IWX_SCAN_TWO_LMACS]; uint32_t scan_priority; uint8_t passive_dwell[IWX_SCAN_TWO_LMACS]; uint8_t num_of_fragments[IWX_SCAN_TWO_LMACS]; } __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_10 */ /** * struct iwx_scan_periodic_parms_v1 * @schedule: can scheduling parameter * @delay: initial delay of the periodic scan in seconds * @reserved: reserved for future */ struct iwx_scan_periodic_parms_v1 { struct iwx_scan_umac_schedule schedule[IWX_MAX_SCHED_SCAN_PLANS]; uint16_t delay; uint16_t reserved; } __packed; /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ /** * struct iwx_scan_req_params_v12 * @general_params: &struct iwl_scan_general_params_v10 * @channel_params: &struct iwl_scan_channel_params_v4 * @periodic_params: &struct iwl_scan_periodic_parms_v1 * @probe_params: &struct iwl_scan_probe_params_v3 */ struct iwx_scan_req_params_v12 { struct iwx_scan_general_params_v10 general_params; struct iwx_scan_channel_params_v4 channel_params; struct iwx_scan_periodic_parms_v1 periodic_params; struct iwx_scan_probe_params_v3 probe_params; } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_12 */ /** * struct iwx_scan_req_params_v14 * @general_params: &struct iwl_scan_general_params_v10 * @channel_params: &struct iwl_scan_channel_params_v6 * @periodic_params: &struct iwl_scan_periodic_parms_v1 * @probe_params: &struct iwl_scan_probe_params_v4 */ struct iwx_scan_req_params_v14 { struct iwx_scan_general_params_v10 general_params; struct iwx_scan_channel_params_v6 channel_params; struct iwx_scan_periodic_parms_v1 periodic_params; struct iwx_scan_probe_params_v4 probe_params; } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_14 */ /** * struct iwx_scan_req_umac_v12 * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @scan_params: scan parameters */ struct iwx_scan_req_umac_v12 { uint32_t uid; uint32_t ooc_priority; struct iwx_scan_req_params_v12 scan_params; } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_12 */ /** * struct iwx_scan_req_umac_v14 * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @scan_params: scan parameters */ struct iwx_scan_req_umac_v14 { uint32_t uid; uint32_t ooc_priority; struct iwx_scan_req_params_v14 scan_params; } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_14 */ /** * struct iwx_umac_scan_abort * @uid: scan id, &enum iwx_umac_scan_uid_offsets * @flags: reserved */ struct iwx_umac_scan_abort { uint32_t uid; uint32_t flags; } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ /** * struct iwx_umac_scan_complete * @uid: scan id, &enum iwx_umac_scan_uid_offsets * @last_schedule: last scheduling line * @last_iter: last scan iteration number * @scan status: &enum iwx_scan_offload_complete_status * @ebs_status: &enum iwx_scan_ebs_status * @time_from_last_iter: time elapsed from last iteration * @reserved: for future use */ struct iwx_umac_scan_complete { uint32_t uid; uint8_t last_schedule; uint8_t last_iter; uint8_t status; uint8_t ebs_status; uint32_t time_from_last_iter; uint32_t reserved; } __packed; /* SCAN_COMPLETE_NTF_UMAC_API_S_VER_1 */ #define IWX_SCAN_OFFLOAD_MATCHING_CHANNELS_LEN 5 /** * struct iwx_scan_offload_profile_match - match information * @bssid: matched bssid * @channel: channel where the match occurred * @energy: * @matching_feature: * @matching_channels: bitmap of channels that matched, referencing * the channels passed in tue scan offload request */ struct iwx_scan_offload_profile_match { uint8_t bssid[ETHER_ADDR_LEN]; uint16_t reserved; uint8_t channel; uint8_t energy; uint8_t matching_feature; uint8_t matching_channels[IWX_SCAN_OFFLOAD_MATCHING_CHANNELS_LEN]; } __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_1 */ /** * struct iwx_scan_offload_profiles_query - match results query response * @matched_profiles: bitmap of matched profiles, referencing the * matches passed in the scan offload request * @last_scan_age: age of the last offloaded scan * @n_scans_done: number of offloaded scans done * @gp2_d0u: GP2 when D0U occurred * @gp2_invoked: GP2 when scan offload was invoked * @resume_while_scanning: not used * @self_recovery: obsolete * @reserved: reserved * @matches: array of match information, one for each match */ struct iwx_scan_offload_profiles_query { uint32_t matched_profiles; uint32_t last_scan_age; uint32_t n_scans_done; uint32_t gp2_d0u; uint32_t gp2_invoked; uint8_t resume_while_scanning; uint8_t self_recovery; uint16_t reserved; struct iwx_scan_offload_profile_match matches[IWX_SCAN_MAX_PROFILES]; } __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */ /** * struct iwx_umac_scan_iter_complete_notif - notifies end of scanning iteration * @uid: scan id, &enum iwx_umac_scan_uid_offsets * @scanned_channels: number of channels scanned and number of valid elements in * results array * @status: one of SCAN_COMP_STATUS_* * @bt_status: BT on/off status * @last_channel: last channel that was scanned * @tsf_low: TSF timer (lower half) in usecs * @tsf_high: TSF timer (higher half) in usecs * @results: array of scan results, only "scanned_channels" of them are valid */ struct iwx_umac_scan_iter_complete_notif { uint32_t uid; uint8_t scanned_channels; uint8_t status; uint8_t bt_status; uint8_t last_channel; uint32_t tsf_low; uint32_t tsf_high; struct iwx_scan_results_notif results[]; } __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_1 */ #define IWX_GSCAN_START_CMD 0x0 #define IWX_GSCAN_STOP_CMD 0x1 #define IWX_GSCAN_SET_HOTLIST_CMD 0x2 #define IWX_GSCAN_RESET_HOTLIST_CMD 0x3 #define IWX_GSCAN_SET_SIGNIFICANT_CHANGE_CMD 0x4 #define IWX_GSCAN_RESET_SIGNIFICANT_CHANGE_CMD 0x5 #define IWX_GSCAN_SIGNIFICANT_CHANGE_EVENT 0xFD #define IWX_GSCAN_HOTLIST_CHANGE_EVENT 0xFE #define IWX_GSCAN_RESULTS_AVAILABLE_EVENT 0xFF /* STA API */ /** * flags for the ADD_STA host command * @IWX_STA_FLG_REDUCED_TX_PWR_CTRL: * @IWX_STA_FLG_REDUCED_TX_PWR_DATA: * @IWX_STA_FLG_DISABLE_TX: set if TX should be disabled * @IWX_STA_FLG_PS: set if STA is in Power Save * @IWX_STA_FLG_INVALID: set if STA is invalid * @IWX_STA_FLG_DLP_EN: Direct Link Protocol is enabled * @IWX_STA_FLG_SET_ALL_KEYS: the current key applies to all key IDs * @IWX_STA_FLG_DRAIN_FLOW: drain flow * @IWX_STA_FLG_PAN: STA is for PAN interface * @IWX_STA_FLG_CLASS_AUTH: * @IWX_STA_FLG_CLASS_ASSOC: * @IWX_STA_FLG_CLASS_MIMO_PROT: * @IWX_STA_FLG_MAX_AGG_SIZE_MSK: maximal size for A-MPDU * @IWX_STA_FLG_AGG_MPDU_DENS_MSK: maximal MPDU density for Tx aggregation * @IWX_STA_FLG_FAT_EN_MSK: support for channel width (for Tx). This flag is * initialised by driver and can be updated by fw upon reception of * action frames that can change the channel width. When cleared the fw * will send all the frames in 20MHz even when FAT channel is requested. * @IWX_STA_FLG_MIMO_EN_MSK: support for MIMO. This flag is initialised by the * driver and can be updated by fw upon reception of action frames. * @IWX_STA_FLG_MFP_EN: Management Frame Protection */ #define IWX_STA_FLG_REDUCED_TX_PWR_CTRL (1 << 3) #define IWX_STA_FLG_REDUCED_TX_PWR_DATA (1 << 6) #define IWX_STA_FLG_DISABLE_TX (1 << 4) #define IWX_STA_FLG_PS (1 << 8) #define IWX_STA_FLG_DRAIN_FLOW (1 << 12) #define IWX_STA_FLG_PAN (1 << 13) #define IWX_STA_FLG_CLASS_AUTH (1 << 14) #define IWX_STA_FLG_CLASS_ASSOC (1 << 15) #define IWX_STA_FLG_RTS_MIMO_PROT (1 << 17) #define IWX_STA_FLG_MAX_AGG_SIZE_SHIFT 19 #define IWX_STA_FLG_MAX_AGG_SIZE_8K (0 << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_MAX_AGG_SIZE_16K (1 << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_MAX_AGG_SIZE_32K (2 << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_MAX_AGG_SIZE_64K (3 << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_MAX_AGG_SIZE_128K (4 << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_MAX_AGG_SIZE_256K (5 << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_MAX_AGG_SIZE_512K (6 << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_MAX_AGG_SIZE_1024K (7 << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_MAX_AGG_SIZE_MSK (0xf << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_MAX_AGG_SIZE_4M (9 << IWX_STA_FLG_MAX_AGG_SIZE_SHIFT) #define IWX_STA_FLG_AGG_MPDU_DENS_SHIFT 23 #define IWX_STA_FLG_AGG_MPDU_DENS_2US (4 << IWX_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWX_STA_FLG_AGG_MPDU_DENS_4US (5 << IWX_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWX_STA_FLG_AGG_MPDU_DENS_8US (6 << IWX_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWX_STA_FLG_AGG_MPDU_DENS_16US (7 << IWX_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWX_STA_FLG_AGG_MPDU_DENS_MSK (7 << IWX_STA_FLG_AGG_MPDU_DENS_SHIFT) #define IWX_STA_FLG_FAT_EN_20MHZ (0 << 26) #define IWX_STA_FLG_FAT_EN_40MHZ (1 << 26) #define IWX_STA_FLG_FAT_EN_80MHZ (2 << 26) #define IWX_STA_FLG_FAT_EN_160MHZ (3 << 26) #define IWX_STA_FLG_FAT_EN_MSK (3 << 26) #define IWX_STA_FLG_MIMO_EN_SISO (0 << 28) #define IWX_STA_FLG_MIMO_EN_MIMO2 (1 << 28) #define IWX_STA_FLG_MIMO_EN_MIMO3 (2 << 28) #define IWX_STA_FLG_MIMO_EN_MSK (3 << 28) /** * key flags for the ADD_STA host command * @IWX_STA_KEY_FLG_NO_ENC: no encryption * @IWX_STA_KEY_FLG_WEP: WEP encryption algorithm * @IWX_STA_KEY_FLG_CCM: CCMP encryption algorithm * @IWX_STA_KEY_FLG_TKIP: TKIP encryption algorithm * @IWX_STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support) * @IWX_STA_KEY_FLG_CMAC: CMAC encryption algorithm * @IWX_STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm * @IWX_STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value * @IWX_STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from * station info array (1 - n 1X mode) * @IWX_STA_KEY_FLG_KEYID_MSK: the index of the key * @IWX_STA_KEY_NOT_VALID: key is invalid * @IWX_STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key * @IWX_STA_KEY_MULTICAST: set for multicast key * @IWX_STA_KEY_MFP: key is used for Management Frame Protection */ #define IWX_STA_KEY_FLG_NO_ENC (0 << 0) #define IWX_STA_KEY_FLG_WEP (1 << 0) #define IWX_STA_KEY_FLG_CCM (2 << 0) #define IWX_STA_KEY_FLG_TKIP (3 << 0) #define IWX_STA_KEY_FLG_EXT (4 << 0) #define IWX_STA_KEY_FLG_CMAC (6 << 0) #define IWX_STA_KEY_FLG_ENC_UNKNOWN (7 << 0) #define IWX_STA_KEY_FLG_EN_MSK (7 << 0) #define IWX_STA_KEY_FLG_WEP_KEY_MAP (1 << 3) #define IWX_STA_KEY_FLG_KEYID_POS 8 #define IWX_STA_KEY_FLG_KEYID_MSK (3 << IWX_STA_KEY_FLG_KEYID_POS) #define IWX_STA_KEY_NOT_VALID (1 << 11) #define IWX_STA_KEY_FLG_WEP_13BYTES (1 << 12) #define IWX_STA_KEY_MULTICAST (1 << 14) #define IWX_STA_KEY_MFP (1 << 15) /** * indicate to the fw what flag are being changed * @IWX_STA_MODIFY_QUEUE_REMOVAL: this command removes a queue * @IWX_STA_MODIFY_TID_DISABLE_TX: this command modifies %tid_disable_tx * @IWX_STA_MODIFY_TX_RATE: unused * @IWX_STA_MODIFY_ADD_BA_TID: this command modifies %add_immediate_ba_tid * @IWX_STA_MODIFY_REMOVE_BA_TID: this command modifies %remove_immediate_ba_tid * @IWX_STA_MODIFY_SLEEPING_STA_TX_COUNT: this command modifies %sleep_tx_count * @IWX_STA_MODIFY_PROT_TH: * @IWX_STA_MODIFY_QUEUES: modify the queues used by this station */ #define IWX_STA_MODIFY_QUEUE_REMOVAL (1 << 0) #define IWX_STA_MODIFY_TID_DISABLE_TX (1 << 1) #define IWX_STA_MODIFY_TX_RATE (1 << 2) #define IWX_STA_MODIFY_ADD_BA_TID (1 << 3) #define IWX_STA_MODIFY_REMOVE_BA_TID (1 << 4) #define IWX_STA_MODIFY_SLEEPING_STA_TX_COUNT (1 << 5) #define IWX_STA_MODIFY_PROT_TH (1 << 6) #define IWX_STA_MODIFY_QUEUES (1 << 7) #define IWX_STA_MODE_MODIFY 1 /** * type of sleep of the station * @IWX_STA_SLEEP_STATE_AWAKE: * @IWX_STA_SLEEP_STATE_PS_POLL: * @IWX_STA_SLEEP_STATE_UAPSD: * @IWX_STA_SLEEP_STATE_MOREDATA: set more-data bit on * (last) released frame */ #define IWX_STA_SLEEP_STATE_AWAKE 0 #define IWX_STA_SLEEP_STATE_PS_POLL (1 << 0) #define IWX_STA_SLEEP_STATE_UAPSD (1 << 1) #define IWX_STA_SLEEP_STATE_MOREDATA (1 << 2) /* STA ID and color bits definitions */ #define IWX_STA_ID_SEED (0x0f) #define IWX_STA_ID_POS (0) #define IWX_STA_ID_MSK (IWX_STA_ID_SEED << IWX_STA_ID_POS) #define IWX_STA_COLOR_SEED (0x7) #define IWX_STA_COLOR_POS (4) #define IWX_STA_COLOR_MSK (IWX_STA_COLOR_SEED << IWX_STA_COLOR_POS) #define IWX_STA_ID_N_COLOR_GET_COLOR(id_n_color) \ (((id_n_color) & IWX_STA_COLOR_MSK) >> IWX_STA_COLOR_POS) #define IWX_STA_ID_N_COLOR_GET_ID(id_n_color) \ (((id_n_color) & IWX_STA_ID_MSK) >> IWX_STA_ID_POS) #define IWX_STA_KEY_MAX_NUM (16) #define IWX_STA_KEY_IDX_INVALID (0xff) #define IWX_STA_KEY_MAX_DATA_KEY_NUM (4) #define IWX_MAX_GLOBAL_KEYS (4) #define IWX_STA_KEY_LEN_WEP40 (5) #define IWX_STA_KEY_LEN_WEP104 (13) /** * struct iwx_keyinfo - key information * @key_flags: type %iwx_sta_key_flag * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx * @key_offset: key offset in the fw's key table * @key: 16-byte unicast decryption key * @tx_secur_seq_cnt: initial RSC / PN needed for replay check * @hw_tkip_mic_rx_key: byte: MIC Rx Key - used for TKIP only * @hw_tkip_mic_tx_key: byte: MIC Tx Key - used for TKIP only */ struct iwx_keyinfo { uint16_t key_flags; uint8_t tkip_rx_tsc_byte2; uint8_t reserved1; uint16_t tkip_rx_ttak[5]; uint8_t key_offset; uint8_t reserved2; uint8_t key[16]; uint64_t tx_secur_seq_cnt; uint64_t hw_tkip_mic_rx_key; uint64_t hw_tkip_mic_tx_key; } __packed; #define IWX_ADD_STA_STATUS_MASK 0xFF #define IWX_ADD_STA_BAID_VALID_MASK 0x8000 #define IWX_ADD_STA_BAID_MASK 0x7F00 #define IWX_ADD_STA_BAID_SHIFT 8 /** * struct iwx_add_sta_cmd - Add/modify a station in the fw's sta table. * ( REPLY_ADD_STA = 0x18 ) * @add_modify: see &enum iwl_sta_mode * @awake_acs: ACs to transmit data on while station is sleeping (for U-APSD) * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to, * see &enum iwl_ctxt_id_and_color * @addr: station's MAC address * @reserved2: reserved * @sta_id: index of station in uCode's station table * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave * alone. 1 - modify, 0 - don't change. * @reserved3: reserved * @station_flags: look at &enum iwl_sta_flags * @station_flags_msk: what of %station_flags have changed, * also &enum iwl_sta_flags * @add_immediate_ba_tid: tid for which to add block-ack support (Rx) * Set %STA_MODIFY_ADD_BA_TID to use this field, and also set * add_immediate_ba_ssn. * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx) * Set %STA_MODIFY_REMOVE_BA_TID to use this field * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with * add_immediate_ba_tid. * @sleep_tx_count: number of packets to transmit to station even though it is * asleep. Used to synchronise PS-poll and u-APSD responses while ucode * keeps track of STA sleep state. * @station_type: type of this station. See &enum iwl_sta_type. * @sleep_state_flags: Look at &enum iwl_sta_sleep_flag. * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP * mac-addr. * @beamform_flags: beam forming controls * @tfd_queue_msk: tfd queues used by this station. * Obselete for new TX API (9 and above). * @rx_ba_window: aggregation window size * @sp_length: the size of the SP in actual number of frames * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver * enabled ACs. * * The device contains an internal table of per-station information, with info * on security keys, aggregation parameters, and Tx rates for initial Tx * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD). * * ADD_STA sets up the table entry for one station, either creating a new * entry, or modifying a pre-existing one. */ struct iwx_add_sta_cmd { uint8_t add_modify; uint8_t awake_acs; uint16_t tid_disable_tx; uint32_t mac_id_n_color; uint8_t addr[ETHER_ADDR_LEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */ uint16_t reserved2; uint8_t sta_id; uint8_t modify_mask; uint16_t reserved3; uint32_t station_flags; uint32_t station_flags_msk; uint8_t add_immediate_ba_tid; uint8_t remove_immediate_ba_tid; uint16_t add_immediate_ba_ssn; uint16_t sleep_tx_count; uint8_t sleep_state_flags; uint8_t station_type; uint16_t assoc_id; uint16_t beamform_flags; uint32_t tfd_queue_msk; uint16_t rx_ba_window; uint8_t sp_length; uint8_t uapsd_acs; } __packed; /* ADD_STA_CMD_API_S_VER_10 */ /** * FW station types * ( REPLY_ADD_STA = 0x18 ) * @IWX_STA_LINK: Link station - normal RX and TX traffic. * @IWX_STA_GENERAL_PURPOSE: General purpose. In AP mode used for beacons * and probe responses. * @IWX_STA_MULTICAST: multicast traffic, * @IWX_STA_TDLS_LINK: TDLS link station * @IWX_STA_AUX_ACTIVITY: auxilary station (scan, ROC and so on). */ #define IWX_STA_LINK 0 #define IWX_STA_GENERAL_PURPOSE 1 #define IWX_STA_MULTICAST 2 #define IWX_STA_TDLS_LINK 3 #define IWX_STA_AUX_ACTIVITY 4 /** * struct iwx_add_sta_key_common - add/modify sta key common part * ( REPLY_ADD_STA_KEY = 0x17 ) * @sta_id: index of station in uCode's station table * @key_offset: key offset in key storage * @key_flags: IWX_STA_KEY_FLG_* * @key: key material data * @rx_secur_seq_cnt: RX security sequence counter for the key */ struct iwx_add_sta_key_common { uint8_t sta_id; uint8_t key_offset; uint16_t key_flags; uint8_t key[32]; uint8_t rx_secur_seq_cnt[16]; } __packed; /** * struct iwx_add_sta_key_cmd_v1 - add/modify sta key * @common: see &struct iwx_add_sta_key_common * @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection * @reserved: reserved * @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx */ struct iwx_add_sta_key_cmd_v1 { struct iwx_add_sta_key_common common; uint8_t tkip_rx_tsc_byte2; uint8_t reserved; uint16_t tkip_rx_ttak[5]; } __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_1 */ /** * struct iwx_add_sta_key_cmd - add/modify sta key * @common: see &struct iwx_add_sta_key_common * @rx_mic_key: TKIP RX unicast or multicast key * @tx_mic_key: TKIP TX key * @transmit_seq_cnt: TSC, transmit packet number */ struct iwx_add_sta_key_cmd { struct iwx_add_sta_key_common common; uint64_t rx_mic_key; uint64_t tx_mic_key; uint64_t transmit_seq_cnt; } __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_2 */ /** * status in the response to ADD_STA command * @IWX_ADD_STA_SUCCESS: operation was executed successfully * @IWX_ADD_STA_STATIONS_OVERLOAD: no room left in the fw's station table * @IWX_ADD_STA_IMMEDIATE_BA_FAILURE: can't add Rx block ack session * @IWX_ADD_STA_MODIFY_NON_EXISTING_STA: driver requested to modify a station * that doesn't exist. */ #define IWX_ADD_STA_SUCCESS 0x1 #define IWX_ADD_STA_STATIONS_OVERLOAD 0x2 #define IWX_ADD_STA_IMMEDIATE_BA_FAILURE 0x4 #define IWX_ADD_STA_MODIFY_NON_EXISTING_STA 0x8 /** * struct iwx_rm_sta_cmd - Add / modify a station in the fw's station table * ( IWX_REMOVE_STA = 0x19 ) * @sta_id: the station id of the station to be removed */ struct iwx_rm_sta_cmd { uint8_t sta_id; uint8_t reserved[3]; } __packed; /* IWX_REMOVE_STA_CMD_API_S_VER_2 */ /** * struct iwx_mgmt_mcast_key_cmd * ( IWX_MGMT_MCAST_KEY = 0x1f ) * @ctrl_flags: %iwx_sta_key_flag * @IGTK: * @K1: IGTK master key * @K2: IGTK sub key * @sta_id: station ID that support IGTK * @key_id: * @receive_seq_cnt: initial RSC/PN needed for replay check */ struct iwx_mgmt_mcast_key_cmd { uint32_t ctrl_flags; uint8_t IGTK[16]; uint8_t K1[16]; uint8_t K2[16]; uint32_t key_id; uint32_t sta_id; uint64_t receive_seq_cnt; } __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */ struct iwx_wep_key { uint8_t key_index; uint8_t key_offset; uint16_t reserved1; uint8_t key_size; uint8_t reserved2[3]; uint8_t key[16]; } __packed; struct iwx_wep_key_cmd { uint32_t mac_id_n_color; uint8_t num_keys; uint8_t decryption_type; uint8_t flags; uint8_t reserved; struct iwx_wep_key wep_key[0]; } __packed; /* SEC_CURR_WEP_KEY_CMD_API_S_VER_2 */ /* * BT coex */ #define IWX_BT_COEX_DISABLE 0x0 #define IWX_BT_COEX_NW 0x1 #define IWX_BT_COEX_BT 0x2 #define IWX_BT_COEX_WIFI 0x3 /* BT_COEX_MODES_E */ #define IWX_BT_COEX_MPLUT_ENABLED (1 << 0) #define IWX_BT_COEX_MPLUT_BOOST_ENABLED (1 << 1) #define IWX_BT_COEX_SYNC2SCO_ENABLED (1 << 2) #define IWX_BT_COEX_CORUN_ENABLED (1 << 3) #define IWX_BT_COEX_HIGH_BAND_RET (1 << 4) /* BT_COEX_MODULES_ENABLE_E_VER_1 */ /** * struct iwx_bt_coex_cmd - bt coex configuration command * @mode: enum %iwx_bt_coex_mode * @enabled_modules: enum %iwx_bt_coex_enabled_modules * * The structure is used for the BT_COEX command. */ struct iwx_bt_coex_cmd { uint32_t mode; uint32_t enabled_modules; } __packed; /* BT_COEX_CMD_API_S_VER_6 */ /* * Location Aware Regulatory (LAR) API - MCC updates */ /** * struct iwx_mcc_update_cmd - Request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the * MCC in the cmd response will be the relevant MCC in the NVM. * @mcc: given mobile country code * @source_id: the source from where we got the MCC, see IWX_MCC_SOURCE_* * @reserved: reserved for alignment * @key: integrity key for MCC API OEM testing * @reserved2: reserved */ struct iwx_mcc_update_cmd { uint16_t mcc; uint8_t source_id; uint8_t reserved; uint32_t key; uint32_t reserved2[5]; } __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */ /** * iwx_mcc_update_resp_v3 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. * @status: see &enum iwx_mcc_update_status * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC * @source_id: the MCC source, see IWX_MCC_SOURCE_* * @time: time elapsed from the MCC test start (in 30 seconds TU) * @reserved: reserved. * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 * channels, depending on platform) * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ struct iwx_mcc_update_resp_v3 { uint32_t status; uint16_t mcc; uint8_t cap; uint8_t source_id; uint16_t time; uint16_t geo_info; uint32_t n_channels; uint32_t channels[0]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ /** * geographic information. * @GEO_NO_INFO: no special info for this geo profile. * @GEO_WMM_ETSI_5GHZ_INFO: this geo profile limits the WMM params * for the 5 GHz band. */ #define IWX_GEO_NO_INFO 0 #define IWX_GEO_WMM_ETSI_5GHZ_INFO (1 << 0) /** * struct iwx_mcc_update_resp - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. * @status: see &enum iwl_mcc_update_status * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC * @time: time elapsed from the MCC test start (in units of 30 seconds) * @geo_info: geographic specific profile information * see IWX_GEO_* * @source_id: the MCC source, see IWX_MCC_SOURCE_* * @reserved: for four bytes alignment. * @n_channels: number of channels in @channels_data. * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ struct iwx_mcc_update_resp { uint32_t status; uint16_t mcc; uint16_t cap; uint16_t time; uint16_t geo_info; uint8_t source_id; uint8_t reserved[3]; uint32_t n_channels; uint32_t channels[0]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_4 */ /** * struct iwx_mcc_chub_notif - chub notifies of mcc change * (MCC_CHUB_UPDATE_CMD = 0xc9) * The Chub (Communication Hub, CommsHUB) is a HW component that connects to * the cellular and connectivity cores that gets updates of the mcc, and * notifies the ucode directly of any mcc change. * The ucode requests the driver to request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the * MCC in the cmd response will be the relevant MCC in the NVM. * @mcc: given mobile country code * @source_id: identity of the change originator, see IWX_MCC_SOURCE_* * @reserved1: reserved for alignment */ struct iwx_mcc_chub_notif { uint16_t mcc; uint8_t source_id; uint8_t reserved1; } __packed; /* LAR_MCC_NOTIFY_S */ enum iwx_mcc_update_status { IWX_MCC_RESP_NEW_CHAN_PROFILE, IWX_MCC_RESP_SAME_CHAN_PROFILE, IWX_MCC_RESP_INVALID, IWX_MCC_RESP_NVM_DISABLED, IWX_MCC_RESP_ILLEGAL, IWX_MCC_RESP_LOW_PRIORITY, IWX_MCC_RESP_TEST_MODE_ACTIVE, IWX_MCC_RESP_TEST_MODE_NOT_ACTIVE, IWX_MCC_RESP_TEST_MODE_DENIAL_OF_SERVICE, }; #define IWX_MCC_SOURCE_OLD_FW 0 #define IWX_MCC_SOURCE_ME 1 #define IWX_MCC_SOURCE_BIOS 2 #define IWX_MCC_SOURCE_3G_LTE_HOST 3 #define IWX_MCC_SOURCE_3G_LTE_DEVICE 4 #define IWX_MCC_SOURCE_WIFI 5 #define IWX_MCC_SOURCE_RESERVED 6 #define IWX_MCC_SOURCE_DEFAULT 7 #define IWX_MCC_SOURCE_UNINITIALIZED 8 #define IWX_MCC_SOURCE_MCC_API 9 #define IWX_MCC_SOURCE_GET_CURRENT 0x10 #define IWX_MCC_SOURCE_GETTING_MCC_TEST_MODE 0x11 /* * From Linux commit ab02165ccec4c78162501acedeef1a768acdb811: * As the firmware is slowly running out of command IDs and grouping of * commands is desirable anyway, the firmware is extending the command * header from 4 bytes to 8 bytes to introduce a group (in place of the * former flags field, since that's always 0 on commands and thus can * be easily used to distinguish between the two). * * These functions retrieve specific information from the id field in * the iwx_host_cmd struct which contains the command id, the group id, * and the version of the command. */ static inline uint8_t iwx_cmd_opcode(uint32_t cmdid) { return cmdid & 0xff; } static inline uint8_t iwx_cmd_groupid(uint32_t cmdid) { return ((cmdid & 0Xff00) >> 8); } static inline uint8_t iwx_cmd_version(uint32_t cmdid) { return ((cmdid & 0xff0000) >> 16); } static inline uint32_t iwx_cmd_id(uint8_t opcode, uint8_t groupid, uint8_t version) { return opcode + (groupid << 8) + (version << 16); } /* make uint16_t wide id out of uint8_t group and opcode */ #define IWX_WIDE_ID(grp, opcode) ((grp << 8) | opcode) struct iwx_cmd_header { uint8_t cmd; uint8_t group_id; uint8_t idx; uint8_t qid; } __packed; struct iwx_cmd_header_wide { uint8_t cmd; uint8_t group_id; uint8_t idx; uint8_t qid; uint16_t length; uint8_t reserved; uint8_t version; } __packed; #define IWX_POWER_SCHEME_CAM 1 #define IWX_POWER_SCHEME_BPS 2 #define IWX_POWER_SCHEME_LP 3 #define IWX_DEF_CMD_PAYLOAD_SIZE 320 #define IWX_MAX_CMD_PAYLOAD_SIZE ((4096 - 4) - sizeof(struct iwx_cmd_header)) #define IWX_CMD_FAILED_MSK 0x40 /** * struct iwx_device_cmd * * For allocation of the command and tx queues, this establishes the overall * size of the largest command we send to uCode, except for commands that * aren't fully copied and use other TFD space. */ struct iwx_device_cmd { union { struct { struct iwx_cmd_header hdr; uint8_t data[IWX_DEF_CMD_PAYLOAD_SIZE]; }; struct { struct iwx_cmd_header_wide hdr_wide; uint8_t data_wide[IWX_DEF_CMD_PAYLOAD_SIZE - sizeof(struct iwx_cmd_header_wide) + sizeof(struct iwx_cmd_header)]; }; }; } __packed; struct iwx_rx_packet { /* * The first 4 bytes of the RX frame header contain both the RX frame * size and some flags. * Bit fields: * 31: flag flush RB request * 30: flag ignore TC (terminal counter) request * 29: flag fast IRQ request * 28-26: Reserved * 25: Offload enabled * 24: RPF enabled * 23: RSS enabled * 22: Checksum enabled * 21-16: RX queue * 15-14: Reserved * 13-00: RX frame size */ uint32_t len_n_flags; struct iwx_cmd_header hdr; uint8_t data[]; } __packed; #define IWX_FH_RSCSR_FRAME_SIZE_MSK 0x00003fff #define IWX_FH_RSCSR_FRAME_INVALID 0x55550000 #define IWX_FH_RSCSR_FRAME_ALIGN 0x40 #define IWX_FH_RSCSR_RPA_EN (1 << 25) #define IWX_FH_RSCSR_RADA_EN (1 << 26) #define IWX_FH_RSCSR_RXQ_POS 16 #define IWX_FH_RSCSR_RXQ_MASK 0x3F0000 static uint32_t iwx_rx_packet_len(const struct iwx_rx_packet *pkt) { return le32toh(pkt->len_n_flags) & IWX_FH_RSCSR_FRAME_SIZE_MSK; } static uint32_t iwx_rx_packet_payload_len(const struct iwx_rx_packet *pkt) { return iwx_rx_packet_len(pkt) - sizeof(pkt->hdr); } #define IWX_MIN_DBM -100 #define IWX_MAX_DBM -33 /* realistic guess */ #define IWX_READ(sc, reg) \ bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg)) #define IWX_WRITE(sc, reg, val) \ bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val)) #define IWX_WRITE64(sc, reg, val) \ do { \ IWX_WRITE((sc), (uint32_t)(reg), (val) & 0xffffffff); \ IWX_WRITE((sc), (uint32_t)(reg) + 4, (val) >> 32); \ } while(0) #define IWX_WRITE_1(sc, reg, val) \ bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val)) #define IWX_SETBITS(sc, reg, mask) \ IWX_WRITE(sc, reg, IWX_READ(sc, reg) & ~(mask) | (mask)) #define IWX_CLRBITS(sc, reg, mask) \ IWX_WRITE(sc, reg, IWX_READ(sc, reg) & ~(mask) | 0) #define IWX_BARRIER_WRITE(sc) \ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ BUS_SPACE_BARRIER_WRITE) #define IWX_BARRIER_READ_WRITE(sc) \ bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) ================================================ FILE: itlwm/hal_iwx/if_iwxvar.h ================================================ /* * 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. */ /* $OpenBSD: if_iwxvar.h,v 1.13 2020/10/11 07:05:28 mpi Exp $ */ /* * Copyright (c) 2014 genua mbh * Copyright (c) 2014 Fixup Software Ltd. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, * which were used as the reference documentation for this implementation. * ****************************************************************************** * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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. * * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ***************************************************************************** */ /*- * Copyright (c) 2007-2010 Damien Bergamini * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #define IWL_CFG_ANY (~0) #define IWL_CFG_MAC_TYPE_PU 0x31 #define IWL_CFG_MAC_TYPE_PNJ 0x32 #define IWL_CFG_MAC_TYPE_TH 0x32 #define IWL_CFG_MAC_TYPE_QU 0x33 #define IWL_CFG_MAC_TYPE_QUZ 0x35 #define IWL_CFG_MAC_TYPE_QNJ 0x36 #define IWL_CFG_MAC_TYPE_SO 0x37 #define IWL_CFG_MAC_TYPE_SNJ 0x42 #define IWL_CFG_MAC_TYPE_SOF 0x43 #define IWL_CFG_MAC_TYPE_MA 0x44 #define IWL_CFG_MAC_TYPE_BZ 0x46 #define IWL_CFG_RF_TYPE_TH 0x105 #define IWL_CFG_RF_TYPE_TH1 0x108 #define IWL_CFG_RF_TYPE_JF2 0x105 #define IWL_CFG_RF_TYPE_JF1 0x108 #define IWL_CFG_RF_TYPE_HR2 0x10A #define IWL_CFG_RF_TYPE_HR1 0x10C #define IWL_CFG_RF_TYPE_GF 0x10D #define IWL_CFG_RF_TYPE_MR 0x110 #define IWL_CFG_RF_TYPE_FM 0x112 #define IWL_CFG_RF_ID_TH 0x1 #define IWL_CFG_RF_ID_TH1 0x1 #define IWL_CFG_RF_ID_JF 0x3 #define IWL_CFG_RF_ID_JF1 0x6 #define IWL_CFG_RF_ID_JF1_DIV 0xA #define IWL_CFG_RF_ID_HR 0x7 #define IWL_CFG_RF_ID_HR1 0x4 #define IWL_CFG_NO_160 0x1 #define IWL_CFG_160 0x0 #define IWL_CFG_CORES_BT 0x0 #define IWL_CFG_CORES_BT_GNSS 0x5 #define IWL_CFG_NO_CDB 0x0 #define IWL_CFG_CDB 0x1 #define IWL_SUBDEVICE_RF_ID(subdevice) ((u16)((subdevice) & 0x00F0) >> 4) #define IWL_SUBDEVICE_NO_160(subdevice) ((u16)((subdevice) & 0x0200) >> 9) #define IWL_SUBDEVICE_CORES(subdevice) ((u16)((subdevice) & 0x1C00) >> 10) /* HW REV */ #define CSR_HW_REV_TYPE(_val) (((_val) & 0x000FFF0) >> 4) /* HW RFID */ #define CSR_HW_RFID_FLAVOR(_val) (((_val) & 0x000000F) >> 0) #define CSR_HW_RFID_DASH(_val) (((_val) & 0x00000F0) >> 4) #define CSR_HW_RFID_STEP(_val) (((_val) & 0x0000F00) >> 8) #define CSR_HW_RFID_TYPE(_val) (((_val) & 0x0FFF000) >> 12) #define CSR_HW_RFID_IS_CDB(_val) (((_val) & 0x10000000) >> 28) #define CSR_HW_RFID_IS_JACKET(_val) (((_val) & 0x20000000) >> 29) #define CSR_HW_REV_TYPE_MSK (0x000FFF0) #define CSR_HW_REV_TYPE_NONE (0x00001F0) #define CSR_HW_REV_TYPE_QNJ (0x0000360) #define CSR_HW_REV_TYPE_QNJ_B0 (0x0000364) #define CSR_HW_REV_TYPE_QU_B0 (0x0000334) #define CSR_HW_REV_TYPE_QU_C0 (0x0000338) #define CSR_HW_REV_TYPE_QUZ (0x0000354) #define CSR_HW_REV_TYPE_HR_CDB (0x0000340) #define CSR_HW_REV_TYPE_SO (0x0000370) #define CSR_HW_REV_TYPE_TY (0x0000420) /* RF_ID value */ #define CSR_HW_RF_ID_TYPE_JF (0x00105100) #define CSR_HW_RF_ID_TYPE_HR (0x0010A000) #define CSR_HW_RF_ID_TYPE_HR1 (0x0010c100) #define CSR_HW_RF_ID_TYPE_HRCDB (0x00109F00) #define CSR_HW_RF_ID_TYPE_GF (0x0010D000) #define CSR_HW_RF_ID_TYPE_GF4 (0x0010E000) /* HW_RF CHIP ID */ #define CSR_HW_RF_ID_TYPE_CHIP_ID(_val) (((_val) >> 12) & 0xFFF) /* HW_RF CHIP STEP */ #define CSR_HW_RF_STEP(_val) (((_val) >> 8) & 0xF) struct iwx_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; uint64_t wr_tsft; uint8_t wr_flags; uint8_t wr_rate; uint16_t wr_chan_freq; uint16_t wr_chan_flags; int8_t wr_dbm_antsignal; int8_t wr_dbm_antnoise; } __packed; #define IWX_RX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_TSFT) | \ (1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL) | \ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)) struct iwx_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; uint8_t wt_flags; uint8_t wt_rate; uint16_t wt_chan_freq; uint16_t wt_chan_flags; } __packed; #define IWX_TX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL)) #define IWX_UCODE_SECT_MAX 60 /* * fw_status is used to determine if we've already parsed the firmware file * * In addition to the following, status < 0 ==> -error */ #define IWX_FW_STATUS_NONE 0 #define IWX_FW_STATUS_INPROGRESS 1 #define IWX_FW_STATUS_DONE 2 enum iwx_ucode_type { IWX_UCODE_TYPE_REGULAR, IWX_UCODE_TYPE_INIT, IWX_UCODE_TYPE_WOW, IWX_UCODE_TYPE_REGULAR_USNIFFER, IWX_UCODE_TYPE_MAX }; struct iwx_fw_onesect { void *fws_data; uint32_t fws_len; uint32_t fws_devoff; }; struct iwx_fw_sects { struct iwx_fw_onesect fw_sect[IWX_UCODE_SECT_MAX]; size_t fw_totlen; int fw_count; }; struct iwx_fw_info { void *fw_rawdata; size_t fw_rawsize; void *pnvm_rawdata; size_t pnvm_rawsize; int fw_status; struct iwx_fw_sects fw_sects[IWX_UCODE_TYPE_MAX]; /* FW debug data parsed for driver usage */ int dbg_dest_tlv_init; uint8_t *dbg_dest_ver; uint8_t n_dest_reg; struct iwx_fw_dbg_dest_tlv_v1 *dbg_dest_tlv_v1; struct iwx_fw_dbg_conf_tlv *dbg_conf_tlv[IWX_FW_DBG_CONF_MAX]; size_t dbg_conf_tlv_len[IWX_FW_DBG_CONF_MAX]; struct iwx_fw_dbg_trigger_tlv *dbg_trigger_tlv[IWX_FW_DBG_TRIGGER_MAX]; size_t dbg_trigger_tlv_len[IWX_FW_DBG_TRIGGER_MAX]; struct iwx_fw_dbg_mem_seg_tlv *dbg_mem_tlv; size_t n_mem_tlv; }; struct iwx_nvm_data { int n_hw_addrs; uint8_t hw_addr[ETHER_ADDR_LEN]; int sku_cap_band_24GHz_enable; int sku_cap_band_52GHz_enable; int sku_cap_11n_enable; int sku_cap_11ac_enable; int sku_cap_11ax_enable; int sku_cap_amt_enable; int sku_cap_ipan_enable; int sku_cap_mimo_disable; int lar_enabled; bool vht160_supported; uint8_t valid_tx_ant, valid_rx_ant; uint16_t nvm_version; }; /* max bufs per tfd the driver will use */ #define IWX_MAX_CMD_TBS_PER_TFD 2 struct iwx_host_cmd { const void *data[IWX_MAX_CMD_TBS_PER_TFD]; struct iwx_rx_packet *resp_pkt; size_t resp_pkt_len; unsigned long _rx_page_addr; uint32_t _rx_page_order; int handler_status; uint32_t flags; uint16_t len[IWX_MAX_CMD_TBS_PER_TFD]; uint8_t dataflags[IWX_MAX_CMD_TBS_PER_TFD]; uint32_t id; }; /* * DMA glue is from iwn */ struct iwx_dma_info { IOBufferMemoryDescriptor* buffer; bus_addr_t paddr; void *vaddr; bus_size_t size; IOBufferMemoryDescriptor *bmd; IODMACommand *cmd; }; struct iwx_tx_data { bus_dmamap_t map; bus_addr_t cmd_paddr; mbuf_t m; struct iwx_node *in; int flags; #define IWX_TXDATA_FLAG_CMD_IS_NARROW 0x01 uint8_t type; }; struct iwx_tx_ring { struct iwx_dma_info desc_dma; struct iwx_dma_info cmd_dma; struct iwx_dma_info bc_tbl; struct iwx_tfh_tfd *desc; struct iwx_device_cmd *cmd; struct iwx_tx_data data[IWX_MIN_256_BA_QUEUE_SIZE_GEN3]; unsigned int ring_count; unsigned int hi_mark; unsigned int low_mark; int qid; int queued; int cur; int tail; }; #define IWX_RX_MQ_RING_COUNT 512 /* Linux driver optionally uses 8k buffer */ #define IWX_RBUF_SIZE 4096 struct iwx_rx_data { mbuf_t m; bus_dmamap_t map; }; struct iwx_rx_ring { struct iwx_dma_info free_desc_dma; struct iwx_dma_info stat_dma; struct iwx_dma_info used_desc_dma; void *desc; void *stat; struct iwx_rx_data data[IWX_RX_MQ_RING_COUNT]; int cur; }; #define IWX_FLAG_USE_ICT 0x01 /* using Interrupt Cause Table */ #define IWX_FLAG_RFKILL 0x02 /* radio kill switch is set */ #define IWX_FLAG_SCANNING 0x04 /* scan in progress */ #define IWX_FLAG_MAC_ACTIVE 0x08 /* MAC context added to firmware */ #define IWX_FLAG_BINDING_ACTIVE 0x10 /* MAC->PHY binding added to firmware */ #define IWX_FLAG_STA_ACTIVE 0x20 /* AP added to firmware station table */ #define IWX_FLAG_TE_ACTIVE 0x40 /* time event is scheduled */ #define IWX_FLAG_HW_ERR 0x80 /* hardware error occurred */ #define IWX_FLAG_SHUTDOWN 0x100 /* shutting down; new tasks forbidden */ #define IWX_FLAG_BGSCAN 0x200 /* background scan in progress */ #define IWX_FLAG_TXFLUSH 0x400 /* Tx queue flushing in progress */ struct iwx_ucode_status { uint32_t uc_lmac_error_event_table[2]; uint32_t uc_umac_error_event_table; uint32_t uc_log_event_table; unsigned int error_event_table_tlv_status; int uc_ok; int uc_intr; }; #define IWX_ERROR_EVENT_TABLE_LMAC1 (1 << 0) #define IWX_ERROR_EVENT_TABLE_LMAC2 (1 << 1) #define IWX_ERROR_EVENT_TABLE_UMAC (1 << 2) #define IWX_CMD_RESP_MAX PAGE_SIZE /* lower blocks contain EEPROM image and calibration data */ #define IWX_OTP_LOW_IMAGE_SIZE_FAMILY_7000 16384 #define IWX_OTP_LOW_IMAGE_SIZE_FAMILY_8000 32768 #define IWX_TE_SESSION_PROTECTION_MAX_TIME_MS 1000 #define IWX_TE_SESSION_PROTECTION_MIN_TIME_MS 400 enum IWX_CMD_MODE { IWX_CMD_ASYNC = (1 << 0), IWX_CMD_WANT_RESP = (1 << 1), IWX_CMD_SEND_IN_RFKILL = (1 << 2), }; enum iwx_hcmd_dataflag { IWX_HCMD_DFL_NOCOPY = (1 << 0), IWX_HCMD_DFL_DUP = (1 << 1), }; #define IWX_NUM_PAPD_CH_GROUPS 9 #define IWX_NUM_TXP_CH_GROUPS 9 struct iwx_phy_ctxt { uint16_t id; uint16_t color; uint32_t ref; struct ieee80211_channel *channel; }; struct iwx_bf_data { int bf_enabled; /* filtering */ int ba_enabled; /* abort */ int ave_beacon_signal; int last_cqm_event; }; /** * struct iwx_self_init_dram - dram data used by self init process * @fw: lmac and umac dram data * @lmac_cnt: number of lmac sections in fw image * @umac_cnt: number of umac sections in fw image * @paging: paging dram data * @paging_cnt: number of paging sections needed by fw image */ struct iwx_self_init_dram { struct iwx_dma_info *fw; int lmac_cnt; int umac_cnt; struct iwx_dma_info *paging; int paging_cnt; }; #define IWX_MAX_TID_COUNT 8 #define IWX_INVALID_QUEUE 0xFFFF struct iwx_tid_data { uint16_t seq_number; uint16_t next_reclaimed; uint16_t qid; uint16_t ssn; }; #define INFSLP UINT64_MAX #ifdef DELAY #undef DELAY #define DELAY IODelay #endif struct iwl_cfg_trans_params { int integrated; int device_family; int low_latency_xtal; int ltr_delay; int xtal_latency; int bisr_workaround; }; struct iwl_cfg { struct iwl_cfg_trans_params trans; const char *name; const char *fwname; int device_family; int tx_with_siso_diversity; int uhb_supported; uint8_t max_tx_agg_size; uint16_t num_rbds; }; /** * struct iwx_reorder_buffer - per ra/tid/queue reorder buffer * @head_sn: reorder window head sn * @num_stored: number of mpdus stored in the buffer * @buf_size: the reorder buffer size as set by the last addba request * @queue: queue of this reorder buffer * @last_amsdu: track last ASMDU SN for duplication detection * @last_sub_index: track ASMDU sub frame index for duplication detection * @reorder_timer: timer for frames are in the reorder buffer. For AMSDU * it is the time of last received sub-frame * @removed: prevent timer re-arming * @valid: reordering is valid for this queue * @consec_oldsn_drops: consecutive drops due to old SN * @consec_oldsn_ampdu_gp2: A-MPDU GP2 timestamp to track * when to apply old SN consecutive drop workaround * @consec_oldsn_prev_drop: track whether or not an MPDU * that was single/part of the previous A-MPDU was * dropped due to old SN */ struct iwx_reorder_buffer { uint16_t head_sn; uint16_t num_stored; uint16_t buf_size; uint16_t last_amsdu; uint8_t last_sub_index; CTimeout *reorder_timer; int removed; int valid; unsigned int consec_oldsn_drops; uint32_t consec_oldsn_ampdu_gp2; unsigned int consec_oldsn_prev_drop; #define IWX_AMPDU_CONSEC_DROPS_DELBA 20 }; /** * struct iwx_reorder_buf_entry - reorder buffer entry per frame sequence number * @frames: list of mbufs stored (A-MSDU subframes share a sequence number) * @reorder_time: time the packet was stored in the reorder buffer */ struct iwx_reorder_buf_entry { struct mbuf_list frames; struct timeval reorder_time; uint32_t rx_pkt_status; int chanidx; int is_shortpre; uint32_t rate_n_flags; uint32_t device_timestamp; struct ieee80211_rxinfo rxi; }; /** * struct iwx_rxba_data - BA session data * @sta_id: station id * @tid: tid of the session * @baid: baid of the session * @timeout: the timeout set in the addba request * @entries_per_queue: # of buffers per queue * @last_rx: last rx timestamp, updated only if timeout passed from last update * @session_timer: timer to check if BA session expired, runs at 2 * timeout * @sc: softc pointer, needed for timer context * @reorder_buf: reorder buffer * @reorder_buf_data: buffered frames, one entry per sequence number */ struct iwx_rxba_data { uint8_t sta_id; uint8_t tid; uint8_t baid; uint16_t timeout; uint16_t entries_per_queue; struct timeval last_rx; CTimeout *session_timer; struct iwx_softc *sc; struct iwx_reorder_buffer reorder_buf; struct iwx_reorder_buf_entry entries[IEEE80211_BA_MAX_WINSZ]; }; static inline struct iwx_rxba_data * iwx_rxba_data_from_reorder_buf(struct iwx_reorder_buffer *buf) { return (struct iwx_rxba_data *)((uint8_t *)buf - offsetof(struct iwx_rxba_data, reorder_buf)); } /** * struct iwx_rxq_dup_data - per station per rx queue data * @last_seq: last sequence per tid for duplicate packet detection * @last_sub_frame: last subframe packet */ struct iwx_rxq_dup_data { uint16_t last_seq[IWX_MAX_TID_COUNT + 1]; uint8_t last_sub_frame[IWX_MAX_TID_COUNT + 1]; }; struct iwx_ba_task_data { uint32_t start_tidmask; uint32_t stop_tidmask; }; struct iwx_softc { struct device sc_dev; struct ieee80211com sc_ic; int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int); int sc_newstate_pending; pci_intr_handle_t ih; struct task init_task; /* NB: not reference-counted */ // struct refcnt task_refs; struct task newstate_task; enum ieee80211_state ns_nstate; int ns_arg; /* Task for firmware BlockAck setup/teardown and its arguments. */ struct task ba_task; struct iwx_ba_task_data ba_rx; struct iwx_ba_task_data ba_tx; struct iwx_tid_data sc_tid_data[IWX_MAX_TID_COUNT + 1];//per tid data + mgmt. Look at %iwx_tid_data. /* Task for ERP/HT prot/slot-time/EDCA updates. */ struct task mac_ctxt_task; struct task chan_ctxt_task; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; bus_size_t sc_sz; bus_dma_tag_t sc_dmat; pci_chipset_tag_t sc_pct; pcitag_t sc_pcitag; IOInterruptEventSource *sc_ih; int sc_msix; /* TX/RX rings. */ struct iwx_tx_ring txq[IWX_MAX_TVQM_QUEUES]; struct iwx_rx_ring rxq; int qfullmsk; struct iwx_tx_ring sc_tvqm_ring; int first_data_qid; int sc_sf_state; /* ICT table. */ struct iwx_dma_info ict_dma; int ict_cur; uint32_t sku_id[3]; int sc_hw_rev; #define IWX_SILICON_A_STEP 0 #define IWX_SILICON_B_STEP 1 #define IWX_SILICON_C_STEP 2 #define IWX_SILICON_D_STEP 3 int sc_hw_rf_id; int sc_hw_id; const struct iwl_cfg_trans_params *sc_cfg_params; const struct iwl_cfg *sc_cfg; int sc_device_family; #define IWX_DEVICE_FAMILY_22000 1 #define IWX_DEVICE_FAMILY_AX210 2 struct iwx_dma_info ctxt_info_dma; struct iwx_self_init_dram init_dram; /* For gen3 */ struct iwx_dma_info prph_scratch_dma; struct iwx_dma_info prph_info_dma; struct iwx_dma_info iml_dma; struct iwx_dma_info pnvm_dram; int sc_fw_chunk_done; int sc_init_complete; #define IWX_INIT_COMPLETE 0x01 #define IWX_CALIB_COMPLETE 0x02 struct iwx_ucode_status sc_uc; char sc_fwver[32]; int sc_capaflags; int sc_capa_max_probe_len; int sc_capa_n_scan_channels; int sc_capa_num_stations; uint8_t sc_ucode_api[howmany(IWX_NUM_UCODE_TLV_API, NBBY)]; uint8_t sc_enabled_capa[howmany(IWX_NUM_UCODE_TLV_CAPA, NBBY)]; #define IWX_MAX_FW_CMD_VERSIONS 800 struct iwx_fw_cmd_version cmd_versions[IWX_MAX_FW_CMD_VERSIONS]; int n_cmd_versions; char sc_fw_mcc[3]; uint16_t sc_fw_mcc_int; #define IWX_IML_MAX_LEN 2048*10 uint32_t sc_iml_len; uint8_t sc_iml[IWX_IML_MAX_LEN]; int sc_intmask; int sc_flags; uint32_t sc_fh_init_mask; uint32_t sc_hw_init_mask; uint32_t sc_fh_mask; uint32_t sc_hw_mask; int sc_generation; // struct rwlock ioctl_rwl; int sc_cap_off; /* PCIe caps */ const char *sc_fwname; struct iwx_fw_info sc_fw; struct iwx_dma_info fw_mon; int sc_fw_phy_config; struct iwx_tlv_calib_ctrl sc_default_calib[IWX_UCODE_TYPE_MAX]; struct iwx_nvm_data sc_nvm; struct iwx_bf_data sc_bf; int sc_tx_timer; int sc_rx_ba_sessions; int sc_scan_last_antenna; int sc_fixed_ridx; uint8_t sc_mgmt_last_antenna_idx; /* for MGMT frames using*/ int sc_staid; int sc_nodecolor; uint8_t *sc_cmd_resp_pkt[IWX_TFD_QUEUE_SIZE_MAX_GEN3]; size_t sc_cmd_resp_len[IWX_TFD_QUEUE_SIZE_MAX_GEN3]; int sc_nic_locks; struct taskq *sc_nswq; struct iwx_rx_phy_info sc_last_phy_info; int sc_ampdu_ref; #define IWX_MAX_BAID 32 struct iwx_rxba_data sc_rxba_data[IWX_MAX_BAID]; uint32_t sc_time_event_uid; /* phy contexts. we only use the first one */ struct iwx_phy_ctxt sc_phyctxt[IWX_NUM_PHY_CTX]; int sc_noise; int sc_pm_support; int sc_ltr_enabled; int sc_integrated; int sc_tx_with_siso_diversity; int sc_max_tfd_queue_size; int sc_ltr_delay; int sc_xtal_latency; int sc_low_latency_xtal; int sc_uhb_supported; #if NBPFILTER > 0 caddr_t sc_drvbpf; union { struct iwx_rx_radiotap_header th; uint8_t pad[IEEE80211_RADIOTAP_HDRLEN]; } sc_rxtapu; #define sc_rxtap sc_rxtapu.th int sc_rxtap_len; union { struct iwx_tx_radiotap_header th; uint8_t pad[IEEE80211_RADIOTAP_HDRLEN]; } sc_txtapu; #define sc_txtap sc_txtapu.th int sc_txtap_len; #endif }; struct iwx_node { struct ieee80211_node in_ni; struct iwx_phy_ctxt *in_phyctxt; uint8_t in_macaddr[ETHER_ADDR_LEN]; uint16_t in_id; uint16_t in_color; struct iwx_rxq_dup_data dup_data; }; #define IWX_STATION_ID 0 #define IWX_AUX_STA_ID 1 #define IWX_MONITOR_STA_ID 2 #define IWX_ICT_SIZE 4096 #define IWX_ICT_COUNT (IWX_ICT_SIZE / sizeof (uint32_t)) #define IWX_ICT_PADDR_SHIFT 12 ================================================ FILE: itlwm/itlwm.cpp ================================================ /* * 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 "itlwm.hpp" #include #include #include #include #include #include #include #include #include #define super IOEthernetController OSDefineMetaClassAndStructors(itlwm, IOEthernetController) OSDefineMetaClassAndStructors(CTimeout, OSObject) IOWorkLoop *_fWorkloop; IOCommandGate *_fCommandGate; bool itlwm::init(OSDictionary *properties) { return super::init(properties); } #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); } IOService* itlwm::probe(IOService *provider, SInt32 *score) { bool isMatch = false; 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 itlwm::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; } struct _ifnet *itlwm::getIfp() { return &fHalService->get80211Controller()->ic_ac.ac_if; } IOEthernetInterface *itlwm::getNetworkInterface() { return getIfp()->iface; } bool itlwm::createMediumTables(const IONetworkMedium **primary) { IONetworkMedium *medium; OSDictionary *mediumDict = OSDictionary::withCapacity(1); if (mediumDict == NULL) { XYLog("Cannot allocate OSDictionary\n"); return false; } medium = IONetworkMedium::medium(kIOMediumEthernetAuto, 100 * 1000000); 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; } void itlwm::joinSSID(const char *ssid_name, const char *ssid_pwd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (strlen(ssid_pwd) == 0) { memset(&nwkey, 0, sizeof(ieee80211_nwkey)); nwkey.i_wepon = IEEE80211_NWKEY_OPEN; nwkey.i_defkid = 0; memcpy(join.i_nwid, ssid_name, strlen(ssid_name)); join.i_len = strlen(ssid_name); join.i_flags = IEEE80211_JOIN_NWKEY; } else { memset(&wpa, 0, sizeof(ieee80211_wpaparams)); wpa.i_enabled = 1; wpa.i_ciphers = 0; wpa.i_groupcipher = 0; wpa.i_protos = IEEE80211_WPA_PROTO_WPA1 | IEEE80211_WPA_PROTO_WPA2; wpa.i_akms = IEEE80211_WPA_AKM_PSK | IEEE80211_WPA_AKM_8021X | IEEE80211_WPA_AKM_SHA256_PSK | IEEE80211_WPA_AKM_SHA256_8021X; memcpy(wpa.i_name, "zxy", strlen("zxy")); memset(&psk, 0, sizeof(ieee80211_wpapsk)); memcpy(psk.i_name, "zxy", strlen("zxy")); psk.i_enabled = 1; pbkdf2_sha1(ssid_pwd, (const uint8_t*)ssid_name, strlen(ssid_name), 4096, psk.i_psk , 32); memset(&nwkey, 0, sizeof(ieee80211_nwkey)); nwkey.i_wepon = 0; nwkey.i_defkid = 0; memset(&join, 0, sizeof(ieee80211_join)); join.i_wpaparams = wpa; join.i_wpapsk = psk; join.i_flags = IEEE80211_JOIN_WPAPSK | IEEE80211_JOIN_ANY | IEEE80211_JOIN_WPA | IEEE80211_JOIN_8021X; join.i_nwkey = nwkey; join.i_len = strlen(ssid_name); memcpy(join.i_nwid, ssid_name, join.i_len); } if (ieee80211_add_ess(ic, &join) == 0) ic->ic_flags |= IEEE80211_F_AUTO_JOIN; } void itlwm::associateSSID(const char *ssid, const char *pwd) { struct ieee80211com *ic = fHalService->get80211Controller(); if (strlen(pwd) == 0) { memcpy(nwid.i_nwid, ssid, 32); nwid.i_len = strlen((char *)nwid.i_nwid); memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); ic->ic_des_esslen = nwid.i_len; memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len); if (ic->ic_des_esslen > 0) { /* 'nwid' disables auto-join magic */ ic->ic_flags &= ~IEEE80211_F_AUTO_JOIN; } else if (!TAILQ_EMPTY(&ic->ic_ess)) { /* '-nwid' re-enables auto-join */ ic->ic_flags |= IEEE80211_F_AUTO_JOIN; } /* disable WPA/WEP */ ieee80211_disable_rsn(ic); ieee80211_disable_wep(ic); } else { memset(&psk, 0, sizeof(psk)); memcpy(nwid.i_nwid, ssid, 32); nwid.i_len = strlen((char *)nwid.i_nwid); memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); ic->ic_des_esslen = nwid.i_len; memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len); if (ic->ic_des_esslen > 0) { /* 'nwid' disables auto-join magic */ ic->ic_flags &= ~IEEE80211_F_AUTO_JOIN; } else if (!TAILQ_EMPTY(&ic->ic_ess)) { /* '-nwid' re-enables auto-join */ ic->ic_flags |= IEEE80211_F_AUTO_JOIN; } /* disable WPA/WEP */ ieee80211_disable_rsn(ic); ieee80211_disable_wep(ic); size_t passlen = strlen(pwd); /* Parse a WPA passphrase */ if (passlen < 8 || passlen > 63) XYLog("wpakey: passphrase must be between " "8 and 63 characters"); if (nwid.i_len == 0) XYLog("wpakey: nwid not set"); pbkdf2_sha1(pwd, (const uint8_t*)ssid, nwid.i_len, 4096, psk.i_psk, 32); psk.i_enabled = 1; if (psk.i_enabled) { ic->ic_flags |= IEEE80211_F_PSK; memcpy(ic->ic_psk, psk.i_psk, sizeof(ic->ic_psk)); if (ic->ic_flags & IEEE80211_F_WEPON) ieee80211_disable_wep(ic); } else { ic->ic_flags &= ~IEEE80211_F_PSK; memset(ic->ic_psk, 0, sizeof(ic->ic_psk)); } memset(&wpa, 0, sizeof(wpa)); ieee80211_ioctl_getwpaparms(ic, &wpa); wpa.i_enabled = psk.i_enabled; wpa.i_ciphers = 0; wpa.i_groupcipher = 0; wpa.i_protos = IEEE80211_WPA_PROTO_WPA1 | IEEE80211_WPA_PROTO_WPA2; wpa.i_akms = IEEE80211_WPA_AKM_PSK | IEEE80211_WPA_AKM_8021X | IEEE80211_WPA_AKM_SHA256_PSK | IEEE80211_WPA_AKM_SHA256_8021X; ieee80211_ioctl_setwpaparms(ic, &wpa); } if (ic->ic_state > IEEE80211_S_AUTH && ic->ic_bss != NULL) IEEE80211_SEND_MGMT(ic, ic->ic_bss, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); ieee80211_del_ess(ic, NULL, 0, 1); struct ieee80211_node *selbs = ieee80211_node_choose_bss(ic, 0, NULL); if (selbs == NULL) { if (ic->ic_state != IEEE80211_S_SCAN) { ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); } } else { if (ic->ic_state > IEEE80211_S_AUTH) { ieee80211_node_join_bss(ic, selbs, 1); fHalService->getDriverController()->clearScanningFlags(); } else { if (ic->ic_state != IEEE80211_S_SCAN) { ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); } } } } bool itlwm::start(IOService *provider) { int boot_value = 0; if (!super::start(provider)) { return false; } pciNub = OSDynamicCast(IOPCIDevice, provider); if (!pciNub) { return false; } pciNub->setBusMasterEnable(true); pciNub->setIOEnable(true); pciNub->setMemoryEnable(true); pciNub->configWrite8(0x41, 0); if (pciNub->requestPowerDomainState(kIOPMPowerOn, (IOPowerConnection *) getParentEntry(gIOPowerPlane), IOPMLowestState) != IOPMNoErr) { 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)itlwm::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); 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, &itlwm::watchdogAction)); if (!watchdogTimer) { XYLog("init watchdog fail\n"); fHalService->detach(pciNub); super::stop(pciNub); releaseAll(); return false; } fWatchdogWorkLoop->addEventSource(watchdogTimer); setLinkStatus(kIONetworkLinkValid); OSObject *wifiEntryObject = NULL; OSDictionary *wifiEntry = NULL; OSString *entryKey = NULL; OSDictionary *wifiDict = OSDynamicCast(OSDictionary, getProperty("WiFiConfig")); if (wifiDict != NULL) { OSCollectionIterator *iterator = OSCollectionIterator::withCollection(wifiDict); while ((wifiEntryObject = iterator->getNextObject())) { entryKey = OSDynamicCast(OSString, wifiEntryObject); if (entryKey == NULL) { continue; } wifiEntry = OSDynamicCast(OSDictionary, wifiDict->getObject(entryKey)); if (wifiEntry == NULL) { continue; } OSString *ssidObj = OSDynamicCast(OSString, wifiEntry->getObject("ssid")); OSString *pwdObj = OSDynamicCast(OSString, wifiEntry->getObject("password")); if (ssidObj == NULL || pwdObj == NULL || ssidObj->isEqualTo("")) { continue; } joinSSID(ssidObj->getCStringNoCopy(), pwdObj->getCStringNoCopy()); } iterator->release(); } if (TAILQ_EMPTY(&fHalService->get80211Controller()->ic_ess)) { fHalService->get80211Controller()->ic_flags |= IEEE80211_F_AUTO_JOIN; } registerService(); fNetIf->registerService(); return true; } void itlwm::watchdogAction(IOTimerEventSource *timer) { struct _ifnet *ifp = getIfp(); (*ifp->if_watchdog)(ifp); watchdogTimer->setTimeoutMS(kWatchDogTimerPeriod); } const OSString * itlwm::newVendorString() const { return OSString::withCString("Apple"); } const OSString * itlwm::newModelString() const { return OSString::withCString("Intel Wireless Card"); } bool itlwm::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 itlwm::createWorkLoop() { _fWorkloop = IOWorkLoop::workLoop(); return _fWorkloop != 0; } IOWorkLoop *itlwm::getWorkLoop() const { return _fWorkloop; } IOReturn itlwm::selectMedium(const IONetworkMedium *medium) { setSelectedMedium(medium); return kIOReturnSuccess; } void itlwm::stop(IOService *provider) { XYLog("%s\n", __FUNCTION__); struct _ifnet *ifp = &fHalService->get80211Controller()->ic_ac.ac_if; super::stop(provider); setLinkStatus(kIONetworkLinkValid); fHalService->detach(pciNub); ether_ifdetach(ifp); detachInterface(fNetIf, true); OSSafeReleaseNULL(fNetIf); releaseAll(); } void itlwm::releaseAll() { if (fHalService) { fHalService->release(); fHalService = NULL; } if (_fWorkloop) { if (_fCommandGate) { // _fCommandGate->disable(); _fWorkloop->removeEventSource(_fCommandGate); _fCommandGate->release(); _fCommandGate = NULL; } if (fWatchdogWorkLoop && watchdogTimer) { watchdogTimer->cancelTimeout(); fWatchdogWorkLoop->removeEventSource(watchdogTimer); watchdogTimer->release(); watchdogTimer = NULL; fWatchdogWorkLoop->release(); fWatchdogWorkLoop = NULL; } _fWorkloop->release(); _fWorkloop = NULL; } unregistPM(); } void itlwm::free() { XYLog("%s\n", __FUNCTION__); if (fHalService != NULL) { fHalService->release(); fHalService = NULL; } super::free(); } IOReturn itlwm::enable(IONetworkInterface *netif) { XYLog("%s\n", __FUNCTION__); super::enable(netif); _fCommandGate->enable(); fHalService->enable(netif); watchdogTimer->setTimeoutMS(kWatchDogTimerPeriod); watchdogTimer->enable(); return kIOReturnSuccess; } IOReturn itlwm::disable(IONetworkInterface *netif) { XYLog("%s\n", __FUNCTION__); super::disable(netif); watchdogTimer->cancelTimeout(); watchdogTimer->disable(); fHalService->disable(netif); setLinkStatus(kIONetworkLinkValid); return kIOReturnSuccess; } bool itlwm:: setLinkStatus(UInt32 status, const IONetworkMedium * activeMedium, UInt64 speed, OSData * data) { _ifnet *ifq = &fHalService->get80211Controller()->ic_ac.ac_if; bool ret = super::setLinkStatus(status, activeMedium, speed, data); if (fNetIf) { if (status & kIONetworkLinkActive) { #ifdef __PRIVATE_SPI__ fNetIf->startOutputThread(); #endif } else if (!(status & kIONetworkLinkNoNetworkChange)) { #ifdef __PRIVATE_SPI__ fNetIf->stopOutputThread(); fNetIf->flushOutputQueue(); #endif ifq_flush(&ifq->if_snd); mq_purge(&fHalService->get80211Controller()->ic_mgtq); } } return ret; } IOReturn itlwm::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 itlwm::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; } #ifdef __PRIVATE_SPI__ IOReturn itlwm::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 itlwm::outputPacket(mbuf_t m, void *param) { // XYLog("%s\n", __FUNCTION__); IOReturn ret = kIOReturnOutputSuccess; _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 itlwm::getFeatures() const { return fHalService->getDriverInfo()->supportedFeatures(); } IOReturn itlwm::setPromiscuousMode(IOEnetPromiscuousMode mode) { return kIOReturnSuccess; } IOReturn itlwm::setMulticastMode(IOEnetMulticastMode mode) { return kIOReturnSuccess; } IOReturn itlwm::setMulticastList(IOEthernetAddress* addr, UInt32 len) { return fHalService->getDriverController()->setMulticastList(addr, len); } IOReturn itlwm::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 itlwm:: tsleepHandler(OSObject* owner, void* arg0, void* arg1, void* arg2, void* arg3) { itlwm* dev = OSDynamicCast(itlwm, 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 (&deadline)); if (_fCommandGate->commandSleep(arg0, deadline, THREAD_INTERRUPTIBLE) == THREAD_AWAKENED) return kIOReturnSuccess; else return kIOReturnTimeout; } } ================================================ FILE: itlwm/itlwm.hpp ================================================ /* * 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 #include "itlhdr.h" #include #include #include #include #include #include #include #include #include #include #include #include "ItlIwm.hpp" #include "ItlIwx.hpp" #include "ItlIwn.hpp" enum { kPowerStateOff = 0, kPowerStateOn, kPowerStateCount }; #define kWatchDogTimerPeriod 1000 class itlwm : public IOEthernetController { OSDeclareDefaultStructors(itlwm) public: //kext virtual bool init(OSDictionary *properties) override; virtual void free() override; virtual IOService* probe(IOService* provider, SInt32* score) override; virtual bool start(IOService *provider) override; virtual void stop(IOService *provider) override; virtual IOReturn getHardwareAddress(IOEthernetAddress* addrP) override; virtual IOReturn setHardwareAddress(const IOEthernetAddress * addrP) override; virtual IOReturn enable(IONetworkInterface *netif) override; virtual IOReturn disable(IONetworkInterface *netif) override; virtual UInt32 outputPacket(mbuf_t, void * param) override; virtual IOReturn setPromiscuousMode(IOEnetPromiscuousMode mode) override; virtual IOReturn setMulticastMode(IOEnetMulticastMode mode) override; virtual IOReturn setMulticastList(IOEthernetAddress* addr, UInt32 len) override; virtual bool configureInterface(IONetworkInterface *netif) override; virtual bool createWorkLoop() override; virtual IOWorkLoop* getWorkLoop() const override; virtual const OSString * newVendorString() const override; virtual const OSString * newModelString() const override; virtual bool setLinkStatus( UInt32 status, const IONetworkMedium * activeMedium = 0, UInt64 speed = 0, OSData * data = 0) override; #ifdef __PRIVATE_SPI__ virtual IOReturn outputStart(IONetworkInterface *interface, IOOptionBits options) override; #endif virtual IOReturn getPacketFilters(const OSSymbol *group, UInt32 *filters) const override; virtual IOReturn selectMedium(const IONetworkMedium *medium) override; virtual UInt32 getFeatures() const override; virtual IOReturn registerWithPolicyMaker( IOService * policyMaker ) override; virtual IOReturn setPowerState( unsigned long powerStateOrdinal, IOService * policyMaker) override; virtual IOReturn setWakeOnMagicPacket( bool active ) override; void releaseAll(); void joinSSID(const char *ssid, const char *pwd); void associateSSID(const char *ssid, const char *pwd); void watchdogAction(IOTimerEventSource *timer); bool initPCIPowerManagment(IOPCIDevice *provider); struct _ifnet *getIfp(); IOEthernetInterface *getNetworkInterface(); static IOReturn tsleepHandler(OSObject* owner, void* arg0 = 0, void* arg1 = 0, void* arg2 = 0, void* arg3 = 0); void setPowerStateOff(void); void setPowerStateOn(void); void unregistPM(); bool createMediumTables(const IONetworkMedium **primary); public: IOInterruptEventSource* fInterrupt; IOTimerEventSource *watchdogTimer; IOPCIDevice *pciNub; IONetworkStats *fpNetStats; IOEthernetInterface *fNetIf; IOWorkLoop *fWatchdogWorkLoop; ItlHalService *fHalService; //pm thread_call_t powerOnThreadCall; thread_call_t powerOffThreadCall; UInt32 pmPowerState; IOService *pmPolicyMaker; UInt8 pmPCICapPtr; bool magicPacketEnabled; bool magicPacketSupported; //connect params struct ieee80211_wpaparams wpa; struct ieee80211_wpapsk psk; struct ieee80211_nwkey nwkey; struct ieee80211_join join; struct ieee80211_nwid nwid; }; ================================================ FILE: itlwm/pm.cpp ================================================ /* * 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 "itlwm.hpp" 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 itlwm::unregistPM() { if (powerOffThreadCall) { thread_call_free(powerOffThreadCall); powerOffThreadCall = NULL; } if (powerOnThreadCall) { thread_call_free(powerOnThreadCall); powerOnThreadCall = NULL; } } IOReturn itlwm::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 itlwm::setWakeOnMagicPacket(bool active) { magicPacketEnabled = active; return kIOReturnSuccess; } static void handleSetPowerStateOff(thread_call_param_t param0, thread_call_param_t param1) { itlwm *self = (itlwm *)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) { itlwm *self = (itlwm *) param0; if (param1 == 0) { self->getCommandGate()->runAction((IOCommandGate::Action) handleSetPowerStateOn, (void *) 1); } else { self->setPowerStateOn(); self->release(); } } IOReturn itlwm::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 itlwm::setPowerStateOff() { pmPowerState = kPowerStateOff; pmPolicyMaker->acknowledgeSetPowerState(); } void itlwm::setPowerStateOn() { pmPowerState = kPowerStateOn; pmPolicyMaker->acknowledgeSetPowerState(); } ================================================ FILE: itlwm.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 48; objects = { /* Begin PBXAggregateTarget section */ 5066D63825287F7900EE6F38 /* fw_gen */ = { isa = PBXAggregateTarget; buildConfigurationList = 5066D63B25287F7900EE6F38 /* Build configuration list for PBXAggregateTarget "fw_gen" */; buildPhases = ( 5066D63C25287F8E00EE6F38 /* Generate Firmware */, ); dependencies = ( ); name = fw_gen; productName = fw; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 024A07B023FCBC3C009FBA6C /* itlwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 024A07AF23FCBC3C009FBA6C /* itlwm.hpp */; }; 024A07B223FCBC3C009FBA6C /* itlwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07B123FCBC3C009FBA6C /* itlwm.cpp */; }; 024A082E23FCBC6C009FBA6C /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07C923FCBC6C009FBA6C /* aes.c */; }; 024A082F23FCBC6C009FBA6C /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CA23FCBC6C009FBA6C /* hmac.c */; }; 024A083023FCBC6C009FBA6C /* sha2.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CB23FCBC6C009FBA6C /* sha2.c */; }; 024A083123FCBC6C009FBA6C /* rijndael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CC23FCBC6C009FBA6C /* rijndael.c */; }; 024A083223FCBC6C009FBA6C /* ecb3_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */; }; 024A083323FCBC6C009FBA6C /* set_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CE23FCBC6C009FBA6C /* set_key.c */; }; 024A083423FCBC6C009FBA6C /* cast.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CF23FCBC6C009FBA6C /* cast.c */; }; 024A083523FCBC6C009FBA6C /* des_locl.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07D023FCBC6C009FBA6C /* des_locl.h */; }; 024A083623FCBC6C009FBA6C /* michael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D123FCBC6C009FBA6C /* michael.c */; }; 024A083723FCBC6C009FBA6C /* key_wrap.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07D223FCBC6C009FBA6C /* key_wrap.h */; }; 024A083823FCBC6C009FBA6C /* poly1305.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07D323FCBC6C009FBA6C /* poly1305.h */; }; 024A083923FCBC6C009FBA6C /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07D423FCBC6C009FBA6C /* md5.h */; }; 024A083A23FCBC6C009FBA6C /* blf.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07D523FCBC6C009FBA6C /* blf.h */; }; 024A083B23FCBC6C009FBA6C /* arc4.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07D623FCBC6C009FBA6C /* arc4.h */; }; 024A083C23FCBC6C009FBA6C /* chachapoly.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07D723FCBC6C009FBA6C /* chachapoly.h */; }; 024A083D23FCBC6C009FBA6C /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D823FCBC6C009FBA6C /* sha1.c */; }; 024A083E23FCBC6C009FBA6C /* sk.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07D923FCBC6C009FBA6C /* sk.h */; }; 024A083F23FCBC6C009FBA6C /* castsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07DA23FCBC6C009FBA6C /* castsb.h */; }; 024A084023FCBC6C009FBA6C /* rmd160.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07DB23FCBC6C009FBA6C /* rmd160.h */; }; 024A084123FCBC6C009FBA6C /* idgen.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07DC23FCBC6C009FBA6C /* idgen.h */; }; 024A084223FCBC6C009FBA6C /* cmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07DD23FCBC6C009FBA6C /* cmac.c */; }; 024A084323FCBC6C009FBA6C /* gmac.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07DE23FCBC6C009FBA6C /* gmac.h */; }; 024A084423FCBC6C009FBA6C /* sha2.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07DF23FCBC6C009FBA6C /* sha2.h */; }; 024A084523FCBC6C009FBA6C /* hmac.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07E023FCBC6C009FBA6C /* hmac.h */; }; 024A084623FCBC6C009FBA6C /* aes.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07E123FCBC6C009FBA6C /* aes.h */; }; 024A084723FCBC6C009FBA6C /* cast.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07E223FCBC6C009FBA6C /* cast.h */; }; 024A084823FCBC6C009FBA6C /* michael.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07E323FCBC6C009FBA6C /* michael.h */; }; 024A084923FCBC6C009FBA6C /* ecb_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E423FCBC6C009FBA6C /* ecb_enc.c */; }; 024A084A23FCBC6C009FBA6C /* cryptodev.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07E523FCBC6C009FBA6C /* cryptodev.h */; }; 024A084B23FCBC6C009FBA6C /* rijndael.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07E623FCBC6C009FBA6C /* rijndael.h */; }; 024A084C23FCBC6C009FBA6C /* chacha_private.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07E723FCBC6C009FBA6C /* chacha_private.h */; }; 024A084D23FCBC6C009FBA6C /* sha1.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07E823FCBC6C009FBA6C /* sha1.h */; }; 024A084E23FCBC6C009FBA6C /* chachapoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E923FCBC6C009FBA6C /* chachapoly.c */; }; 024A084F23FCBC6C009FBA6C /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EA23FCBC6C009FBA6C /* md5.c */; }; 024A085023FCBC6C009FBA6C /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EB23FCBC6C009FBA6C /* arc4.c */; }; 024A085123FCBC6C009FBA6C /* blf.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EC23FCBC6C009FBA6C /* blf.c */; }; 024A085223FCBC6C009FBA6C /* poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07ED23FCBC6C009FBA6C /* poly1305.c */; }; 024A085323FCBC6C009FBA6C /* spr.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07EE23FCBC6C009FBA6C /* spr.h */; }; 024A085423FCBC6C009FBA6C /* podd.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07EF23FCBC6C009FBA6C /* podd.h */; }; 024A085523FCBC6C009FBA6C /* key_wrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F023FCBC6C009FBA6C /* key_wrap.c */; }; 024A085623FCBC6C009FBA6C /* cmac.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A07F123FCBC6C009FBA6C /* cmac.h */; }; 024A085723FCBC6C009FBA6C /* gmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F223FCBC6C009FBA6C /* gmac.c */; }; 024A085823FCBC6C009FBA6C /* rmd160.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F323FCBC6C009FBA6C /* rmd160.c */; }; 024A085923FCBC6C009FBA6C /* idgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F423FCBC6C009FBA6C /* idgen.c */; }; 024A088B23FCBE38009FBA6C /* if_iwmreg.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A088923FCBE38009FBA6C /* if_iwmreg.h */; }; 024A088C23FCBE38009FBA6C /* if_iwmvar.h in Headers */ = {isa = PBXBuildFile; fileRef = 024A088A23FCBE38009FBA6C /* if_iwmvar.h */; }; 024A08BE23FCD314009FBA6C /* fw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BD23FCD314009FBA6C /* fw.cpp */; }; 024A08C023FCD4E2009FBA6C /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BF23FCD4E2009FBA6C /* utils.cpp */; }; 024A08C223FCD999009FBA6C /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C123FCD999009FBA6C /* io.cpp */; }; 024A08C423FCDC14009FBA6C /* rx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C323FCDC14009FBA6C /* rx.cpp */; }; 024A08C623FCDC3B009FBA6C /* tx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C523FCDC3B009FBA6C /* tx.cpp */; }; 024A08C823FCE2ED009FBA6C /* hw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C723FCE2ED009FBA6C /* hw.cpp */; }; 024A08CA23FCE537009FBA6C /* phy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C923FCE537009FBA6C /* phy.cpp */; }; 024A08CC23FCE5CA009FBA6C /* mac80211.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */; }; 024A08CE23FCE67F009FBA6C /* nvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CD23FCE67F009FBA6C /* nvm.cpp */; }; 024A08D023FCEE88009FBA6C /* ctxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CF23FCEE88009FBA6C /* ctxt.cpp */; }; 024A08D223FCF395009FBA6C /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D123FCF395009FBA6C /* led.cpp */; }; 024A08D423FCF3E6009FBA6C /* power.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D323FCF3E6009FBA6C /* power.cpp */; }; 024A08D623FCF4D7009FBA6C /* scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D523FCF4D7009FBA6C /* scan.cpp */; }; 17FD7F10255E4AC800611406 /* ItlIwn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */; }; 17FD7F11255E4AC800611406 /* ItlIwn.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 17FD7F0F255E4AC800611406 /* ItlIwn.hpp */; }; 17FD7F63255E547100611406 /* ItlIwn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */; }; 17FD7F6A255E547100611406 /* ItlIwn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */; }; 17FD7F71255E547200611406 /* ItlIwn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */; }; 17FD7F78255E547200611406 /* ItlIwn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */; }; 17FD7F7F255E549500611406 /* if_iwnvar.h in Headers */ = {isa = PBXBuildFile; fileRef = 17FD7F0C255E4A0900611406 /* if_iwnvar.h */; }; 17FD7F86255E549900611406 /* if_iwnreg.h in Headers */ = {isa = PBXBuildFile; fileRef = 17FD7F0D255E4AB000611406 /* if_iwnreg.h */; }; 35CBE659251CB89700435CBC /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6C2225027609000F77FF /* debug.h */; }; 35CBE65A251CB89700435CBC /* IOSkywalkEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */; }; 35CBE65B251CB89700435CBC /* apple80211_ioctl.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */; }; 35CBE661251CB89700435CBC /* apple80211_var.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC425021DEC000F77FF /* apple80211_var.h */; }; 35CBE664251CB89700435CBC /* AirportItlwmInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */; }; 35CBE666251CB89700435CBC /* AirportItlwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */; }; 35CBE66F251CB89700435CBC /* apple80211_wps.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC325021DEC000F77FF /* apple80211_wps.h */; }; 35CBE671251CB89700435CBC /* _mbuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D257732495A33500872E4F /* _mbuf.cpp */; }; 35CBE672251CB89700435CBC /* _task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8F9EDE0240B7415009CB8E7 /* _task.cpp */; }; 35CBE673251CB89700435CBC /* FwBinary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */; }; 35CBE675251CB89700435CBC /* ieee80211_proto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC2F24080319007A9422 /* ieee80211_proto.c */; }; 35CBE676251CB89700435CBC /* AirportItlwmInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8CA44A125091AF60036119A /* AirportItlwmInterface.cpp */; }; 35CBE677251CB89700435CBC /* _string.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3024080319007A9422 /* _string.c */; }; 35CBE678251CB89700435CBC /* ieee80211_ioctl.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */; }; 35CBE679251CB89700435CBC /* ieee80211.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3324080319007A9422 /* ieee80211.c */; }; 35CBE67A251CB89700435CBC /* ieee80211_rssadapt.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */; }; 35CBE67B251CB89700435CBC /* ieee80211_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3524080319007A9422 /* ieee80211_input.c */; }; 35CBE67C251CB89700435CBC /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3724080319007A9422 /* timeout.c */; }; 35CBE67D251CB89700435CBC /* ieee80211_mira.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3924080319007A9422 /* ieee80211_mira.c */; }; 35CBE67E251CB89700435CBC /* ieee80211_crypto_bip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */; }; 35CBE67F251CB89700435CBC /* ieee80211_crypto_tkip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */; }; 35CBE680251CB89700435CBC /* ieee80211_crypto_ccmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */; }; 35CBE681251CB89700435CBC /* ieee80211_crypto_wep.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */; }; 35CBE682251CB89700435CBC /* ieee80211_pae_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */; }; 35CBE683251CB89700435CBC /* ieee80211_amrr.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4024080319007A9422 /* ieee80211_amrr.c */; }; 35CBE684251CB89700435CBC /* ieee80211_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC472408031A007A9422 /* ieee80211_output.c */; }; 35CBE685251CB89700435CBC /* ieee80211_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC482408031A007A9422 /* ieee80211_crypto.c */; }; 35CBE686251CB89700435CBC /* CTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC492408031A007A9422 /* CTimeout.cpp */; }; 35CBE687251CB89700435CBC /* ieee80211_regdomain.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */; }; 35CBE688251CB89700435CBC /* ieee80211_node.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4C2408031A007A9422 /* ieee80211_node.c */; }; 35CBE689251CB89700435CBC /* ieee80211_pae_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */; }; 35CBE68A251CB89700435CBC /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */; }; 35CBE68B251CB89700435CBC /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07C923FCBC6C009FBA6C /* aes.c */; }; 35CBE68C251CB89700435CBC /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CA23FCBC6C009FBA6C /* hmac.c */; }; 35CBE68D251CB89700435CBC /* sha2.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CB23FCBC6C009FBA6C /* sha2.c */; }; 35CBE68E251CB89700435CBC /* rijndael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CC23FCBC6C009FBA6C /* rijndael.c */; }; 35CBE68F251CB89700435CBC /* ecb3_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */; }; 35CBE690251CB89700435CBC /* set_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CE23FCBC6C009FBA6C /* set_key.c */; }; 35CBE691251CB89700435CBC /* cast.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CF23FCBC6C009FBA6C /* cast.c */; }; 35CBE692251CB89700435CBC /* michael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D123FCBC6C009FBA6C /* michael.c */; }; 35CBE693251CB89700435CBC /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D823FCBC6C009FBA6C /* sha1.c */; }; 35CBE694251CB89700435CBC /* cmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07DD23FCBC6C009FBA6C /* cmac.c */; }; 35CBE695251CB89700435CBC /* ecb_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E423FCBC6C009FBA6C /* ecb_enc.c */; }; 35CBE696251CB89700435CBC /* chachapoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E923FCBC6C009FBA6C /* chachapoly.c */; }; 35CBE697251CB89700435CBC /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EA23FCBC6C009FBA6C /* md5.c */; }; 35CBE698251CB89700435CBC /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EB23FCBC6C009FBA6C /* arc4.c */; }; 35CBE699251CB89700435CBC /* blf.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EC23FCBC6C009FBA6C /* blf.c */; }; 35CBE69A251CB89700435CBC /* poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07ED23FCBC6C009FBA6C /* poly1305.c */; }; 35CBE69B251CB89700435CBC /* key_wrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F023FCBC6C009FBA6C /* key_wrap.c */; }; 35CBE69C251CB89700435CBC /* gmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F223FCBC6C009FBA6C /* gmac.c */; }; 35CBE69D251CB89700435CBC /* rmd160.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F323FCBC6C009FBA6C /* rmd160.c */; }; 35CBE69E251CB89700435CBC /* idgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F423FCBC6C009FBA6C /* idgen.c */; }; 35CBE69F251CB89700435CBC /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07BA23FCBC6C009FBA6C /* compat.cpp */; }; 35CBE6A0251CB89700435CBC /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = F8FA0EED2501E8C100B1822E /* zutil.c */; }; 35CBE6A1251CB89700435CBC /* ItlHalService.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D364F624F93AFD0029340B /* ItlHalService.cpp */; }; 35CBE6A2251CB89700435CBC /* ItlIwx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */; }; 35CBE6A3251CB89700435CBC /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BF23FCD4E2009FBA6C /* utils.cpp */; }; 35CBE6A4251CB89700435CBC /* fw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BD23FCD314009FBA6C /* fw.cpp */; }; 35CBE6A5251CB89700435CBC /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C123FCD999009FBA6C /* io.cpp */; }; 35CBE6A6251CB89700435CBC /* rx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C323FCDC14009FBA6C /* rx.cpp */; }; 35CBE6A7251CB89700435CBC /* tx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C523FCDC3B009FBA6C /* tx.cpp */; }; 35CBE6A8251CB89700435CBC /* hw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C723FCE2ED009FBA6C /* hw.cpp */; }; 35CBE6A9251CB89700435CBC /* phy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C923FCE537009FBA6C /* phy.cpp */; }; 35CBE6AA251CB89700435CBC /* mac80211.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */; }; 35CBE6AB251CB89700435CBC /* nvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CD23FCE67F009FBA6C /* nvm.cpp */; }; 35CBE6AC251CB89700435CBC /* ctxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CF23FCEE88009FBA6C /* ctxt.cpp */; }; 35CBE6AD251CB89700435CBC /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D123FCF395009FBA6C /* led.cpp */; }; 35CBE6AE251CB89700435CBC /* power.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D323FCF3E6009FBA6C /* power.cpp */; }; 35CBE6AF251CB89700435CBC /* scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D523FCF4D7009FBA6C /* scan.cpp */; }; 35CBE6B0251CB89700435CBC /* ItlIwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */; }; 35CBE6B1251CB89700435CBC /* AirportSTAIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDC25022F8C000F77FF /* AirportSTAIOCTL.cpp */; }; 35CBE6B2251CB89700435CBC /* AirportItlwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BBD25021C9C000F77FF /* AirportItlwm.cpp */; }; 35CBE6B3251CB89700435CBC /* AirportVirtualIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDE25022FB5000F77FF /* AirportVirtualIOCTL.cpp */; }; 35CBE6B4251CB89700435CBC /* AirportAWDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BE025022FC7000F77FF /* AirportAWDL.cpp */; }; 35CBE6C3251CB8BF00435CBC /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6C2225027609000F77FF /* debug.h */; }; 35CBE6C4251CB8BF00435CBC /* IOSkywalkEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */; }; 35CBE6C5251CB8BF00435CBC /* apple80211_ioctl.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */; }; 35CBE6CB251CB8BF00435CBC /* apple80211_var.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC425021DEC000F77FF /* apple80211_var.h */; }; 35CBE6CE251CB8BF00435CBC /* AirportItlwmInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */; }; 35CBE6D0251CB8BF00435CBC /* AirportItlwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */; }; 35CBE6D9251CB8BF00435CBC /* apple80211_wps.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC325021DEC000F77FF /* apple80211_wps.h */; }; 35CBE6DB251CB8BF00435CBC /* _mbuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D257732495A33500872E4F /* _mbuf.cpp */; }; 35CBE6DC251CB8BF00435CBC /* _task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8F9EDE0240B7415009CB8E7 /* _task.cpp */; }; 35CBE6DD251CB8BF00435CBC /* FwBinary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */; }; 35CBE6DF251CB8BF00435CBC /* ieee80211_proto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC2F24080319007A9422 /* ieee80211_proto.c */; }; 35CBE6E0251CB8BF00435CBC /* AirportItlwmInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8CA44A125091AF60036119A /* AirportItlwmInterface.cpp */; }; 35CBE6E1251CB8BF00435CBC /* _string.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3024080319007A9422 /* _string.c */; }; 35CBE6E2251CB8BF00435CBC /* ieee80211_ioctl.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */; }; 35CBE6E3251CB8BF00435CBC /* ieee80211.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3324080319007A9422 /* ieee80211.c */; }; 35CBE6E4251CB8BF00435CBC /* ieee80211_rssadapt.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */; }; 35CBE6E5251CB8BF00435CBC /* ieee80211_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3524080319007A9422 /* ieee80211_input.c */; }; 35CBE6E6251CB8BF00435CBC /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3724080319007A9422 /* timeout.c */; }; 35CBE6E7251CB8BF00435CBC /* ieee80211_mira.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3924080319007A9422 /* ieee80211_mira.c */; }; 35CBE6E8251CB8BF00435CBC /* ieee80211_crypto_bip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */; }; 35CBE6E9251CB8BF00435CBC /* ieee80211_crypto_tkip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */; }; 35CBE6EA251CB8BF00435CBC /* ieee80211_crypto_ccmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */; }; 35CBE6EB251CB8BF00435CBC /* ieee80211_crypto_wep.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */; }; 35CBE6EC251CB8BF00435CBC /* ieee80211_pae_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */; }; 35CBE6ED251CB8BF00435CBC /* ieee80211_amrr.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4024080319007A9422 /* ieee80211_amrr.c */; }; 35CBE6EE251CB8BF00435CBC /* ieee80211_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC472408031A007A9422 /* ieee80211_output.c */; }; 35CBE6EF251CB8BF00435CBC /* ieee80211_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC482408031A007A9422 /* ieee80211_crypto.c */; }; 35CBE6F0251CB8BF00435CBC /* CTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC492408031A007A9422 /* CTimeout.cpp */; }; 35CBE6F1251CB8BF00435CBC /* ieee80211_regdomain.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */; }; 35CBE6F2251CB8BF00435CBC /* ieee80211_node.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4C2408031A007A9422 /* ieee80211_node.c */; }; 35CBE6F3251CB8BF00435CBC /* ieee80211_pae_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */; }; 35CBE6F4251CB8BF00435CBC /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */; }; 35CBE6F5251CB8BF00435CBC /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07C923FCBC6C009FBA6C /* aes.c */; }; 35CBE6F6251CB8BF00435CBC /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CA23FCBC6C009FBA6C /* hmac.c */; }; 35CBE6F7251CB8BF00435CBC /* sha2.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CB23FCBC6C009FBA6C /* sha2.c */; }; 35CBE6F8251CB8BF00435CBC /* rijndael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CC23FCBC6C009FBA6C /* rijndael.c */; }; 35CBE6F9251CB8BF00435CBC /* ecb3_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */; }; 35CBE6FA251CB8BF00435CBC /* set_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CE23FCBC6C009FBA6C /* set_key.c */; }; 35CBE6FB251CB8BF00435CBC /* cast.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CF23FCBC6C009FBA6C /* cast.c */; }; 35CBE6FC251CB8BF00435CBC /* michael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D123FCBC6C009FBA6C /* michael.c */; }; 35CBE6FD251CB8BF00435CBC /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D823FCBC6C009FBA6C /* sha1.c */; }; 35CBE6FE251CB8BF00435CBC /* cmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07DD23FCBC6C009FBA6C /* cmac.c */; }; 35CBE6FF251CB8BF00435CBC /* ecb_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E423FCBC6C009FBA6C /* ecb_enc.c */; }; 35CBE700251CB8BF00435CBC /* chachapoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E923FCBC6C009FBA6C /* chachapoly.c */; }; 35CBE701251CB8BF00435CBC /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EA23FCBC6C009FBA6C /* md5.c */; }; 35CBE702251CB8BF00435CBC /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EB23FCBC6C009FBA6C /* arc4.c */; }; 35CBE703251CB8BF00435CBC /* blf.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EC23FCBC6C009FBA6C /* blf.c */; }; 35CBE704251CB8BF00435CBC /* poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07ED23FCBC6C009FBA6C /* poly1305.c */; }; 35CBE705251CB8BF00435CBC /* key_wrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F023FCBC6C009FBA6C /* key_wrap.c */; }; 35CBE706251CB8BF00435CBC /* gmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F223FCBC6C009FBA6C /* gmac.c */; }; 35CBE707251CB8BF00435CBC /* rmd160.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F323FCBC6C009FBA6C /* rmd160.c */; }; 35CBE708251CB8BF00435CBC /* idgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F423FCBC6C009FBA6C /* idgen.c */; }; 35CBE709251CB8BF00435CBC /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07BA23FCBC6C009FBA6C /* compat.cpp */; }; 35CBE70A251CB8BF00435CBC /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = F8FA0EED2501E8C100B1822E /* zutil.c */; }; 35CBE70B251CB8BF00435CBC /* ItlHalService.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D364F624F93AFD0029340B /* ItlHalService.cpp */; }; 35CBE70C251CB8BF00435CBC /* ItlIwx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */; }; 35CBE70D251CB8BF00435CBC /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BF23FCD4E2009FBA6C /* utils.cpp */; }; 35CBE70E251CB8BF00435CBC /* fw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BD23FCD314009FBA6C /* fw.cpp */; }; 35CBE70F251CB8BF00435CBC /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C123FCD999009FBA6C /* io.cpp */; }; 35CBE710251CB8BF00435CBC /* rx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C323FCDC14009FBA6C /* rx.cpp */; }; 35CBE711251CB8BF00435CBC /* tx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C523FCDC3B009FBA6C /* tx.cpp */; }; 35CBE712251CB8BF00435CBC /* hw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C723FCE2ED009FBA6C /* hw.cpp */; }; 35CBE713251CB8BF00435CBC /* phy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C923FCE537009FBA6C /* phy.cpp */; }; 35CBE714251CB8BF00435CBC /* mac80211.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */; }; 35CBE715251CB8BF00435CBC /* nvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CD23FCE67F009FBA6C /* nvm.cpp */; }; 35CBE716251CB8BF00435CBC /* ctxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CF23FCEE88009FBA6C /* ctxt.cpp */; }; 35CBE717251CB8BF00435CBC /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D123FCF395009FBA6C /* led.cpp */; }; 35CBE718251CB8BF00435CBC /* power.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D323FCF3E6009FBA6C /* power.cpp */; }; 35CBE719251CB8BF00435CBC /* scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D523FCF4D7009FBA6C /* scan.cpp */; }; 35CBE71A251CB8BF00435CBC /* ItlIwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */; }; 35CBE71B251CB8BF00435CBC /* AirportSTAIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDC25022F8C000F77FF /* AirportSTAIOCTL.cpp */; }; 35CBE71C251CB8BF00435CBC /* AirportItlwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BBD25021C9C000F77FF /* AirportItlwm.cpp */; }; 35CBE71D251CB8BF00435CBC /* AirportVirtualIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDE25022FB5000F77FF /* AirportVirtualIOCTL.cpp */; }; 35CBE71E251CB8BF00435CBC /* AirportAWDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BE025022FC7000F77FF /* AirportAWDL.cpp */; }; 35CBE72E251CB8CA00435CBC /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6C2225027609000F77FF /* debug.h */; }; 35CBE72F251CB8CA00435CBC /* IOSkywalkEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */; }; 35CBE730251CB8CA00435CBC /* apple80211_ioctl.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */; }; 35CBE736251CB8CA00435CBC /* apple80211_var.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC425021DEC000F77FF /* apple80211_var.h */; }; 35CBE739251CB8CA00435CBC /* AirportItlwmInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */; }; 35CBE73B251CB8CA00435CBC /* AirportItlwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */; }; 35CBE744251CB8CA00435CBC /* apple80211_wps.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC325021DEC000F77FF /* apple80211_wps.h */; }; 35CBE746251CB8CA00435CBC /* _mbuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D257732495A33500872E4F /* _mbuf.cpp */; }; 35CBE747251CB8CA00435CBC /* _task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8F9EDE0240B7415009CB8E7 /* _task.cpp */; }; 35CBE748251CB8CA00435CBC /* FwBinary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */; }; 35CBE74A251CB8CA00435CBC /* ieee80211_proto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC2F24080319007A9422 /* ieee80211_proto.c */; }; 35CBE74B251CB8CA00435CBC /* AirportItlwmInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8CA44A125091AF60036119A /* AirportItlwmInterface.cpp */; }; 35CBE74C251CB8CA00435CBC /* _string.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3024080319007A9422 /* _string.c */; }; 35CBE74D251CB8CA00435CBC /* ieee80211_ioctl.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */; }; 35CBE74E251CB8CA00435CBC /* ieee80211.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3324080319007A9422 /* ieee80211.c */; }; 35CBE74F251CB8CA00435CBC /* ieee80211_rssadapt.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */; }; 35CBE750251CB8CA00435CBC /* ieee80211_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3524080319007A9422 /* ieee80211_input.c */; }; 35CBE751251CB8CA00435CBC /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3724080319007A9422 /* timeout.c */; }; 35CBE752251CB8CA00435CBC /* ieee80211_mira.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3924080319007A9422 /* ieee80211_mira.c */; }; 35CBE753251CB8CA00435CBC /* ieee80211_crypto_bip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */; }; 35CBE754251CB8CA00435CBC /* ieee80211_crypto_tkip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */; }; 35CBE755251CB8CA00435CBC /* ieee80211_crypto_ccmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */; }; 35CBE756251CB8CA00435CBC /* ieee80211_crypto_wep.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */; }; 35CBE757251CB8CA00435CBC /* ieee80211_pae_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */; }; 35CBE758251CB8CA00435CBC /* ieee80211_amrr.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4024080319007A9422 /* ieee80211_amrr.c */; }; 35CBE759251CB8CA00435CBC /* ieee80211_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC472408031A007A9422 /* ieee80211_output.c */; }; 35CBE75A251CB8CA00435CBC /* ieee80211_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC482408031A007A9422 /* ieee80211_crypto.c */; }; 35CBE75B251CB8CA00435CBC /* CTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC492408031A007A9422 /* CTimeout.cpp */; }; 35CBE75C251CB8CA00435CBC /* ieee80211_regdomain.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */; }; 35CBE75D251CB8CA00435CBC /* ieee80211_node.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4C2408031A007A9422 /* ieee80211_node.c */; }; 35CBE75E251CB8CA00435CBC /* ieee80211_pae_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */; }; 35CBE75F251CB8CA00435CBC /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */; }; 35CBE760251CB8CA00435CBC /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07C923FCBC6C009FBA6C /* aes.c */; }; 35CBE761251CB8CA00435CBC /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CA23FCBC6C009FBA6C /* hmac.c */; }; 35CBE762251CB8CA00435CBC /* sha2.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CB23FCBC6C009FBA6C /* sha2.c */; }; 35CBE763251CB8CA00435CBC /* rijndael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CC23FCBC6C009FBA6C /* rijndael.c */; }; 35CBE764251CB8CA00435CBC /* ecb3_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */; }; 35CBE765251CB8CA00435CBC /* set_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CE23FCBC6C009FBA6C /* set_key.c */; }; 35CBE766251CB8CA00435CBC /* cast.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CF23FCBC6C009FBA6C /* cast.c */; }; 35CBE767251CB8CA00435CBC /* michael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D123FCBC6C009FBA6C /* michael.c */; }; 35CBE768251CB8CA00435CBC /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D823FCBC6C009FBA6C /* sha1.c */; }; 35CBE769251CB8CA00435CBC /* cmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07DD23FCBC6C009FBA6C /* cmac.c */; }; 35CBE76A251CB8CA00435CBC /* ecb_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E423FCBC6C009FBA6C /* ecb_enc.c */; }; 35CBE76B251CB8CA00435CBC /* chachapoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E923FCBC6C009FBA6C /* chachapoly.c */; }; 35CBE76C251CB8CA00435CBC /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EA23FCBC6C009FBA6C /* md5.c */; }; 35CBE76D251CB8CA00435CBC /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EB23FCBC6C009FBA6C /* arc4.c */; }; 35CBE76E251CB8CA00435CBC /* blf.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EC23FCBC6C009FBA6C /* blf.c */; }; 35CBE76F251CB8CA00435CBC /* poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07ED23FCBC6C009FBA6C /* poly1305.c */; }; 35CBE770251CB8CA00435CBC /* key_wrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F023FCBC6C009FBA6C /* key_wrap.c */; }; 35CBE771251CB8CA00435CBC /* gmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F223FCBC6C009FBA6C /* gmac.c */; }; 35CBE772251CB8CA00435CBC /* rmd160.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F323FCBC6C009FBA6C /* rmd160.c */; }; 35CBE773251CB8CA00435CBC /* idgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F423FCBC6C009FBA6C /* idgen.c */; }; 35CBE774251CB8CA00435CBC /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07BA23FCBC6C009FBA6C /* compat.cpp */; }; 35CBE775251CB8CA00435CBC /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = F8FA0EED2501E8C100B1822E /* zutil.c */; }; 35CBE776251CB8CA00435CBC /* ItlHalService.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D364F624F93AFD0029340B /* ItlHalService.cpp */; }; 35CBE777251CB8CA00435CBC /* ItlIwx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */; }; 35CBE778251CB8CA00435CBC /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BF23FCD4E2009FBA6C /* utils.cpp */; }; 35CBE779251CB8CA00435CBC /* fw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BD23FCD314009FBA6C /* fw.cpp */; }; 35CBE77A251CB8CA00435CBC /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C123FCD999009FBA6C /* io.cpp */; }; 35CBE77B251CB8CA00435CBC /* rx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C323FCDC14009FBA6C /* rx.cpp */; }; 35CBE77C251CB8CA00435CBC /* tx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C523FCDC3B009FBA6C /* tx.cpp */; }; 35CBE77D251CB8CA00435CBC /* hw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C723FCE2ED009FBA6C /* hw.cpp */; }; 35CBE77E251CB8CA00435CBC /* phy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C923FCE537009FBA6C /* phy.cpp */; }; 35CBE77F251CB8CA00435CBC /* mac80211.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */; }; 35CBE780251CB8CA00435CBC /* nvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CD23FCE67F009FBA6C /* nvm.cpp */; }; 35CBE781251CB8CA00435CBC /* ctxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CF23FCEE88009FBA6C /* ctxt.cpp */; }; 35CBE782251CB8CA00435CBC /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D123FCF395009FBA6C /* led.cpp */; }; 35CBE783251CB8CA00435CBC /* power.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D323FCF3E6009FBA6C /* power.cpp */; }; 35CBE784251CB8CA00435CBC /* scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D523FCF4D7009FBA6C /* scan.cpp */; }; 35CBE785251CB8CA00435CBC /* ItlIwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */; }; 35CBE786251CB8CA00435CBC /* AirportSTAIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDC25022F8C000F77FF /* AirportSTAIOCTL.cpp */; }; 35CBE787251CB8CA00435CBC /* AirportItlwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BBD25021C9C000F77FF /* AirportItlwm.cpp */; }; 35CBE788251CB8CA00435CBC /* AirportVirtualIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDE25022FB5000F77FF /* AirportVirtualIOCTL.cpp */; }; 35CBE789251CB8CA00435CBC /* AirportAWDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BE025022FC7000F77FF /* AirportAWDL.cpp */; }; 5088ECBD252884870068A63D /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5088ECBC252884870068A63D /* libkmod.a */; }; 5088ECBE252884A30068A63D /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5088ECBC252884870068A63D /* libkmod.a */; }; 5088ECBF252884AF0068A63D /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5088ECBC252884870068A63D /* libkmod.a */; }; 5088ECC0252884C10068A63D /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5088ECBC252884870068A63D /* libkmod.a */; }; 5088ECC1252884D70068A63D /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5088ECBC252884870068A63D /* libkmod.a */; }; A5A0C5242A501E6800EF9328 /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = A5A0C5232A501E6800EF9328 /* arp.c */; }; A5A0C5252A501E6800EF9328 /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = A5A0C5232A501E6800EF9328 /* arp.c */; }; A5A0C5262A501E6800EF9328 /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = A5A0C5232A501E6800EF9328 /* arp.c */; }; A5A0C5272A501E6800EF9328 /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = A5A0C5232A501E6800EF9328 /* arp.c */; }; A5A0C5282A501E6800EF9328 /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = A5A0C5232A501E6800EF9328 /* arp.c */; }; A5A0C5292A501E6800EF9328 /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = A5A0C5232A501E6800EF9328 /* arp.c */; }; A5A0C52A2A501E6800EF9328 /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = A5A0C5232A501E6800EF9328 /* arp.c */; }; A5A0C52B2A501E6800EF9328 /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = A5A0C5232A501E6800EF9328 /* arp.c */; }; A5DD111526D93B5F00BA01EF /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DD111326D93B5F00BA01EF /* rs.cpp */; }; A5DD111626D93B5F00BA01EF /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DD111326D93B5F00BA01EF /* rs.cpp */; }; A5DD111726D93B5F00BA01EF /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DD111326D93B5F00BA01EF /* rs.cpp */; }; A5DD111826D93B5F00BA01EF /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DD111326D93B5F00BA01EF /* rs.cpp */; }; A5DD111926D93B5F00BA01EF /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DD111326D93B5F00BA01EF /* rs.cpp */; }; A5DD111A26D93B5F00BA01EF /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DD111326D93B5F00BA01EF /* rs.cpp */; }; A5DD111B26D93B5F00BA01EF /* rs.h in Headers */ = {isa = PBXBuildFile; fileRef = A5DD111426D93B5F00BA01EF /* rs.h */; }; A5DD111C26D93B5F00BA01EF /* rs.h in Headers */ = {isa = PBXBuildFile; fileRef = A5DD111426D93B5F00BA01EF /* rs.h */; }; A5DD111D26D93B5F00BA01EF /* rs.h in Headers */ = {isa = PBXBuildFile; fileRef = A5DD111426D93B5F00BA01EF /* rs.h */; }; A5DD111E26D93B5F00BA01EF /* rs.h in Headers */ = {isa = PBXBuildFile; fileRef = A5DD111426D93B5F00BA01EF /* rs.h */; }; A5DD111F26D93B5F00BA01EF /* rs.h in Headers */ = {isa = PBXBuildFile; fileRef = A5DD111426D93B5F00BA01EF /* rs.h */; }; A5DD112026D93B5F00BA01EF /* rs.h in Headers */ = {isa = PBXBuildFile; fileRef = A5DD111426D93B5F00BA01EF /* rs.h */; }; A5FA2AE428A797B200847103 /* _ifq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FA2AE328A797B200847103 /* _ifq.cpp */; }; A5FA2AE528A797B200847103 /* _ifq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FA2AE328A797B200847103 /* _ifq.cpp */; }; A5FA2AE628A797B200847103 /* _ifq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FA2AE328A797B200847103 /* _ifq.cpp */; }; A5FA2AE728A797B200847103 /* _ifq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FA2AE328A797B200847103 /* _ifq.cpp */; }; A5FA2AE828A797B200847103 /* _ifq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FA2AE328A797B200847103 /* _ifq.cpp */; }; A5FA2AE928A797B200847103 /* _ifq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FA2AE328A797B200847103 /* _ifq.cpp */; }; A5FA2AEA28A797B200847103 /* _ifq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FA2AE328A797B200847103 /* _ifq.cpp */; }; F800DD9B24FBEBF000789320 /* ItlDriverController.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F800DD9A24FBEBF000789320 /* ItlDriverController.hpp */; }; F8294FE424FCBF5100239253 /* FwBinary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */; }; F837C91D2724577F00B2C499 /* coex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F837C91C2724577F00B2C499 /* coex.cpp */; }; F837C91E2724577F00B2C499 /* coex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F837C91C2724577F00B2C499 /* coex.cpp */; }; F837C91F2724577F00B2C499 /* coex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F837C91C2724577F00B2C499 /* coex.cpp */; }; F837C9202724577F00B2C499 /* coex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F837C91C2724577F00B2C499 /* coex.cpp */; }; F837C9212724577F00B2C499 /* coex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F837C91C2724577F00B2C499 /* coex.cpp */; }; F837C9222724577F00B2C499 /* coex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F837C91C2724577F00B2C499 /* coex.cpp */; }; F84AD8862A497DB200DC8DED /* IO80211WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */; }; F84AD8872A497DB200DC8DED /* IO80211WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */; }; F84AD8882A497DB200DC8DED /* IO80211WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */; }; F84AD8892A497DB200DC8DED /* IO80211WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */; }; F84AD88A2A497DB200DC8DED /* IO80211WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */; }; F84AD88B2A497DB200DC8DED /* IO80211WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */; }; F84AD88C2A497DB200DC8DED /* IO80211WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */; }; F84AD88D2A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */; }; F84AD88E2A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */; }; F84AD88F2A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */; }; F84AD8902A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */; }; F84AD8912A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */; }; F84AD8922A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */; }; F84AD8932A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */; }; F84AD8942A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */; }; F84AD8952A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */; }; F84AD8962A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */; }; F84AD8972A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */; }; F84AD8982A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */; }; F84AD8992A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */; }; F84AD89A2A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */; }; F84AD89B2A497DB200DC8DED /* CCPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87D2A497DB200DC8DED /* CCPipe.h */; }; F84AD89C2A497DB200DC8DED /* CCPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87D2A497DB200DC8DED /* CCPipe.h */; }; F84AD89D2A497DB200DC8DED /* CCPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87D2A497DB200DC8DED /* CCPipe.h */; }; F84AD89E2A497DB200DC8DED /* CCPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87D2A497DB200DC8DED /* CCPipe.h */; }; F84AD89F2A497DB200DC8DED /* CCPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87D2A497DB200DC8DED /* CCPipe.h */; }; F84AD8A02A497DB200DC8DED /* CCPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87D2A497DB200DC8DED /* CCPipe.h */; }; F84AD8A12A497DB200DC8DED /* CCPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87D2A497DB200DC8DED /* CCPipe.h */; }; F84AD8A22A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */; }; F84AD8A32A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */; }; F84AD8A42A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */; }; F84AD8A52A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */; }; F84AD8A62A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */; }; F84AD8A72A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */; }; F84AD8A82A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */; }; F84AD8A92A497DB200DC8DED /* IO80211InfraInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */; }; F84AD8AA2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */; }; F84AD8AB2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */; }; F84AD8AC2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */; }; F84AD8AD2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */; }; F84AD8AE2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */; }; F84AD8AF2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */; }; F84AD8B02A497DB200DC8DED /* CCStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8802A497DB200DC8DED /* CCStream.h */; }; F84AD8B12A497DB200DC8DED /* CCStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8802A497DB200DC8DED /* CCStream.h */; }; F84AD8B22A497DB200DC8DED /* CCStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8802A497DB200DC8DED /* CCStream.h */; }; F84AD8B32A497DB200DC8DED /* CCStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8802A497DB200DC8DED /* CCStream.h */; }; F84AD8B42A497DB200DC8DED /* CCStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8802A497DB200DC8DED /* CCStream.h */; }; F84AD8B52A497DB200DC8DED /* CCStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8802A497DB200DC8DED /* CCStream.h */; }; F84AD8B62A497DB200DC8DED /* CCStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8802A497DB200DC8DED /* CCStream.h */; }; F84AD8B72A497DB200DC8DED /* CCDataPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8812A497DB200DC8DED /* CCDataPipe.h */; }; F84AD8B82A497DB200DC8DED /* CCDataPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8812A497DB200DC8DED /* CCDataPipe.h */; }; F84AD8B92A497DB200DC8DED /* CCDataPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8812A497DB200DC8DED /* CCDataPipe.h */; }; F84AD8BA2A497DB200DC8DED /* CCDataPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8812A497DB200DC8DED /* CCDataPipe.h */; }; F84AD8BB2A497DB200DC8DED /* CCDataPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8812A497DB200DC8DED /* CCDataPipe.h */; }; F84AD8BC2A497DB200DC8DED /* CCDataPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8812A497DB200DC8DED /* CCDataPipe.h */; }; F84AD8BD2A497DB200DC8DED /* CCDataPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8812A497DB200DC8DED /* CCDataPipe.h */; }; F84AD8BE2A497DB200DC8DED /* CCLogStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8822A497DB200DC8DED /* CCLogStream.h */; }; F84AD8BF2A497DB200DC8DED /* CCLogStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8822A497DB200DC8DED /* CCLogStream.h */; }; F84AD8C02A497DB200DC8DED /* CCLogStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8822A497DB200DC8DED /* CCLogStream.h */; }; F84AD8C12A497DB200DC8DED /* CCLogStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8822A497DB200DC8DED /* CCLogStream.h */; }; F84AD8C22A497DB200DC8DED /* CCLogStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8822A497DB200DC8DED /* CCLogStream.h */; }; F84AD8C32A497DB200DC8DED /* CCLogStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8822A497DB200DC8DED /* CCLogStream.h */; }; F84AD8C42A497DB200DC8DED /* CCLogStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8822A497DB200DC8DED /* CCLogStream.h */; }; F84AD8C52A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */; }; F84AD8C62A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */; }; F84AD8C72A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */; }; F84AD8C82A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */; }; F84AD8C92A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */; }; F84AD8CA2A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */; }; F84AD8CB2A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */; }; F84AD8CC2A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */; }; F84AD8CD2A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */; }; F84AD8CE2A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */; }; F84AD8CF2A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */; }; F84AD8D02A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */; }; F84AD8D12A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */; }; F84AD8D22A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */; }; F84AD8D32A497DB200DC8DED /* CCLogPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8852A497DB200DC8DED /* CCLogPipe.h */; }; F84AD8D42A497DB200DC8DED /* CCLogPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8852A497DB200DC8DED /* CCLogPipe.h */; }; F84AD8D52A497DB200DC8DED /* CCLogPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8852A497DB200DC8DED /* CCLogPipe.h */; }; F84AD8D62A497DB200DC8DED /* CCLogPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8852A497DB200DC8DED /* CCLogPipe.h */; }; F84AD8D72A497DB200DC8DED /* CCLogPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8852A497DB200DC8DED /* CCLogPipe.h */; }; F84AD8D82A497DB200DC8DED /* CCLogPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8852A497DB200DC8DED /* CCLogPipe.h */; }; F84AD8D92A497DB200DC8DED /* CCLogPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8852A497DB200DC8DED /* CCLogPipe.h */; }; F8876A4E28B71F5400A21E42 /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DD111326D93B5F00BA01EF /* rs.cpp */; }; F88CB91424FBE9130060B1A5 /* ItlDriverInfo.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F88CB91324FBE9130060B1A5 /* ItlDriverInfo.hpp */; }; F88D2B3D2414E64000BBE700 /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */; }; F897ECBA266EFF93005EE8F7 /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6C2225027609000F77FF /* debug.h */; }; F897ECBB266EFF93005EE8F7 /* IOSkywalkEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */; }; F897ECBC266EFF93005EE8F7 /* apple80211_ioctl.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */; }; F897ECBD266EFF93005EE8F7 /* IO80211P2PInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */; }; F897ECBE266EFF93005EE8F7 /* IO80211WorkLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */; }; F897ECBF266EFF93005EE8F7 /* apple80211_var.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC425021DEC000F77FF /* apple80211_var.h */; }; F897ECC0266EFF93005EE8F7 /* AirportItlwmInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */; }; F897ECC1266EFF93005EE8F7 /* IO80211Interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA38252D834500520FD4 /* IO80211Interface.h */; }; F897ECC2266EFF93005EE8F7 /* (null) in Headers */ = {isa = PBXBuildFile; }; F897ECC3266EFF93005EE8F7 /* IO80211SkywalkInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */; }; F897ECC4266EFF93005EE8F7 /* AirportItlwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */; }; F897ECC5266EFF93005EE8F7 /* IO80211VirtualInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */; }; F897ECC6266EFF93005EE8F7 /* IO80211Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA35252D834500520FD4 /* IO80211Controller.h */; }; F897ECC7266EFF93005EE8F7 /* (null) in Headers */ = {isa = PBXBuildFile; }; F897ECC8266EFF93005EE8F7 /* ieee80211_ra.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C594D225FD935B0007D19C /* ieee80211_ra.h */; }; F897ECC9266EFF93005EE8F7 /* apple80211_wps.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC325021DEC000F77FF /* apple80211_wps.h */; }; F897ECCB266EFF93005EE8F7 /* _mbuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D257732495A33500872E4F /* _mbuf.cpp */; }; F897ECCC266EFF93005EE8F7 /* ieee80211_ra.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C594D125FD935B0007D19C /* ieee80211_ra.c */; }; F897ECCD266EFF93005EE8F7 /* _task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8F9EDE0240B7415009CB8E7 /* _task.cpp */; }; F897ECCE266EFF93005EE8F7 /* FwBinary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */; }; F897ECD0266EFF93005EE8F7 /* ieee80211_proto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC2F24080319007A9422 /* ieee80211_proto.c */; }; F897ECD1266EFF93005EE8F7 /* AirportItlwmInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8CA44A125091AF60036119A /* AirportItlwmInterface.cpp */; }; F897ECD2266EFF93005EE8F7 /* _string.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3024080319007A9422 /* _string.c */; }; F897ECD3266EFF93005EE8F7 /* ieee80211_ioctl.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */; }; F897ECD4266EFF93005EE8F7 /* ieee80211.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3324080319007A9422 /* ieee80211.c */; }; F897ECD5266EFF93005EE8F7 /* ieee80211_rssadapt.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */; }; F897ECD6266EFF93005EE8F7 /* ieee80211_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3524080319007A9422 /* ieee80211_input.c */; }; F897ECD7266EFF93005EE8F7 /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3724080319007A9422 /* timeout.c */; }; F897ECD8266EFF93005EE8F7 /* ieee80211_mira.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3924080319007A9422 /* ieee80211_mira.c */; }; F897ECD9266EFF93005EE8F7 /* ieee80211_crypto_bip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */; }; F897ECDA266EFF93005EE8F7 /* ieee80211_crypto_tkip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */; }; F897ECDB266EFF93005EE8F7 /* ieee80211_crypto_ccmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */; }; F897ECDC266EFF93005EE8F7 /* ieee80211_crypto_wep.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */; }; F897ECDD266EFF93005EE8F7 /* ieee80211_pae_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */; }; F897ECDE266EFF93005EE8F7 /* ieee80211_amrr.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4024080319007A9422 /* ieee80211_amrr.c */; }; F897ECDF266EFF93005EE8F7 /* ieee80211_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC472408031A007A9422 /* ieee80211_output.c */; }; F897ECE0266EFF93005EE8F7 /* ieee80211_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC482408031A007A9422 /* ieee80211_crypto.c */; }; F897ECE1266EFF93005EE8F7 /* CTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC492408031A007A9422 /* CTimeout.cpp */; }; F897ECE2266EFF93005EE8F7 /* ieee80211_regdomain.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */; }; F897ECE3266EFF93005EE8F7 /* ieee80211_node.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4C2408031A007A9422 /* ieee80211_node.c */; }; F897ECE4266EFF93005EE8F7 /* ieee80211_pae_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */; }; F897ECE5266EFF93005EE8F7 /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */; }; F897ECE6266EFF93005EE8F7 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07C923FCBC6C009FBA6C /* aes.c */; }; F897ECE7266EFF93005EE8F7 /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CA23FCBC6C009FBA6C /* hmac.c */; }; F897ECE8266EFF93005EE8F7 /* sha2.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CB23FCBC6C009FBA6C /* sha2.c */; }; F897ECE9266EFF93005EE8F7 /* rijndael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CC23FCBC6C009FBA6C /* rijndael.c */; }; F897ECEA266EFF93005EE8F7 /* ecb3_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */; }; F897ECEB266EFF93005EE8F7 /* set_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CE23FCBC6C009FBA6C /* set_key.c */; }; F897ECEC266EFF93005EE8F7 /* cast.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CF23FCBC6C009FBA6C /* cast.c */; }; F897ECED266EFF93005EE8F7 /* michael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D123FCBC6C009FBA6C /* michael.c */; }; F897ECEE266EFF93005EE8F7 /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D823FCBC6C009FBA6C /* sha1.c */; }; F897ECEF266EFF93005EE8F7 /* cmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07DD23FCBC6C009FBA6C /* cmac.c */; }; F897ECF0266EFF93005EE8F7 /* ecb_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E423FCBC6C009FBA6C /* ecb_enc.c */; }; F897ECF1266EFF93005EE8F7 /* chachapoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E923FCBC6C009FBA6C /* chachapoly.c */; }; F897ECF2266EFF93005EE8F7 /* (null) in Sources */ = {isa = PBXBuildFile; }; F897ECF3266EFF93005EE8F7 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EA23FCBC6C009FBA6C /* md5.c */; }; F897ECF4266EFF93005EE8F7 /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EB23FCBC6C009FBA6C /* arc4.c */; }; F897ECF5266EFF93005EE8F7 /* blf.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EC23FCBC6C009FBA6C /* blf.c */; }; F897ECF6266EFF93005EE8F7 /* poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07ED23FCBC6C009FBA6C /* poly1305.c */; }; F897ECF7266EFF93005EE8F7 /* key_wrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F023FCBC6C009FBA6C /* key_wrap.c */; }; F897ECF8266EFF93005EE8F7 /* gmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F223FCBC6C009FBA6C /* gmac.c */; }; F897ECF9266EFF93005EE8F7 /* rmd160.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F323FCBC6C009FBA6C /* rmd160.c */; }; F897ECFA266EFF93005EE8F7 /* idgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F423FCBC6C009FBA6C /* idgen.c */; }; F897ECFB266EFF93005EE8F7 /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07BA23FCBC6C009FBA6C /* compat.cpp */; }; F897ECFC266EFF93005EE8F7 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = F8FA0EED2501E8C100B1822E /* zutil.c */; }; F897ECFD266EFF93005EE8F7 /* ItlHalService.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D364F624F93AFD0029340B /* ItlHalService.cpp */; }; F897ECFE266EFF93005EE8F7 /* ItlIwx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */; }; F897ECFF266EFF93005EE8F7 /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BF23FCD4E2009FBA6C /* utils.cpp */; }; F897ED00266EFF93005EE8F7 /* fw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BD23FCD314009FBA6C /* fw.cpp */; }; F897ED01266EFF93005EE8F7 /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C123FCD999009FBA6C /* io.cpp */; }; F897ED02266EFF93005EE8F7 /* rx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C323FCDC14009FBA6C /* rx.cpp */; }; F897ED03266EFF93005EE8F7 /* tx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C523FCDC3B009FBA6C /* tx.cpp */; }; F897ED04266EFF93005EE8F7 /* hw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C723FCE2ED009FBA6C /* hw.cpp */; }; F897ED05266EFF93005EE8F7 /* ItlIwn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */; }; F897ED06266EFF93005EE8F7 /* phy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C923FCE537009FBA6C /* phy.cpp */; }; F897ED07266EFF93005EE8F7 /* mac80211.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */; }; F897ED08266EFF93005EE8F7 /* nvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CD23FCE67F009FBA6C /* nvm.cpp */; }; F897ED09266EFF93005EE8F7 /* ctxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CF23FCEE88009FBA6C /* ctxt.cpp */; }; F897ED0A266EFF93005EE8F7 /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D123FCF395009FBA6C /* led.cpp */; }; F897ED0B266EFF93005EE8F7 /* power.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D323FCF3E6009FBA6C /* power.cpp */; }; F897ED0C266EFF93005EE8F7 /* scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D523FCF4D7009FBA6C /* scan.cpp */; }; F897ED0D266EFF93005EE8F7 /* ItlIwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */; }; F897ED0E266EFF93005EE8F7 /* AirportSTAIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDC25022F8C000F77FF /* AirportSTAIOCTL.cpp */; }; F897ED0F266EFF93005EE8F7 /* AirportItlwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BBD25021C9C000F77FF /* AirportItlwm.cpp */; }; F897ED10266EFF93005EE8F7 /* AirportVirtualIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDE25022FB5000F77FF /* AirportVirtualIOCTL.cpp */; }; F897ED11266EFF93005EE8F7 /* AirportAWDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BE025022FC7000F77FF /* AirportAWDL.cpp */; }; F897ED13266EFF93005EE8F7 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5088ECBC252884870068A63D /* libkmod.a */; }; F89B6BBC25021C9C000F77FF /* AirportItlwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */; }; F89B6BBE25021C9C000F77FF /* AirportItlwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BBD25021C9C000F77FF /* AirportItlwm.cpp */; }; F89B6BC725021DED000F77FF /* apple80211_wps.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC325021DEC000F77FF /* apple80211_wps.h */; }; F89B6BC925021DED000F77FF /* apple80211_var.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC425021DEC000F77FF /* apple80211_var.h */; }; F89B6BCB25021DED000F77FF /* apple80211_ioctl.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */; }; F89B6BD725021E66000F77FF /* IOSkywalkEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */; }; F89B6BDD25022F8C000F77FF /* AirportSTAIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDC25022F8C000F77FF /* AirportSTAIOCTL.cpp */; }; F89B6BDF25022FB5000F77FF /* AirportVirtualIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDE25022FB5000F77FF /* AirportVirtualIOCTL.cpp */; }; F89B6BE125022FC7000F77FF /* AirportAWDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BE025022FC7000F77FF /* AirportAWDL.cpp */; }; F89B6BE22502315B000F77FF /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BF23FCD4E2009FBA6C /* utils.cpp */; }; F89B6BE32502315B000F77FF /* fw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BD23FCD314009FBA6C /* fw.cpp */; }; F89B6BE42502315B000F77FF /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C123FCD999009FBA6C /* io.cpp */; }; F89B6BE52502315B000F77FF /* rx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C323FCDC14009FBA6C /* rx.cpp */; }; F89B6BE62502315B000F77FF /* tx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C523FCDC3B009FBA6C /* tx.cpp */; }; F89B6BE72502315B000F77FF /* hw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C723FCE2ED009FBA6C /* hw.cpp */; }; F89B6BE82502315B000F77FF /* phy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C923FCE537009FBA6C /* phy.cpp */; }; F89B6BE92502315B000F77FF /* mac80211.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */; }; F89B6BEA2502315B000F77FF /* nvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CD23FCE67F009FBA6C /* nvm.cpp */; }; F89B6BEB2502315B000F77FF /* ctxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CF23FCEE88009FBA6C /* ctxt.cpp */; }; F89B6BEC2502315B000F77FF /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D123FCF395009FBA6C /* led.cpp */; }; F89B6BED2502315B000F77FF /* power.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D323FCF3E6009FBA6C /* power.cpp */; }; F89B6BEE2502315B000F77FF /* scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D523FCF4D7009FBA6C /* scan.cpp */; }; F89B6BEF2502315B000F77FF /* ItlIwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */; }; F89B6BF025023162000F77FF /* ItlIwx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */; }; F89B6BF12502316A000F77FF /* ItlHalService.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D364F624F93AFD0029340B /* ItlHalService.cpp */; }; F89B6BF3250231E3000F77FF /* FwBinary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */; }; F89B6BF5250231E3000F77FF /* ieee80211_proto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC2F24080319007A9422 /* ieee80211_proto.c */; }; F89B6BF6250231E3000F77FF /* _string.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3024080319007A9422 /* _string.c */; }; F89B6BF7250231E3000F77FF /* ieee80211_ioctl.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */; }; F89B6BF8250231E3000F77FF /* ieee80211.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3324080319007A9422 /* ieee80211.c */; }; F89B6BF9250231E3000F77FF /* ieee80211_rssadapt.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */; }; F89B6BFA250231E3000F77FF /* ieee80211_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3524080319007A9422 /* ieee80211_input.c */; }; F89B6BFB250231E3000F77FF /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3724080319007A9422 /* timeout.c */; }; F89B6BFC250231E3000F77FF /* ieee80211_mira.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3924080319007A9422 /* ieee80211_mira.c */; }; F89B6BFD250231E3000F77FF /* ieee80211_crypto_bip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */; }; F89B6BFE250231E3000F77FF /* ieee80211_crypto_tkip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */; }; F89B6BFF250231E3000F77FF /* ieee80211_crypto_ccmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */; }; F89B6C00250231E3000F77FF /* ieee80211_crypto_wep.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */; }; F89B6C01250231E3000F77FF /* ieee80211_pae_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */; }; F89B6C02250231E3000F77FF /* ieee80211_amrr.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4024080319007A9422 /* ieee80211_amrr.c */; }; F89B6C03250231E3000F77FF /* ieee80211_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC472408031A007A9422 /* ieee80211_output.c */; }; F89B6C04250231E3000F77FF /* ieee80211_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC482408031A007A9422 /* ieee80211_crypto.c */; }; F89B6C05250231E3000F77FF /* CTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC492408031A007A9422 /* CTimeout.cpp */; }; F89B6C06250231E3000F77FF /* ieee80211_regdomain.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */; }; F89B6C07250231E4000F77FF /* ieee80211_node.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4C2408031A007A9422 /* ieee80211_node.c */; }; F89B6C08250231E4000F77FF /* ieee80211_pae_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */; }; F89B6C09250231E4000F77FF /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */; }; F89B6C0A250231E4000F77FF /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07C923FCBC6C009FBA6C /* aes.c */; }; F89B6C0B250231E4000F77FF /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CA23FCBC6C009FBA6C /* hmac.c */; }; F89B6C0C250231E4000F77FF /* sha2.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CB23FCBC6C009FBA6C /* sha2.c */; }; F89B6C0D250231E4000F77FF /* rijndael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CC23FCBC6C009FBA6C /* rijndael.c */; }; F89B6C0E250231E4000F77FF /* ecb3_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */; }; F89B6C0F250231E4000F77FF /* set_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CE23FCBC6C009FBA6C /* set_key.c */; }; F89B6C10250231E4000F77FF /* cast.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CF23FCBC6C009FBA6C /* cast.c */; }; F89B6C11250231E4000F77FF /* michael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D123FCBC6C009FBA6C /* michael.c */; }; F89B6C12250231E4000F77FF /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D823FCBC6C009FBA6C /* sha1.c */; }; F89B6C13250231E4000F77FF /* cmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07DD23FCBC6C009FBA6C /* cmac.c */; }; F89B6C14250231E4000F77FF /* ecb_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E423FCBC6C009FBA6C /* ecb_enc.c */; }; F89B6C15250231E4000F77FF /* chachapoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E923FCBC6C009FBA6C /* chachapoly.c */; }; F89B6C16250231E4000F77FF /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EA23FCBC6C009FBA6C /* md5.c */; }; F89B6C17250231E4000F77FF /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EB23FCBC6C009FBA6C /* arc4.c */; }; F89B6C18250231E4000F77FF /* blf.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EC23FCBC6C009FBA6C /* blf.c */; }; F89B6C19250231E4000F77FF /* poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07ED23FCBC6C009FBA6C /* poly1305.c */; }; F89B6C1A250231E4000F77FF /* key_wrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F023FCBC6C009FBA6C /* key_wrap.c */; }; F89B6C1B250231E4000F77FF /* gmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F223FCBC6C009FBA6C /* gmac.c */; }; F89B6C1C250231E4000F77FF /* rmd160.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F323FCBC6C009FBA6C /* rmd160.c */; }; F89B6C1D250231E4000F77FF /* idgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F423FCBC6C009FBA6C /* idgen.c */; }; F89B6C1E250231E4000F77FF /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07BA23FCBC6C009FBA6C /* compat.cpp */; }; F89B6C1F250231E4000F77FF /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = F8FA0EED2501E8C100B1822E /* zutil.c */; }; F89B6C20250232DC000F77FF /* _mbuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D257732495A33500872E4F /* _mbuf.cpp */; }; F89B6C21250232DC000F77FF /* _task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8F9EDE0240B7415009CB8E7 /* _task.cpp */; }; F89B6C2325027609000F77FF /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6C2225027609000F77FF /* debug.h */; }; F89F35F22A49867F00061876 /* IO80211ControllerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = F89F35F12A49867F00061876 /* IO80211ControllerV2.h */; }; F89F35F32A49867F00061876 /* IO80211ControllerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = F89F35F12A49867F00061876 /* IO80211ControllerV2.h */; }; F89F35F42A49867F00061876 /* IO80211ControllerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = F89F35F12A49867F00061876 /* IO80211ControllerV2.h */; }; F89F35F52A49867F00061876 /* IO80211ControllerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = F89F35F12A49867F00061876 /* IO80211ControllerV2.h */; }; F89F35F62A49867F00061876 /* IO80211ControllerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = F89F35F12A49867F00061876 /* IO80211ControllerV2.h */; }; F89F35F72A49867F00061876 /* IO80211ControllerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = F89F35F12A49867F00061876 /* IO80211ControllerV2.h */; }; F89F35F82A49867F00061876 /* IO80211ControllerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = F89F35F12A49867F00061876 /* IO80211ControllerV2.h */; }; F8A028222A4A7DDC00C6DE90 /* AirportItlwmV2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8A028202A4A7DDC00C6DE90 /* AirportItlwmV2.cpp */; }; F8A028232A4A7DDC00C6DE90 /* AirportItlwmV2.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8A028212A4A7DDC00C6DE90 /* AirportItlwmV2.hpp */; }; F8A0282F2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8A0282D2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.cpp */; }; F8A028302A4A7E0500C6DE90 /* AirportItlwmEthernetInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8A0282E2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.hpp */; }; F8A028722A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8A028702A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.cpp */; }; F8A028732A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8A028712A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.hpp */; }; F8A0287F2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8A0287D2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.cpp */; }; F8A028802A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8A0287E2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.hpp */; }; F8A4307325062CE300EA545E /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = F8FA0EED2501E8C100B1822E /* zutil.c */; }; F8AE64F9285471560085B4CF /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6C2225027609000F77FF /* debug.h */; }; F8AE64FA285471560085B4CF /* IOSkywalkEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */; }; F8AE64FB285471560085B4CF /* apple80211_ioctl.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */; }; F8AE64FC285471560085B4CF /* IO80211P2PInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */; }; F8AE64FD285471560085B4CF /* IO80211WorkLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */; }; F8AE64FE285471560085B4CF /* apple80211_var.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC425021DEC000F77FF /* apple80211_var.h */; }; F8AE64FF285471560085B4CF /* AirportItlwmInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */; }; F8AE6500285471560085B4CF /* IO80211Interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA38252D834500520FD4 /* IO80211Interface.h */; }; F8AE6501285471560085B4CF /* (null) in Headers */ = {isa = PBXBuildFile; }; F8AE6502285471560085B4CF /* IO80211SkywalkInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */; }; F8AE6503285471560085B4CF /* AirportItlwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */; }; F8AE6504285471560085B4CF /* IO80211VirtualInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */; }; F8AE6505285471560085B4CF /* IO80211Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA35252D834500520FD4 /* IO80211Controller.h */; }; F8AE6506285471560085B4CF /* (null) in Headers */ = {isa = PBXBuildFile; }; F8AE6507285471560085B4CF /* ieee80211_ra.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C594D225FD935B0007D19C /* ieee80211_ra.h */; }; F8AE6508285471560085B4CF /* apple80211_wps.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC325021DEC000F77FF /* apple80211_wps.h */; }; F8AE650A285471560085B4CF /* _mbuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D257732495A33500872E4F /* _mbuf.cpp */; }; F8AE650B285471560085B4CF /* ieee80211_ra.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C594D125FD935B0007D19C /* ieee80211_ra.c */; }; F8AE650C285471560085B4CF /* _task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8F9EDE0240B7415009CB8E7 /* _task.cpp */; }; F8AE650D285471560085B4CF /* FwBinary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */; }; F8AE650F285471560085B4CF /* ieee80211_proto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC2F24080319007A9422 /* ieee80211_proto.c */; }; F8AE6510285471560085B4CF /* AirportItlwmInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8CA44A125091AF60036119A /* AirportItlwmInterface.cpp */; }; F8AE6511285471560085B4CF /* _string.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3024080319007A9422 /* _string.c */; }; F8AE6512285471560085B4CF /* ieee80211_ioctl.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */; }; F8AE6513285471560085B4CF /* ieee80211.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3324080319007A9422 /* ieee80211.c */; }; F8AE6514285471560085B4CF /* ieee80211_rssadapt.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */; }; F8AE6515285471560085B4CF /* ieee80211_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3524080319007A9422 /* ieee80211_input.c */; }; F8AE6516285471560085B4CF /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3724080319007A9422 /* timeout.c */; }; F8AE6517285471560085B4CF /* ieee80211_mira.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3924080319007A9422 /* ieee80211_mira.c */; }; F8AE6518285471560085B4CF /* ieee80211_crypto_bip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */; }; F8AE6519285471560085B4CF /* ieee80211_crypto_tkip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */; }; F8AE651A285471560085B4CF /* ieee80211_crypto_ccmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */; }; F8AE651B285471560085B4CF /* ieee80211_crypto_wep.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */; }; F8AE651C285471560085B4CF /* ieee80211_pae_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */; }; F8AE651D285471560085B4CF /* ieee80211_amrr.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4024080319007A9422 /* ieee80211_amrr.c */; }; F8AE651E285471560085B4CF /* ieee80211_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC472408031A007A9422 /* ieee80211_output.c */; }; F8AE651F285471560085B4CF /* ieee80211_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC482408031A007A9422 /* ieee80211_crypto.c */; }; F8AE6520285471560085B4CF /* CTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC492408031A007A9422 /* CTimeout.cpp */; }; F8AE6521285471560085B4CF /* ieee80211_regdomain.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */; }; F8AE6522285471560085B4CF /* ieee80211_node.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4C2408031A007A9422 /* ieee80211_node.c */; }; F8AE6523285471560085B4CF /* ieee80211_pae_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */; }; F8AE6524285471560085B4CF /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */; }; F8AE6525285471560085B4CF /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07C923FCBC6C009FBA6C /* aes.c */; }; F8AE6526285471560085B4CF /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CA23FCBC6C009FBA6C /* hmac.c */; }; F8AE6527285471560085B4CF /* sha2.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CB23FCBC6C009FBA6C /* sha2.c */; }; F8AE6528285471560085B4CF /* rijndael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CC23FCBC6C009FBA6C /* rijndael.c */; }; F8AE6529285471560085B4CF /* ecb3_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */; }; F8AE652A285471560085B4CF /* set_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CE23FCBC6C009FBA6C /* set_key.c */; }; F8AE652B285471560085B4CF /* cast.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CF23FCBC6C009FBA6C /* cast.c */; }; F8AE652C285471560085B4CF /* michael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D123FCBC6C009FBA6C /* michael.c */; }; F8AE652D285471560085B4CF /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D823FCBC6C009FBA6C /* sha1.c */; }; F8AE652E285471560085B4CF /* cmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07DD23FCBC6C009FBA6C /* cmac.c */; }; F8AE652F285471560085B4CF /* ecb_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E423FCBC6C009FBA6C /* ecb_enc.c */; }; F8AE6530285471560085B4CF /* chachapoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E923FCBC6C009FBA6C /* chachapoly.c */; }; F8AE6531285471560085B4CF /* (null) in Sources */ = {isa = PBXBuildFile; }; F8AE6532285471560085B4CF /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EA23FCBC6C009FBA6C /* md5.c */; }; F8AE6533285471560085B4CF /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EB23FCBC6C009FBA6C /* arc4.c */; }; F8AE6534285471560085B4CF /* blf.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EC23FCBC6C009FBA6C /* blf.c */; }; F8AE6535285471560085B4CF /* poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07ED23FCBC6C009FBA6C /* poly1305.c */; }; F8AE6536285471560085B4CF /* key_wrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F023FCBC6C009FBA6C /* key_wrap.c */; }; F8AE6537285471560085B4CF /* gmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F223FCBC6C009FBA6C /* gmac.c */; }; F8AE6538285471560085B4CF /* rmd160.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F323FCBC6C009FBA6C /* rmd160.c */; }; F8AE6539285471560085B4CF /* idgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F423FCBC6C009FBA6C /* idgen.c */; }; F8AE653A285471560085B4CF /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07BA23FCBC6C009FBA6C /* compat.cpp */; }; F8AE653B285471560085B4CF /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = F8FA0EED2501E8C100B1822E /* zutil.c */; }; F8AE653C285471560085B4CF /* ItlHalService.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D364F624F93AFD0029340B /* ItlHalService.cpp */; }; F8AE653D285471560085B4CF /* ItlIwx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */; }; F8AE653E285471560085B4CF /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BF23FCD4E2009FBA6C /* utils.cpp */; }; F8AE653F285471560085B4CF /* fw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BD23FCD314009FBA6C /* fw.cpp */; }; F8AE6540285471560085B4CF /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C123FCD999009FBA6C /* io.cpp */; }; F8AE6541285471560085B4CF /* rx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C323FCDC14009FBA6C /* rx.cpp */; }; F8AE6542285471560085B4CF /* coex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F837C91C2724577F00B2C499 /* coex.cpp */; }; F8AE6543285471560085B4CF /* tx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C523FCDC3B009FBA6C /* tx.cpp */; }; F8AE6544285471560085B4CF /* hw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C723FCE2ED009FBA6C /* hw.cpp */; }; F8AE6545285471560085B4CF /* ItlIwn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */; }; F8AE6546285471560085B4CF /* phy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C923FCE537009FBA6C /* phy.cpp */; }; F8AE6547285471560085B4CF /* mac80211.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */; }; F8AE6548285471560085B4CF /* nvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CD23FCE67F009FBA6C /* nvm.cpp */; }; F8AE6549285471560085B4CF /* ctxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CF23FCEE88009FBA6C /* ctxt.cpp */; }; F8AE654A285471560085B4CF /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D123FCF395009FBA6C /* led.cpp */; }; F8AE654B285471560085B4CF /* power.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D323FCF3E6009FBA6C /* power.cpp */; }; F8AE654C285471560085B4CF /* scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D523FCF4D7009FBA6C /* scan.cpp */; }; F8AE654D285471560085B4CF /* ItlIwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */; }; F8AE654E285471560085B4CF /* AirportSTAIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDC25022F8C000F77FF /* AirportSTAIOCTL.cpp */; }; F8AE654F285471560085B4CF /* AirportItlwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BBD25021C9C000F77FF /* AirportItlwm.cpp */; }; F8AE6550285471560085B4CF /* AirportVirtualIOCTL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BDE25022FB5000F77FF /* AirportVirtualIOCTL.cpp */; }; F8AE6551285471560085B4CF /* AirportAWDL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F89B6BE025022FC7000F77FF /* AirportAWDL.cpp */; }; F8AE6553285471560085B4CF /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5088ECBC252884870068A63D /* libkmod.a */; }; F8AF3A3124F9F35B008911C1 /* ItlIwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */; }; F8AF3A3224F9F35B008911C1 /* ItlIwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8AF3A3024F9F35B008911C1 /* ItlIwm.hpp */; }; F8B210AB2A2EC2680043ECBD /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6C2225027609000F77FF /* debug.h */; }; F8B210AC2A2EC2680043ECBD /* IOSkywalkEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */; }; F8B210AD2A2EC2680043ECBD /* apple80211_ioctl.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */; }; F8B210AE2A2EC2680043ECBD /* IO80211P2PInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */; }; F8B210AF2A2EC2680043ECBD /* IO80211WorkLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */; }; F8B210B02A2EC2680043ECBD /* apple80211_var.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC425021DEC000F77FF /* apple80211_var.h */; }; F8B210B12A2EC2680043ECBD /* AirportItlwmInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */; }; F8B210B22A2EC2680043ECBD /* IO80211Interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA38252D834500520FD4 /* IO80211Interface.h */; }; F8B210B32A2EC2680043ECBD /* (null) in Headers */ = {isa = PBXBuildFile; }; F8B210B42A2EC2680043ECBD /* IO80211SkywalkInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */; }; F8B210B52A2EC2680043ECBD /* AirportItlwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */; }; F8B210B62A2EC2680043ECBD /* IO80211VirtualInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */; }; F8B210B72A2EC2680043ECBD /* IO80211Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA35252D834500520FD4 /* IO80211Controller.h */; }; F8B210B82A2EC2680043ECBD /* (null) in Headers */ = {isa = PBXBuildFile; }; F8B210B92A2EC2680043ECBD /* ieee80211_ra.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C594D225FD935B0007D19C /* ieee80211_ra.h */; }; F8B210BA2A2EC2680043ECBD /* apple80211_wps.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC325021DEC000F77FF /* apple80211_wps.h */; }; F8B210BC2A2EC2680043ECBD /* _mbuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D257732495A33500872E4F /* _mbuf.cpp */; }; F8B210BD2A2EC2680043ECBD /* ieee80211_ra.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C594D125FD935B0007D19C /* ieee80211_ra.c */; }; F8B210BE2A2EC2680043ECBD /* _task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8F9EDE0240B7415009CB8E7 /* _task.cpp */; }; F8B210BF2A2EC2680043ECBD /* FwBinary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */; }; F8B210C02A2EC2680043ECBD /* ieee80211_proto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC2F24080319007A9422 /* ieee80211_proto.c */; }; F8B210C22A2EC2680043ECBD /* _string.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3024080319007A9422 /* _string.c */; }; F8B210C32A2EC2680043ECBD /* ieee80211_ioctl.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */; }; F8B210C42A2EC2680043ECBD /* ieee80211.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3324080319007A9422 /* ieee80211.c */; }; F8B210C52A2EC2680043ECBD /* ieee80211_rssadapt.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */; }; F8B210C62A2EC2680043ECBD /* ieee80211_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3524080319007A9422 /* ieee80211_input.c */; }; F8B210C72A2EC2680043ECBD /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3724080319007A9422 /* timeout.c */; }; F8B210C82A2EC2680043ECBD /* ieee80211_mira.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3924080319007A9422 /* ieee80211_mira.c */; }; F8B210C92A2EC2680043ECBD /* ieee80211_crypto_bip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */; }; F8B210CA2A2EC2680043ECBD /* ieee80211_crypto_tkip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */; }; F8B210CB2A2EC2680043ECBD /* ieee80211_crypto_ccmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */; }; F8B210CC2A2EC2680043ECBD /* ieee80211_crypto_wep.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */; }; F8B210CD2A2EC2680043ECBD /* ieee80211_pae_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */; }; F8B210CE2A2EC2680043ECBD /* ieee80211_amrr.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4024080319007A9422 /* ieee80211_amrr.c */; }; F8B210CF2A2EC2680043ECBD /* ieee80211_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC472408031A007A9422 /* ieee80211_output.c */; }; F8B210D02A2EC2680043ECBD /* ieee80211_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC482408031A007A9422 /* ieee80211_crypto.c */; }; F8B210D12A2EC2680043ECBD /* CTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC492408031A007A9422 /* CTimeout.cpp */; }; F8B210D22A2EC2680043ECBD /* ieee80211_regdomain.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */; }; F8B210D32A2EC2680043ECBD /* ieee80211_node.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4C2408031A007A9422 /* ieee80211_node.c */; }; F8B210D42A2EC2680043ECBD /* ieee80211_pae_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */; }; F8B210D52A2EC2680043ECBD /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */; }; F8B210D62A2EC2680043ECBD /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07C923FCBC6C009FBA6C /* aes.c */; }; F8B210D72A2EC2680043ECBD /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CA23FCBC6C009FBA6C /* hmac.c */; }; F8B210D82A2EC2680043ECBD /* sha2.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CB23FCBC6C009FBA6C /* sha2.c */; }; F8B210D92A2EC2680043ECBD /* rijndael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CC23FCBC6C009FBA6C /* rijndael.c */; }; F8B210DA2A2EC2680043ECBD /* ecb3_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */; }; F8B210DB2A2EC2680043ECBD /* set_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CE23FCBC6C009FBA6C /* set_key.c */; }; F8B210DC2A2EC2680043ECBD /* cast.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CF23FCBC6C009FBA6C /* cast.c */; }; F8B210DD2A2EC2680043ECBD /* michael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D123FCBC6C009FBA6C /* michael.c */; }; F8B210DE2A2EC2680043ECBD /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D823FCBC6C009FBA6C /* sha1.c */; }; F8B210DF2A2EC2680043ECBD /* cmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07DD23FCBC6C009FBA6C /* cmac.c */; }; F8B210E02A2EC2680043ECBD /* ecb_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E423FCBC6C009FBA6C /* ecb_enc.c */; }; F8B210E12A2EC2680043ECBD /* chachapoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E923FCBC6C009FBA6C /* chachapoly.c */; }; F8B210E22A2EC2680043ECBD /* (null) in Sources */ = {isa = PBXBuildFile; }; F8B210E32A2EC2680043ECBD /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EA23FCBC6C009FBA6C /* md5.c */; }; F8B210E42A2EC2680043ECBD /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EB23FCBC6C009FBA6C /* arc4.c */; }; F8B210E52A2EC2680043ECBD /* blf.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EC23FCBC6C009FBA6C /* blf.c */; }; F8B210E62A2EC2680043ECBD /* _ifq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FA2AE328A797B200847103 /* _ifq.cpp */; }; F8B210E72A2EC2680043ECBD /* poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07ED23FCBC6C009FBA6C /* poly1305.c */; }; F8B210E82A2EC2680043ECBD /* key_wrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F023FCBC6C009FBA6C /* key_wrap.c */; }; F8B210E92A2EC2680043ECBD /* gmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F223FCBC6C009FBA6C /* gmac.c */; }; F8B210EA2A2EC2680043ECBD /* rmd160.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F323FCBC6C009FBA6C /* rmd160.c */; }; F8B210EB2A2EC2680043ECBD /* idgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F423FCBC6C009FBA6C /* idgen.c */; }; F8B210EC2A2EC2680043ECBD /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07BA23FCBC6C009FBA6C /* compat.cpp */; }; F8B210ED2A2EC2680043ECBD /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = F8FA0EED2501E8C100B1822E /* zutil.c */; }; F8B210EE2A2EC2680043ECBD /* ItlHalService.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D364F624F93AFD0029340B /* ItlHalService.cpp */; }; F8B210EF2A2EC2680043ECBD /* ItlIwx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */; }; F8B210F02A2EC2680043ECBD /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BF23FCD4E2009FBA6C /* utils.cpp */; }; F8B210F12A2EC2680043ECBD /* fw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BD23FCD314009FBA6C /* fw.cpp */; }; F8B210F22A2EC2680043ECBD /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C123FCD999009FBA6C /* io.cpp */; }; F8B210F32A2EC2680043ECBD /* rx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C323FCDC14009FBA6C /* rx.cpp */; }; F8B210F42A2EC2680043ECBD /* coex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F837C91C2724577F00B2C499 /* coex.cpp */; }; F8B210F52A2EC2680043ECBD /* tx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C523FCDC3B009FBA6C /* tx.cpp */; }; F8B210F62A2EC2680043ECBD /* hw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C723FCE2ED009FBA6C /* hw.cpp */; }; F8B210F72A2EC2680043ECBD /* ItlIwn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */; }; F8B210F82A2EC2680043ECBD /* phy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C923FCE537009FBA6C /* phy.cpp */; }; F8B210F92A2EC2680043ECBD /* mac80211.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */; }; F8B210FA2A2EC2680043ECBD /* nvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CD23FCE67F009FBA6C /* nvm.cpp */; }; F8B210FB2A2EC2680043ECBD /* ctxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CF23FCEE88009FBA6C /* ctxt.cpp */; }; F8B210FC2A2EC2680043ECBD /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D123FCF395009FBA6C /* led.cpp */; }; F8B210FD2A2EC2680043ECBD /* power.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D323FCF3E6009FBA6C /* power.cpp */; }; F8B210FE2A2EC2680043ECBD /* scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D523FCF4D7009FBA6C /* scan.cpp */; }; F8B210FF2A2EC2680043ECBD /* ItlIwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */; }; F8B211052A2EC2680043ECBD /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5088ECBC252884870068A63D /* libkmod.a */; }; F8C2EC4F2408031A007A9422 /* ieee80211_proto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC2F24080319007A9422 /* ieee80211_proto.c */; }; F8C2EC502408031A007A9422 /* _string.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3024080319007A9422 /* _string.c */; }; F8C2EC512408031A007A9422 /* ieee80211_amrr.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC3124080319007A9422 /* ieee80211_amrr.h */; }; F8C2EC522408031A007A9422 /* ieee80211_ioctl.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */; }; F8C2EC532408031A007A9422 /* ieee80211.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3324080319007A9422 /* ieee80211.c */; }; F8C2EC542408031A007A9422 /* ieee80211_rssadapt.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */; }; F8C2EC552408031A007A9422 /* ieee80211_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3524080319007A9422 /* ieee80211_input.c */; }; F8C2EC562408031A007A9422 /* ieee80211_node.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC3624080319007A9422 /* ieee80211_node.h */; }; F8C2EC572408031A007A9422 /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3724080319007A9422 /* timeout.c */; }; F8C2EC582408031A007A9422 /* ieee80211_regdomain.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC3824080319007A9422 /* ieee80211_regdomain.h */; }; F8C2EC592408031A007A9422 /* ieee80211_mira.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3924080319007A9422 /* ieee80211_mira.c */; }; F8C2EC5A2408031A007A9422 /* ieee80211_crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC3A24080319007A9422 /* ieee80211_crypto.h */; }; F8C2EC5B2408031A007A9422 /* ieee80211_crypto_bip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */; }; F8C2EC5C2408031A007A9422 /* ieee80211_crypto_tkip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */; }; F8C2EC5D2408031A007A9422 /* ieee80211_crypto_ccmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */; }; F8C2EC5E2408031A007A9422 /* ieee80211_pae_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */; }; F8C2EC5F2408031A007A9422 /* ieee80211_radiotap.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC3F24080319007A9422 /* ieee80211_radiotap.h */; }; F8C2EC602408031A007A9422 /* ieee80211_amrr.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4024080319007A9422 /* ieee80211_amrr.c */; }; F8C2EC612408031A007A9422 /* ieee80211_proto.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC4124080319007A9422 /* ieee80211_proto.h */; }; F8C2EC622408031A007A9422 /* ieee80211_rssadapt.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC422408031A007A9422 /* ieee80211_rssadapt.h */; }; F8C2EC632408031A007A9422 /* ieee80211.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC432408031A007A9422 /* ieee80211.h */; }; F8C2EC642408031A007A9422 /* ieee80211_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC442408031A007A9422 /* ieee80211_priv.h */; }; F8C2EC652408031A007A9422 /* ieee80211_ioctl.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC452408031A007A9422 /* ieee80211_ioctl.h */; }; F8C2EC662408031A007A9422 /* ieee80211_crypto_wep.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */; }; F8C2EC672408031A007A9422 /* ieee80211_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC472408031A007A9422 /* ieee80211_output.c */; }; F8C2EC682408031A007A9422 /* ieee80211_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC482408031A007A9422 /* ieee80211_crypto.c */; }; F8C2EC692408031A007A9422 /* CTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC492408031A007A9422 /* CTimeout.cpp */; }; F8C2EC6A2408031A007A9422 /* ieee80211_mira.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC4A2408031A007A9422 /* ieee80211_mira.h */; }; F8C2EC6B2408031A007A9422 /* ieee80211_regdomain.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */; }; F8C2EC6C2408031A007A9422 /* ieee80211_node.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4C2408031A007A9422 /* ieee80211_node.c */; }; F8C2EC6D2408031A007A9422 /* ieee80211_pae_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */; }; F8C2EC6E2408031A007A9422 /* ieee80211_var.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC4E2408031A007A9422 /* ieee80211_var.h */; }; F8C2EC9124080557007A9422 /* _buf.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC8724080556007A9422 /* _buf.h */; }; F8C2EC9224080557007A9422 /* CTimeout.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC8824080556007A9422 /* CTimeout.hpp */; }; F8C2EC9324080557007A9422 /* _arc4random.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC8924080556007A9422 /* _arc4random.h */; }; F8C2EC9424080557007A9422 /* endian.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC8A24080556007A9422 /* endian.h */; }; F8C2EC9524080557007A9422 /* _mbuf.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC8B24080556007A9422 /* _mbuf.h */; }; F8C2EC9624080557007A9422 /* _if_ether.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC8C24080556007A9422 /* _if_ether.h */; }; F8C2EC9724080557007A9422 /* tree.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC8D24080556007A9422 /* tree.h */; }; F8C2EC9824080557007A9422 /* _if_media.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC8E24080556007A9422 /* _if_media.h */; }; F8C2EC9924080557007A9422 /* _null.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC8F24080556007A9422 /* _null.h */; }; F8C2EC9A24080557007A9422 /* timeout.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC9024080556007A9422 /* timeout.h */; }; F8C2EC9C2408062D007A9422 /* pcireg.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C2EC9B2408062D007A9422 /* pcireg.h */; }; F8C594D325FD935B0007D19C /* ieee80211_ra.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C594D125FD935B0007D19C /* ieee80211_ra.c */; }; F8C594D425FD935B0007D19C /* ieee80211_ra.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C594D125FD935B0007D19C /* ieee80211_ra.c */; }; F8C594D525FD935B0007D19C /* ieee80211_ra.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C594D125FD935B0007D19C /* ieee80211_ra.c */; }; F8C594D625FD935B0007D19C /* ieee80211_ra.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C594D125FD935B0007D19C /* ieee80211_ra.c */; }; F8C594D725FD935B0007D19C /* ieee80211_ra.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C594D125FD935B0007D19C /* ieee80211_ra.c */; }; F8C594D825FD935B0007D19C /* ieee80211_ra.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C594D225FD935B0007D19C /* ieee80211_ra.h */; }; F8C594D925FD935B0007D19C /* ieee80211_ra.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C594D225FD935B0007D19C /* ieee80211_ra.h */; }; F8C594DA25FD935B0007D19C /* ieee80211_ra.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C594D225FD935B0007D19C /* ieee80211_ra.h */; }; F8C594DB25FD935B0007D19C /* ieee80211_ra.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C594D225FD935B0007D19C /* ieee80211_ra.h */; }; F8C594DC25FD935B0007D19C /* ieee80211_ra.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C594D225FD935B0007D19C /* ieee80211_ra.h */; }; F8C772922443439A00A1B8A0 /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07BA23FCBC6C009FBA6C /* compat.cpp */; }; F8CA44A325091AF60036119A /* AirportItlwmInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8CA44A125091AF60036119A /* AirportItlwmInterface.cpp */; }; F8CA44A425091AF60036119A /* AirportItlwmInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */; }; F8D257742495A33500872E4F /* _mbuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D257732495A33500872E4F /* _mbuf.cpp */; }; F8D257782495DEFC00872E4F /* Common.h in Headers */ = {isa = PBXBuildFile; fileRef = F8D257762495DEFC00872E4F /* Common.h */; }; F8D2577A2495DEFC00872E4F /* IoctlId.h in Headers */ = {isa = PBXBuildFile; fileRef = F8D257772495DEFC00872E4F /* IoctlId.h */; }; F8D364F824F93AFD0029340B /* ItlHalService.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D364F624F93AFD0029340B /* ItlHalService.cpp */; }; F8D364FA24F93AFD0029340B /* ItlHalService.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8D364F724F93AFD0029340B /* ItlHalService.hpp */; }; F8D76362244F21BB00DEA040 /* pm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D76361244F21BB00DEA040 /* pm.cpp */; }; F8D94C842B9ABFE20081A3C4 /* CCDataPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8812A497DB200DC8DED /* CCDataPipe.h */; }; F8D94C852B9ABFE20081A3C4 /* debug.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6C2225027609000F77FF /* debug.h */; }; F8D94C862B9ABFE20081A3C4 /* IOSkywalkEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */; }; F8D94C872B9ABFE20081A3C4 /* IO80211InfraProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */; }; F8D94C882B9ABFE20081A3C4 /* IOSkywalkLogicalLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */; }; F8D94C892B9ABFE20081A3C4 /* AirportItlwmEthernetInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8A0282E2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.hpp */; }; F8D94C8A2B9ABFE20081A3C4 /* IOSkywalkNetworkPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */; }; F8D94C8B2B9ABFE20081A3C4 /* apple80211_ioctl.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */; }; F8D94C8C2B9ABFE20081A3C4 /* CCLogPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8852A497DB200DC8DED /* CCLogPipe.h */; }; F8D94C8D2B9ABFE20081A3C4 /* IO80211P2PInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */; }; F8D94C8E2B9ABFE20081A3C4 /* CCPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87D2A497DB200DC8DED /* CCPipe.h */; }; F8D94C8F2B9ABFE20081A3C4 /* IO80211WorkLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */; }; F8D94C902B9ABFE20081A3C4 /* apple80211_var.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC425021DEC000F77FF /* apple80211_var.h */; }; F8D94C912B9ABFE20081A3C4 /* IOSkywalkPacketBufferPool.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */; }; F8D94C922B9ABFE20081A3C4 /* IOSkywalkLegacyEthernetInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */; }; F8D94C932B9ABFE20081A3C4 /* AirportItlwmInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */; }; F8D94C942B9ABFE20081A3C4 /* IO80211Interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA38252D834500520FD4 /* IO80211Interface.h */; }; F8D94C952B9ABFE20081A3C4 /* IO80211WorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */; }; F8D94C962B9ABFE20081A3C4 /* (null) in Headers */ = {isa = PBXBuildFile; }; F8D94C972B9ABFE20081A3C4 /* IO80211InfraInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */; }; F8D94C982B9ABFE20081A3C4 /* IO80211SkywalkInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */; }; F8D94C992B9ABFE20081A3C4 /* CCLogStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8822A497DB200DC8DED /* CCLogStream.h */; }; F8D94C9A2B9ABFE20081A3C4 /* AirportItlwmSkywalkInterface.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8A028712A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.hpp */; }; F8D94C9B2B9ABFE20081A3C4 /* AirportItlwm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */; }; F8D94C9C2B9ABFE20081A3C4 /* IO80211ControllerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = F89F35F12A49867F00061876 /* IO80211ControllerV2.h */; }; F8D94C9D2B9ABFE20081A3C4 /* IOPCIEDeviceWrapper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8A0287E2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.hpp */; }; F8D94C9E2B9ABFE20081A3C4 /* IO80211VirtualInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */; }; F8D94C9F2B9ABFE20081A3C4 /* IO80211Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA35252D834500520FD4 /* IO80211Controller.h */; }; F8D94CA02B9ABFE20081A3C4 /* (null) in Headers */ = {isa = PBXBuildFile; }; F8D94CA12B9ABFE20081A3C4 /* AirportItlwmV2.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8A028212A4A7DDC00C6DE90 /* AirportItlwmV2.hpp */; }; F8D94CA22B9ABFE20081A3C4 /* ieee80211_ra.h in Headers */ = {isa = PBXBuildFile; fileRef = F8C594D225FD935B0007D19C /* ieee80211_ra.h */; }; F8D94CA32B9ABFE20081A3C4 /* CCStream.h in Headers */ = {isa = PBXBuildFile; fileRef = F84AD8802A497DB200DC8DED /* CCStream.h */; }; F8D94CA42B9ABFE20081A3C4 /* apple80211_wps.h in Headers */ = {isa = PBXBuildFile; fileRef = F89B6BC325021DEC000F77FF /* apple80211_wps.h */; }; F8D94CA62B9ABFE20081A3C4 /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DD111326D93B5F00BA01EF /* rs.cpp */; }; F8D94CA72B9ABFE20081A3C4 /* _mbuf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D257732495A33500872E4F /* _mbuf.cpp */; }; F8D94CA82B9ABFE20081A3C4 /* ieee80211_ra.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C594D125FD935B0007D19C /* ieee80211_ra.c */; }; F8D94CA92B9ABFE20081A3C4 /* _task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8F9EDE0240B7415009CB8E7 /* _task.cpp */; }; F8D94CAA2B9ABFE20081A3C4 /* FwBinary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */; }; F8D94CAB2B9ABFE20081A3C4 /* ieee80211_proto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC2F24080319007A9422 /* ieee80211_proto.c */; }; F8D94CAC2B9ABFE20081A3C4 /* _string.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3024080319007A9422 /* _string.c */; }; F8D94CAD2B9ABFE20081A3C4 /* ieee80211_ioctl.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */; }; F8D94CAE2B9ABFE20081A3C4 /* ieee80211.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3324080319007A9422 /* ieee80211.c */; }; F8D94CAF2B9ABFE20081A3C4 /* ieee80211_rssadapt.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */; }; F8D94CB02B9ABFE20081A3C4 /* ieee80211_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3524080319007A9422 /* ieee80211_input.c */; }; F8D94CB12B9ABFE20081A3C4 /* timeout.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3724080319007A9422 /* timeout.c */; }; F8D94CB22B9ABFE20081A3C4 /* ieee80211_mira.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3924080319007A9422 /* ieee80211_mira.c */; }; F8D94CB32B9ABFE20081A3C4 /* ieee80211_crypto_bip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */; }; F8D94CB42B9ABFE20081A3C4 /* ieee80211_crypto_tkip.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */; }; F8D94CB52B9ABFE20081A3C4 /* ieee80211_crypto_ccmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */; }; F8D94CB62B9ABFE20081A3C4 /* ieee80211_crypto_wep.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */; }; F8D94CB72B9ABFE20081A3C4 /* ieee80211_pae_input.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */; }; F8D94CB82B9ABFE20081A3C4 /* ieee80211_amrr.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4024080319007A9422 /* ieee80211_amrr.c */; }; F8D94CB92B9ABFE20081A3C4 /* ieee80211_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC472408031A007A9422 /* ieee80211_output.c */; }; F8D94CBA2B9ABFE20081A3C4 /* ieee80211_crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC482408031A007A9422 /* ieee80211_crypto.c */; }; F8D94CBB2B9ABFE20081A3C4 /* CTimeout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC492408031A007A9422 /* CTimeout.cpp */; }; F8D94CBC2B9ABFE20081A3C4 /* ieee80211_regdomain.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */; }; F8D94CBD2B9ABFE20081A3C4 /* ieee80211_node.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4C2408031A007A9422 /* ieee80211_node.c */; }; F8D94CBE2B9ABFE20081A3C4 /* ieee80211_pae_output.c in Sources */ = {isa = PBXBuildFile; fileRef = F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */; }; F8D94CBF2B9ABFE20081A3C4 /* sha1-pbkdf2.c in Sources */ = {isa = PBXBuildFile; fileRef = F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */; }; F8D94CC02B9ABFE20081A3C4 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07C923FCBC6C009FBA6C /* aes.c */; }; F8D94CC12B9ABFE20081A3C4 /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CA23FCBC6C009FBA6C /* hmac.c */; }; F8D94CC22B9ABFE20081A3C4 /* sha2.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CB23FCBC6C009FBA6C /* sha2.c */; }; F8D94CC32B9ABFE20081A3C4 /* rijndael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CC23FCBC6C009FBA6C /* rijndael.c */; }; F8D94CC42B9ABFE20081A3C4 /* ecb3_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */; }; F8D94CC52B9ABFE20081A3C4 /* set_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CE23FCBC6C009FBA6C /* set_key.c */; }; F8D94CC62B9ABFE20081A3C4 /* cast.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07CF23FCBC6C009FBA6C /* cast.c */; }; F8D94CC72B9ABFE20081A3C4 /* michael.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D123FCBC6C009FBA6C /* michael.c */; }; F8D94CC82B9ABFE20081A3C4 /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = A5A0C5232A501E6800EF9328 /* arp.c */; }; F8D94CC92B9ABFE20081A3C4 /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07D823FCBC6C009FBA6C /* sha1.c */; }; F8D94CCA2B9ABFE20081A3C4 /* cmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07DD23FCBC6C009FBA6C /* cmac.c */; }; F8D94CCB2B9ABFE20081A3C4 /* ecb_enc.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E423FCBC6C009FBA6C /* ecb_enc.c */; }; F8D94CCC2B9ABFE20081A3C4 /* chachapoly.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07E923FCBC6C009FBA6C /* chachapoly.c */; }; F8D94CCD2B9ABFE20081A3C4 /* AirportItlwmV2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8A028202A4A7DDC00C6DE90 /* AirportItlwmV2.cpp */; }; F8D94CCE2B9ABFE20081A3C4 /* (null) in Sources */ = {isa = PBXBuildFile; }; F8D94CCF2B9ABFE20081A3C4 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EA23FCBC6C009FBA6C /* md5.c */; }; F8D94CD02B9ABFE20081A3C4 /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EB23FCBC6C009FBA6C /* arc4.c */; }; F8D94CD12B9ABFE20081A3C4 /* AirportItlwmEthernetInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8A0282D2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.cpp */; }; F8D94CD22B9ABFE20081A3C4 /* AirportItlwmSkywalkInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8A028702A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.cpp */; }; F8D94CD32B9ABFE20081A3C4 /* blf.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07EC23FCBC6C009FBA6C /* blf.c */; }; F8D94CD42B9ABFE20081A3C4 /* _ifq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5FA2AE328A797B200847103 /* _ifq.cpp */; }; F8D94CD52B9ABFE20081A3C4 /* poly1305.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07ED23FCBC6C009FBA6C /* poly1305.c */; }; F8D94CD62B9ABFE20081A3C4 /* key_wrap.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F023FCBC6C009FBA6C /* key_wrap.c */; }; F8D94CD72B9ABFE20081A3C4 /* gmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F223FCBC6C009FBA6C /* gmac.c */; }; F8D94CD82B9ABFE20081A3C4 /* rmd160.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F323FCBC6C009FBA6C /* rmd160.c */; }; F8D94CD92B9ABFE20081A3C4 /* idgen.c in Sources */ = {isa = PBXBuildFile; fileRef = 024A07F423FCBC6C009FBA6C /* idgen.c */; }; F8D94CDA2B9ABFE20081A3C4 /* compat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A07BA23FCBC6C009FBA6C /* compat.cpp */; }; F8D94CDB2B9ABFE20081A3C4 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = F8FA0EED2501E8C100B1822E /* zutil.c */; }; F8D94CDC2B9ABFE20081A3C4 /* ItlHalService.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D364F624F93AFD0029340B /* ItlHalService.cpp */; }; F8D94CDD2B9ABFE20081A3C4 /* ItlIwx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */; }; F8D94CDE2B9ABFE20081A3C4 /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BF23FCD4E2009FBA6C /* utils.cpp */; }; F8D94CDF2B9ABFE20081A3C4 /* fw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08BD23FCD314009FBA6C /* fw.cpp */; }; F8D94CE02B9ABFE20081A3C4 /* io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C123FCD999009FBA6C /* io.cpp */; }; F8D94CE12B9ABFE20081A3C4 /* rx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C323FCDC14009FBA6C /* rx.cpp */; }; F8D94CE22B9ABFE20081A3C4 /* coex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F837C91C2724577F00B2C499 /* coex.cpp */; }; F8D94CE32B9ABFE20081A3C4 /* tx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C523FCDC3B009FBA6C /* tx.cpp */; }; F8D94CE42B9ABFE20081A3C4 /* hw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C723FCE2ED009FBA6C /* hw.cpp */; }; F8D94CE52B9ABFE20081A3C4 /* ItlIwn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */; }; F8D94CE62B9ABFE20081A3C4 /* phy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08C923FCE537009FBA6C /* phy.cpp */; }; F8D94CE72B9ABFE20081A3C4 /* mac80211.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */; }; F8D94CE82B9ABFE20081A3C4 /* nvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CD23FCE67F009FBA6C /* nvm.cpp */; }; F8D94CE92B9ABFE20081A3C4 /* ctxt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08CF23FCEE88009FBA6C /* ctxt.cpp */; }; F8D94CEA2B9ABFE20081A3C4 /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D123FCF395009FBA6C /* led.cpp */; }; F8D94CEB2B9ABFE20081A3C4 /* power.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D323FCF3E6009FBA6C /* power.cpp */; }; F8D94CEC2B9ABFE20081A3C4 /* scan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 024A08D523FCF4D7009FBA6C /* scan.cpp */; }; F8D94CED2B9ABFE20081A3C4 /* IOPCIEDeviceWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8A0287D2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.cpp */; }; F8D94CEE2B9ABFE20081A3C4 /* ItlIwm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */; }; F8D94CF02B9ABFE20081A3C4 /* libkmod.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5088ECBC252884870068A63D /* libkmod.a */; }; F8E49A14249B923500BE6868 /* ItlNetworkUserClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8E49A12249B923500BE6868 /* ItlNetworkUserClient.cpp */; }; F8E49A15249B923500BE6868 /* ItlNetworkUserClient.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F8E49A13249B923500BE6868 /* ItlNetworkUserClient.hpp */; }; F8ED134424FBB5B70068C831 /* ItlIwx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */; }; F8F7EA3A252D834600520FD4 /* IO80211VirtualInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */; }; F8F7EA3B252D834600520FD4 /* IO80211VirtualInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */; }; F8F7EA3C252D834600520FD4 /* IO80211VirtualInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */; }; F8F7EA3D252D834600520FD4 /* IO80211VirtualInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */; }; F8F7EA3E252D834600520FD4 /* IO80211Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA35252D834500520FD4 /* IO80211Controller.h */; }; F8F7EA3F252D834600520FD4 /* IO80211Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA35252D834500520FD4 /* IO80211Controller.h */; }; F8F7EA40252D834600520FD4 /* IO80211Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA35252D834500520FD4 /* IO80211Controller.h */; }; F8F7EA41252D834600520FD4 /* IO80211Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA35252D834500520FD4 /* IO80211Controller.h */; }; F8F7EA42252D834600520FD4 /* IO80211P2PInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */; }; F8F7EA43252D834600520FD4 /* IO80211P2PInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */; }; F8F7EA44252D834600520FD4 /* IO80211P2PInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */; }; F8F7EA45252D834600520FD4 /* IO80211P2PInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */; }; F8F7EA46252D834600520FD4 /* IO80211SkywalkInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */; }; F8F7EA47252D834600520FD4 /* IO80211SkywalkInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */; }; F8F7EA48252D834600520FD4 /* IO80211SkywalkInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */; }; F8F7EA49252D834600520FD4 /* IO80211SkywalkInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */; }; F8F7EA4A252D834600520FD4 /* IO80211Interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA38252D834500520FD4 /* IO80211Interface.h */; }; F8F7EA4B252D834600520FD4 /* IO80211Interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA38252D834500520FD4 /* IO80211Interface.h */; }; F8F7EA4C252D834600520FD4 /* IO80211Interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA38252D834500520FD4 /* IO80211Interface.h */; }; F8F7EA4D252D834600520FD4 /* IO80211Interface.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA38252D834500520FD4 /* IO80211Interface.h */; }; F8F7EA4E252D834600520FD4 /* IO80211WorkLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */; }; F8F7EA4F252D834600520FD4 /* IO80211WorkLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */; }; F8F7EA50252D834600520FD4 /* IO80211WorkLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */; }; F8F7EA51252D834600520FD4 /* IO80211WorkLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */; }; F8F84F682ADE26F1002808DE /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5DD111326D93B5F00BA01EF /* rs.cpp */; }; F8F9257E240974EF0088B8D5 /* bitfield.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F92573240974EE0088B8D5 /* bitfield.h */; }; F8F9257F240974EF0088B8D5 /* kernel.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F92574240974EE0088B8D5 /* kernel.h */; }; F8F92583240974EF0088B8D5 /* random.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F92578240974EE0088B8D5 /* random.h */; }; F8F92586240974EF0088B8D5 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = F8F9257B240974EF0088B8D5 /* types.h */; }; F8F9EDE1240B7415009CB8E7 /* _task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F8F9EDE0240B7415009CB8E7 /* _task.cpp */; }; F8FA0EEC2501E7EE00B1822E /* zutil.h in Headers */ = {isa = PBXBuildFile; fileRef = F8FA0EEB2501E7EE00B1822E /* zutil.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 5066D63D252880A700EE6F38 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 024A07A323FCBC3C009FBA6C /* Project object */; proxyType = 1; remoteGlobalIDString = 5066D63825287F7900EE6F38; remoteInfo = fw_gen; }; 5066D63F252880AD00EE6F38 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 024A07A323FCBC3C009FBA6C /* Project object */; proxyType = 1; remoteGlobalIDString = 5066D63825287F7900EE6F38; remoteInfo = fw_gen; }; 5066D6412528814000EE6F38 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 024A07A323FCBC3C009FBA6C /* Project object */; proxyType = 1; remoteGlobalIDString = 5066D63825287F7900EE6F38; remoteInfo = fw_gen; }; 5066D6432528814400EE6F38 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 024A07A323FCBC3C009FBA6C /* Project object */; proxyType = 1; remoteGlobalIDString = 5066D63825287F7900EE6F38; remoteInfo = fw_gen; }; 5066D6452528814900EE6F38 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 024A07A323FCBC3C009FBA6C /* Project object */; proxyType = 1; remoteGlobalIDString = 5066D63825287F7900EE6F38; remoteInfo = fw_gen; }; F897ECB8266EFF93005EE8F7 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 024A07A323FCBC3C009FBA6C /* Project object */; proxyType = 1; remoteGlobalIDString = 5066D63825287F7900EE6F38; remoteInfo = fw_gen; }; F8AE64F7285471560085B4CF /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 024A07A323FCBC3C009FBA6C /* Project object */; proxyType = 1; remoteGlobalIDString = 5066D63825287F7900EE6F38; remoteInfo = fw_gen; }; F8B210A92A2EC2680043ECBD /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 024A07A323FCBC3C009FBA6C /* Project object */; proxyType = 1; remoteGlobalIDString = 5066D63825287F7900EE6F38; remoteInfo = fw_gen; }; F8D94C822B9ABFE20081A3C4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 024A07A323FCBC3C009FBA6C /* Project object */; proxyType = 1; remoteGlobalIDString = 5066D63825287F7900EE6F38; remoteInfo = fw_gen; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 024A07AC23FCBC3C009FBA6C /* itlwm.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = itlwm.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 024A07AF23FCBC3C009FBA6C /* itlwm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = itlwm.hpp; sourceTree = ""; }; 024A07B123FCBC3C009FBA6C /* itlwm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = itlwm.cpp; sourceTree = ""; }; 024A07B323FCBC3C009FBA6C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 024A07BA23FCBC6C009FBA6C /* compat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compat.cpp; sourceTree = ""; }; 024A07C923FCBC6C009FBA6C /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = ""; }; 024A07CA23FCBC6C009FBA6C /* hmac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hmac.c; sourceTree = ""; }; 024A07CB23FCBC6C009FBA6C /* sha2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sha2.c; sourceTree = ""; }; 024A07CC23FCBC6C009FBA6C /* rijndael.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rijndael.c; sourceTree = ""; }; 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ecb3_enc.c; sourceTree = ""; }; 024A07CE23FCBC6C009FBA6C /* set_key.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = set_key.c; sourceTree = ""; }; 024A07CF23FCBC6C009FBA6C /* cast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cast.c; sourceTree = ""; }; 024A07D023FCBC6C009FBA6C /* des_locl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = des_locl.h; sourceTree = ""; }; 024A07D123FCBC6C009FBA6C /* michael.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = michael.c; sourceTree = ""; }; 024A07D223FCBC6C009FBA6C /* key_wrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = key_wrap.h; sourceTree = ""; }; 024A07D323FCBC6C009FBA6C /* poly1305.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = poly1305.h; sourceTree = ""; }; 024A07D423FCBC6C009FBA6C /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = ""; }; 024A07D523FCBC6C009FBA6C /* blf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blf.h; sourceTree = ""; }; 024A07D623FCBC6C009FBA6C /* arc4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arc4.h; sourceTree = ""; }; 024A07D723FCBC6C009FBA6C /* chachapoly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chachapoly.h; sourceTree = ""; }; 024A07D823FCBC6C009FBA6C /* sha1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sha1.c; sourceTree = ""; }; 024A07D923FCBC6C009FBA6C /* sk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sk.h; sourceTree = ""; }; 024A07DA23FCBC6C009FBA6C /* castsb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = castsb.h; sourceTree = ""; }; 024A07DB23FCBC6C009FBA6C /* rmd160.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rmd160.h; sourceTree = ""; }; 024A07DC23FCBC6C009FBA6C /* idgen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = idgen.h; sourceTree = ""; }; 024A07DD23FCBC6C009FBA6C /* cmac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmac.c; sourceTree = ""; }; 024A07DE23FCBC6C009FBA6C /* gmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gmac.h; sourceTree = ""; }; 024A07DF23FCBC6C009FBA6C /* sha2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha2.h; sourceTree = ""; }; 024A07E023FCBC6C009FBA6C /* hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hmac.h; sourceTree = ""; }; 024A07E123FCBC6C009FBA6C /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = ""; }; 024A07E223FCBC6C009FBA6C /* cast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cast.h; sourceTree = ""; }; 024A07E323FCBC6C009FBA6C /* michael.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = michael.h; sourceTree = ""; }; 024A07E423FCBC6C009FBA6C /* ecb_enc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ecb_enc.c; sourceTree = ""; }; 024A07E523FCBC6C009FBA6C /* cryptodev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cryptodev.h; sourceTree = ""; }; 024A07E623FCBC6C009FBA6C /* rijndael.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rijndael.h; sourceTree = ""; }; 024A07E723FCBC6C009FBA6C /* chacha_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chacha_private.h; sourceTree = ""; }; 024A07E823FCBC6C009FBA6C /* sha1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha1.h; sourceTree = ""; }; 024A07E923FCBC6C009FBA6C /* chachapoly.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = chachapoly.c; sourceTree = ""; }; 024A07EA23FCBC6C009FBA6C /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = md5.c; sourceTree = ""; }; 024A07EB23FCBC6C009FBA6C /* arc4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arc4.c; sourceTree = ""; }; 024A07EC23FCBC6C009FBA6C /* blf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blf.c; sourceTree = ""; }; 024A07ED23FCBC6C009FBA6C /* poly1305.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = poly1305.c; sourceTree = ""; }; 024A07EE23FCBC6C009FBA6C /* spr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spr.h; sourceTree = ""; }; 024A07EF23FCBC6C009FBA6C /* podd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = podd.h; sourceTree = ""; }; 024A07F023FCBC6C009FBA6C /* key_wrap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = key_wrap.c; sourceTree = ""; }; 024A07F123FCBC6C009FBA6C /* cmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cmac.h; sourceTree = ""; }; 024A07F223FCBC6C009FBA6C /* gmac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gmac.c; sourceTree = ""; }; 024A07F323FCBC6C009FBA6C /* rmd160.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rmd160.c; sourceTree = ""; }; 024A07F423FCBC6C009FBA6C /* idgen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = idgen.c; sourceTree = ""; }; 024A082123FCBC6C009FBA6C /* compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compat.h; sourceTree = ""; }; 024A088923FCBE38009FBA6C /* if_iwmreg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if_iwmreg.h; sourceTree = ""; }; 024A088A23FCBE38009FBA6C /* if_iwmvar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if_iwmvar.h; sourceTree = ""; }; 024A08BC23FCD0A9009FBA6C /* itlhdr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = itlhdr.h; sourceTree = ""; }; 024A08BD23FCD314009FBA6C /* fw.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = fw.cpp; sourceTree = ""; }; 024A08BF23FCD4E2009FBA6C /* utils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = utils.cpp; sourceTree = ""; }; 024A08C123FCD999009FBA6C /* io.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = io.cpp; sourceTree = ""; }; 024A08C323FCDC14009FBA6C /* rx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rx.cpp; sourceTree = ""; }; 024A08C523FCDC3B009FBA6C /* tx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = tx.cpp; sourceTree = ""; }; 024A08C723FCE2ED009FBA6C /* hw.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = hw.cpp; sourceTree = ""; }; 024A08C923FCE537009FBA6C /* phy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = phy.cpp; sourceTree = ""; }; 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = mac80211.cpp; sourceTree = ""; }; 024A08CD23FCE67F009FBA6C /* nvm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = nvm.cpp; sourceTree = ""; }; 024A08CF23FCEE88009FBA6C /* ctxt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ctxt.cpp; sourceTree = ""; }; 024A08D123FCF395009FBA6C /* led.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = led.cpp; sourceTree = ""; }; 024A08D323FCF3E6009FBA6C /* power.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = power.cpp; sourceTree = ""; }; 024A08D523FCF4D7009FBA6C /* scan.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = scan.cpp; sourceTree = ""; }; 17FD7F0C255E4A0900611406 /* if_iwnvar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = if_iwnvar.h; sourceTree = ""; }; 17FD7F0D255E4AB000611406 /* if_iwnreg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = if_iwnreg.h; sourceTree = ""; }; 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ItlIwn.cpp; sourceTree = ""; }; 17FD7F0F255E4AC800611406 /* ItlIwn.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ItlIwn.hpp; sourceTree = ""; }; 17FD7F38255E4EB200611406 /* iwn-6005 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-6005"; sourceTree = ""; }; 17FD7F39255E4EB200611406 /* iwn-135 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-135"; sourceTree = ""; }; 17FD7F3A255E4EB200611406 /* iwn-6030 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-6030"; sourceTree = ""; }; 17FD7F3B255E4EB200611406 /* iwn-1000 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-1000"; sourceTree = ""; }; 17FD7F3C255E4EB200611406 /* iwn-5000 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-5000"; sourceTree = ""; }; 17FD7F3D255E4EB300611406 /* iwn-6000 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-6000"; sourceTree = ""; }; 17FD7F3E255E4EB300611406 /* iwn-105 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-105"; sourceTree = ""; }; 17FD7F3F255E4EB300611406 /* iwn-6050 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-6050"; sourceTree = ""; }; 17FD7F40255E4EB300611406 /* iwn-2030 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-2030"; sourceTree = ""; }; 17FD7F41255E4EB300611406 /* iwn-5150 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-5150"; sourceTree = ""; }; 17FD7F42255E4EB300611406 /* iwn-2000 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-2000"; sourceTree = ""; }; 17FD7F44255E4EB300611406 /* iwn-4965 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwn-4965"; sourceTree = ""; }; 35CBE6BA251CB89700435CBC /* AirportItlwm.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AirportItlwm.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 35CBE724251CB8BF00435CBC /* AirportItlwm.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AirportItlwm.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 35CBE78F251CB8CA00435CBC /* AirportItlwm.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AirportItlwm.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FwBinary.cpp; sourceTree = ""; }; 5088ECB8252883BF0068A63D /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 5088ECB9252883C60068A63D /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 5088ECBA252884060068A63D /* iwlwifi-firmware-license */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwlwifi-firmware-license"; sourceTree = ""; }; 5088ECBC252884870068A63D /* libkmod.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libkmod.a; path = MacKernelSDK/Library/x86_64/libkmod.a; sourceTree = ""; }; A5213EBB27A0C3EC00D7EAB1 /* iwm-9000-46 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwm-9000-46"; sourceTree = ""; }; A5213EBC27A0C3ED00D7EAB1 /* iwm-8000C-36 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwm-8000C-36"; sourceTree = ""; }; A5213EBD27A0C3ED00D7EAB1 /* iwm-9260-46 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwm-9260-46"; sourceTree = ""; }; A5213EBE27A0C3ED00D7EAB1 /* iwm-8265-36 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwm-8265-36"; sourceTree = ""; }; A5A0C5222A501E2900EF9328 /* arp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = arp.h; sourceTree = ""; }; A5A0C5232A501E6800EF9328 /* arp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = arp.c; sourceTree = ""; }; A5DD111326D93B5F00BA01EF /* rs.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rs.cpp; sourceTree = ""; }; A5DD111426D93B5F00BA01EF /* rs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rs.h; sourceTree = ""; }; A5FA2AE328A797B200847103 /* _ifq.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = _ifq.cpp; sourceTree = ""; }; F800DD9A24FBEBF000789320 /* ItlDriverController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ItlDriverController.hpp; sourceTree = ""; }; F837C91C2724577F00B2C499 /* coex.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = coex.cpp; sourceTree = ""; }; F837C9252724732B00B2C499 /* iwlwifi-so-a0-gf-a0.pnvm */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-so-a0-gf-a0.pnvm"; sourceTree = ""; }; F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211WorkQueue.h; sourceTree = ""; }; F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOSkywalkNetworkPacket.h; sourceTree = ""; }; F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211InfraProtocol.h; sourceTree = ""; }; F84AD87D2A497DB200DC8DED /* CCPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCPipe.h; sourceTree = ""; }; F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOSkywalkLogicalLink.h; sourceTree = ""; }; F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211InfraInterface.h; sourceTree = ""; }; F84AD8802A497DB200DC8DED /* CCStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCStream.h; sourceTree = ""; }; F84AD8812A497DB200DC8DED /* CCDataPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCDataPipe.h; sourceTree = ""; }; F84AD8822A497DB200DC8DED /* CCLogStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCLogStream.h; sourceTree = ""; }; F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOSkywalkPacketBufferPool.h; sourceTree = ""; }; F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOSkywalkLegacyEthernetInterface.h; sourceTree = ""; }; F84AD8852A497DB200DC8DED /* CCLogPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCLogPipe.h; sourceTree = ""; }; F883EC1F266F43F200EA018C /* AirportItlwm-Monterey-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "AirportItlwm-Monterey-Info.plist"; sourceTree = ""; }; F88CB91324FBE9130060B1A5 /* ItlDriverInfo.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ItlDriverInfo.hpp; sourceTree = ""; }; F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sha1-pbkdf2.c"; sourceTree = ""; }; F897ED18266EFF93005EE8F7 /* AirportItlwm.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AirportItlwm.kext; sourceTree = BUILT_PRODUCTS_DIR; }; F89B6B8325021A79000F77FF /* apple_private_spi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = apple_private_spi.h; sourceTree = ""; }; F89B6B8525021AF1000F77FF /* Apple80211.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Apple80211.h; sourceTree = ""; }; F89B6BB925021C9C000F77FF /* AirportItlwm.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AirportItlwm.kext; sourceTree = BUILT_PRODUCTS_DIR; }; F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AirportItlwm.hpp; sourceTree = ""; }; F89B6BBD25021C9C000F77FF /* AirportItlwm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AirportItlwm.cpp; sourceTree = ""; }; F89B6BBF25021C9C000F77FF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F89B6BC325021DEC000F77FF /* apple80211_wps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apple80211_wps.h; sourceTree = ""; }; F89B6BC425021DEC000F77FF /* apple80211_var.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apple80211_var.h; sourceTree = ""; }; F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apple80211_ioctl.h; sourceTree = ""; }; F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOSkywalkEthernetInterface.h; sourceTree = ""; }; F89B6BDC25022F8C000F77FF /* AirportSTAIOCTL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AirportSTAIOCTL.cpp; sourceTree = ""; }; F89B6BDE25022FB5000F77FF /* AirportVirtualIOCTL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AirportVirtualIOCTL.cpp; sourceTree = ""; }; F89B6BE025022FC7000F77FF /* AirportAWDL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AirportAWDL.cpp; sourceTree = ""; }; F89B6C2225027609000F77FF /* debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = ""; }; F89F35F12A49867F00061876 /* IO80211ControllerV2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211ControllerV2.h; sourceTree = ""; }; F8A028202A4A7DDC00C6DE90 /* AirportItlwmV2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AirportItlwmV2.cpp; sourceTree = ""; }; F8A028212A4A7DDC00C6DE90 /* AirportItlwmV2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AirportItlwmV2.hpp; sourceTree = ""; }; F8A0282D2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AirportItlwmEthernetInterface.cpp; sourceTree = ""; }; F8A0282E2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AirportItlwmEthernetInterface.hpp; sourceTree = ""; }; F8A028702A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AirportItlwmSkywalkInterface.cpp; sourceTree = ""; }; F8A028712A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AirportItlwmSkywalkInterface.hpp; sourceTree = ""; }; F8A0287D2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IOPCIEDeviceWrapper.cpp; sourceTree = ""; }; F8A0287E2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = IOPCIEDeviceWrapper.hpp; sourceTree = ""; }; F8A2A68B2A305B9E002ABDDB /* IOSkywalkNetworkInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IOSkywalkNetworkInterface.h; sourceTree = ""; }; F8A2A68C2A305BAC002ABDDB /* IOSkywalkInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IOSkywalkInterface.h; sourceTree = ""; }; F8A763892766B95F004606BE /* iwlwifi-so-a0-gf4-a0.pnvm */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-so-a0-gf4-a0.pnvm"; sourceTree = ""; }; F8AE6558285471560085B4CF /* AirportItlwm.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AirportItlwm.kext; sourceTree = BUILT_PRODUCTS_DIR; }; F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ItlIwm.cpp; sourceTree = ""; }; F8AF3A3024F9F35B008911C1 /* ItlIwm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ItlIwm.hpp; sourceTree = ""; }; F8B2110A2A2EC2680043ECBD /* AirportItlwm.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AirportItlwm.kext; sourceTree = BUILT_PRODUCTS_DIR; }; F8B783AF240B9F87004C9777 /* _ifq.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _ifq.h; sourceTree = ""; }; F8BB56172647FDF500F180EC /* _clock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _clock.h; sourceTree = ""; }; F8BEFA9124CA93E900F6D938 /* _malloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _malloc.h; sourceTree = ""; }; F8C2EC2F24080319007A9422 /* ieee80211_proto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_proto.c; sourceTree = ""; }; F8C2EC3024080319007A9422 /* _string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = _string.c; sourceTree = ""; }; F8C2EC3124080319007A9422 /* ieee80211_amrr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_amrr.h; sourceTree = ""; }; F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_ioctl.c; sourceTree = ""; }; F8C2EC3324080319007A9422 /* ieee80211.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211.c; sourceTree = ""; }; F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_rssadapt.c; sourceTree = ""; }; F8C2EC3524080319007A9422 /* ieee80211_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_input.c; sourceTree = ""; }; F8C2EC3624080319007A9422 /* ieee80211_node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_node.h; sourceTree = ""; }; F8C2EC3724080319007A9422 /* timeout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = timeout.c; sourceTree = ""; }; F8C2EC3824080319007A9422 /* ieee80211_regdomain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_regdomain.h; sourceTree = ""; }; F8C2EC3924080319007A9422 /* ieee80211_mira.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_mira.c; sourceTree = ""; }; F8C2EC3A24080319007A9422 /* ieee80211_crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_crypto.h; sourceTree = ""; }; F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_crypto_bip.c; sourceTree = ""; }; F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_crypto_tkip.c; sourceTree = ""; }; F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_crypto_ccmp.c; sourceTree = ""; }; F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_pae_input.c; sourceTree = ""; }; F8C2EC3F24080319007A9422 /* ieee80211_radiotap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_radiotap.h; sourceTree = ""; }; F8C2EC4024080319007A9422 /* ieee80211_amrr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_amrr.c; sourceTree = ""; }; F8C2EC4124080319007A9422 /* ieee80211_proto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_proto.h; sourceTree = ""; }; F8C2EC422408031A007A9422 /* ieee80211_rssadapt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_rssadapt.h; sourceTree = ""; }; F8C2EC432408031A007A9422 /* ieee80211.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211.h; sourceTree = ""; }; F8C2EC442408031A007A9422 /* ieee80211_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_priv.h; sourceTree = ""; }; F8C2EC452408031A007A9422 /* ieee80211_ioctl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_ioctl.h; sourceTree = ""; }; F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_crypto_wep.c; sourceTree = ""; }; F8C2EC472408031A007A9422 /* ieee80211_output.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_output.c; sourceTree = ""; }; F8C2EC482408031A007A9422 /* ieee80211_crypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_crypto.c; sourceTree = ""; }; F8C2EC492408031A007A9422 /* CTimeout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CTimeout.cpp; sourceTree = ""; }; F8C2EC4A2408031A007A9422 /* ieee80211_mira.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_mira.h; sourceTree = ""; }; F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_regdomain.c; sourceTree = ""; }; F8C2EC4C2408031A007A9422 /* ieee80211_node.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_node.c; sourceTree = ""; }; F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieee80211_pae_output.c; sourceTree = ""; }; F8C2EC4E2408031A007A9422 /* ieee80211_var.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ieee80211_var.h; sourceTree = ""; }; F8C2EC8724080556007A9422 /* _buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _buf.h; sourceTree = ""; }; F8C2EC8824080556007A9422 /* CTimeout.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CTimeout.hpp; sourceTree = ""; }; F8C2EC8924080556007A9422 /* _arc4random.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _arc4random.h; sourceTree = ""; }; F8C2EC8A24080556007A9422 /* endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endian.h; sourceTree = ""; }; F8C2EC8B24080556007A9422 /* _mbuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _mbuf.h; sourceTree = ""; }; F8C2EC8C24080556007A9422 /* _if_ether.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _if_ether.h; sourceTree = ""; }; F8C2EC8D24080556007A9422 /* tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tree.h; sourceTree = ""; }; F8C2EC8E24080556007A9422 /* _if_media.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _if_media.h; sourceTree = ""; }; F8C2EC8F24080556007A9422 /* _null.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _null.h; sourceTree = ""; }; F8C2EC9024080556007A9422 /* timeout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timeout.h; sourceTree = ""; }; F8C2EC9B2408062D007A9422 /* pcireg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pcireg.h; sourceTree = ""; }; F8C4BF822420FAEB007F410E /* iwm-3160-17 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwm-3160-17"; sourceTree = ""; }; F8C4BF8A2420FAEC007F410E /* iwm-3168-29 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwm-3168-29"; sourceTree = ""; }; F8C4BF8C2420FAED007F410E /* iwm-7265-17 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwm-7265-17"; sourceTree = ""; }; F8C4BF8F2420FAED007F410E /* iwm-7260-17 */ = {isa = PBXFileReference; lastKnownFileType = text; path = "iwm-7260-17"; sourceTree = ""; }; F8C594D125FD935B0007D19C /* ieee80211_ra.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ieee80211_ra.c; sourceTree = ""; }; F8C594D225FD935B0007D19C /* ieee80211_ra.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ieee80211_ra.h; sourceTree = ""; }; F8C7EF7B263125DE00BA87B6 /* _netstat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _netstat.h; sourceTree = ""; }; F8CA44A125091AF60036119A /* AirportItlwmInterface.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AirportItlwmInterface.cpp; sourceTree = ""; }; F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AirportItlwmInterface.hpp; sourceTree = ""; }; F8D257732495A33500872E4F /* _mbuf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = _mbuf.cpp; sourceTree = ""; }; F8D257762495DEFC00872E4F /* Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Common.h; sourceTree = ""; }; F8D257772495DEFC00872E4F /* IoctlId.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IoctlId.h; sourceTree = ""; }; F8D364F624F93AFD0029340B /* ItlHalService.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ItlHalService.cpp; sourceTree = ""; }; F8D364F724F93AFD0029340B /* ItlHalService.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ItlHalService.hpp; sourceTree = ""; }; F8D6CD542442E0D100D2A454 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F8D6CD622442E8F200D2A454 /* ItlIwx.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ItlIwx.hpp; sourceTree = ""; }; F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ItlIwx.cpp; sourceTree = ""; }; F8D6CD6C2442F20C00D2A454 /* if_iwxreg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if_iwxreg.h; sourceTree = ""; }; F8D6CD6D2442F20C00D2A454 /* if_iwxvar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if_iwxvar.h; sourceTree = ""; }; F8D76361244F21BB00DEA040 /* pm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = pm.cpp; sourceTree = ""; }; F8D94CF52B9ABFE20081A3C4 /* AirportItlwm.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AirportItlwm.kext; sourceTree = BUILT_PRODUCTS_DIR; }; F8E3806526D533D400568FEB /* iwlwifi-ty-a0-gf-a0.pnvm */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-ty-a0-gf-a0.pnvm"; sourceTree = ""; }; F8E49A12249B923500BE6868 /* ItlNetworkUserClient.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ItlNetworkUserClient.cpp; sourceTree = ""; }; F8E49A13249B923500BE6868 /* ItlNetworkUserClient.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ItlNetworkUserClient.hpp; sourceTree = ""; }; F8EE4D1A241786B0002FA666 /* FwData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FwData.h; sourceTree = ""; }; F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211VirtualInterface.h; sourceTree = ""; }; F8F7EA35252D834500520FD4 /* IO80211Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211Controller.h; sourceTree = ""; }; F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211P2PInterface.h; sourceTree = ""; }; F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211SkywalkInterface.h; sourceTree = ""; }; F8F7EA38252D834500520FD4 /* IO80211Interface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211Interface.h; sourceTree = ""; }; F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IO80211WorkLoop.h; sourceTree = ""; }; F8F884F02791284800545F2C /* iwlwifi-cc-a0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-cc-a0-68.ucode"; sourceTree = ""; }; F8F884F12791285A00545F2C /* iwlwifi-Qu-b0-hr-b0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-Qu-b0-hr-b0-68.ucode"; sourceTree = ""; }; F8F884F22791286E00545F2C /* iwlwifi-Qu-b0-jf-b0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-Qu-b0-jf-b0-68.ucode"; sourceTree = ""; }; F8F884F32791289200545F2C /* iwlwifi-Qu-c0-hr-b0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-Qu-c0-hr-b0-68.ucode"; sourceTree = ""; }; F8F884F42791289C00545F2C /* iwlwifi-Qu-c0-jf-b0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-Qu-c0-jf-b0-68.ucode"; sourceTree = ""; }; F8F884F5279128B300545F2C /* iwlwifi-QuZ-a0-hr-b0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-QuZ-a0-hr-b0-68.ucode"; sourceTree = ""; }; F8F884F6279128C400545F2C /* iwlwifi-QuZ-a0-jf-b0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-QuZ-a0-jf-b0-68.ucode"; sourceTree = ""; }; F8F884F7279128DD00545F2C /* iwlwifi-so-a0-gf-a0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-so-a0-gf-a0-68.ucode"; sourceTree = ""; }; F8F884F92791293C00545F2C /* iwlwifi-so-a0-gf4-a0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-so-a0-gf4-a0-68.ucode"; sourceTree = ""; }; F8F884FA2791294B00545F2C /* iwlwifi-so-a0-hr-b0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-so-a0-hr-b0-68.ucode"; sourceTree = ""; }; F8F884FB2791295D00545F2C /* iwlwifi-so-a0-jf-b0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-so-a0-jf-b0-68.ucode"; sourceTree = ""; }; F8F884FC2791296C00545F2C /* iwlwifi-ty-a0-gf-a0-68.ucode */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iwlwifi-ty-a0-gf-a0-68.ucode"; sourceTree = ""; }; F8F92573240974EE0088B8D5 /* bitfield.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitfield.h; sourceTree = ""; }; F8F92574240974EE0088B8D5 /* kernel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel.h; sourceTree = ""; }; F8F92578240974EE0088B8D5 /* random.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = random.h; sourceTree = ""; }; F8F9257B240974EF0088B8D5 /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = ""; }; F8F9EDDF240B4741009CB8E7 /* _task.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _task.h; sourceTree = ""; }; F8F9EDE0240B7415009CB8E7 /* _task.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = _task.cpp; sourceTree = ""; }; F8FA0EEB2501E7EE00B1822E /* zutil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = zutil.h; sourceTree = ""; }; F8FA0EED2501E8C100B1822E /* zutil.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zutil.c; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 024A07A923FCBC3C009FBA6C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5088ECBD252884870068A63D /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE6B5251CB89700435CBC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5088ECC1252884D70068A63D /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE71F251CB8BF00435CBC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5088ECBF252884AF0068A63D /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE78A251CB8CA00435CBC /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5088ECBE252884A30068A63D /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; F897ED12266EFF93005EE8F7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( F897ED13266EFF93005EE8F7 /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; F89B6BB625021C9C000F77FF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5088ECC0252884C10068A63D /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; F8AE6552285471560085B4CF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( F8AE6553285471560085B4CF /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; F8B211042A2EC2680043ECBD /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( F8B211052A2EC2680043ECBD /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; F8D94CEF2B9ABFE20081A3C4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( F8D94CF02B9ABFE20081A3C4 /* libkmod.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 024A07A223FCBC3C009FBA6C = { isa = PBXGroup; children = ( 5088ECB8252883BF0068A63D /* README.md */, 5088ECB9252883C60068A63D /* LICENSE */, 5088ECBA252884060068A63D /* iwlwifi-firmware-license */, F8B8F1622493C28B0059FAA8 /* include */, 024A07AE23FCBC3C009FBA6C /* itlwm */, F8D6CD4F2442E0D100D2A454 /* itl80211 */, F89B6BBA25021C9C000F77FF /* AirportItlwm */, 024A07AD23FCBC3C009FBA6C /* Products */, 5088ECBB252884870068A63D /* Frameworks */, ); sourceTree = ""; }; 024A07AD23FCBC3C009FBA6C /* Products */ = { isa = PBXGroup; children = ( 024A07AC23FCBC3C009FBA6C /* itlwm.kext */, F89B6BB925021C9C000F77FF /* AirportItlwm.kext */, 35CBE6BA251CB89700435CBC /* AirportItlwm.kext */, 35CBE724251CB8BF00435CBC /* AirportItlwm.kext */, 35CBE78F251CB8CA00435CBC /* AirportItlwm.kext */, F897ED18266EFF93005EE8F7 /* AirportItlwm.kext */, F8AE6558285471560085B4CF /* AirportItlwm.kext */, F8B2110A2A2EC2680043ECBD /* AirportItlwm.kext */, F8D94CF52B9ABFE20081A3C4 /* AirportItlwm.kext */, ); name = Products; sourceTree = ""; }; 024A07AE23FCBC3C009FBA6C /* itlwm */ = { isa = PBXGroup; children = ( 0250B31C23FD768400FF8CEA /* firmware */, 17FD7F0B255E496000611406 /* hal_iwn */, F8AF3A2E24F9F25E008911C1 /* hal_iwm */, F8AF3A2D24F9F246008911C1 /* hal_iwx */, 024A07AF23FCBC3C009FBA6C /* itlwm.hpp */, 024A07B123FCBC3C009FBA6C /* itlwm.cpp */, 024A07B323FCBC3C009FBA6C /* Info.plist */, F8D76361244F21BB00DEA040 /* pm.cpp */, F8E49A12249B923500BE6868 /* ItlNetworkUserClient.cpp */, F8E49A13249B923500BE6868 /* ItlNetworkUserClient.hpp */, ); path = itlwm; sourceTree = ""; }; 024A07C723FCBC6C009FBA6C /* openbsd */ = { isa = PBXGroup; children = ( F8C2EC8624080556007A9422 /* sys */, F8C2EC2E24080319007A9422 /* net80211 */, 024A07C823FCBC6C009FBA6C /* crypto */, ); path = openbsd; sourceTree = ""; }; 024A07C823FCBC6C009FBA6C /* crypto */ = { isa = PBXGroup; children = ( F88D2B3B2414E64000BBE700 /* sha1-pbkdf2.c */, 024A07C923FCBC6C009FBA6C /* aes.c */, 024A07CA23FCBC6C009FBA6C /* hmac.c */, 024A07CB23FCBC6C009FBA6C /* sha2.c */, 024A07CC23FCBC6C009FBA6C /* rijndael.c */, 024A07CD23FCBC6C009FBA6C /* ecb3_enc.c */, 024A07CE23FCBC6C009FBA6C /* set_key.c */, 024A07CF23FCBC6C009FBA6C /* cast.c */, 024A07D023FCBC6C009FBA6C /* des_locl.h */, 024A07D123FCBC6C009FBA6C /* michael.c */, 024A07D223FCBC6C009FBA6C /* key_wrap.h */, 024A07D323FCBC6C009FBA6C /* poly1305.h */, 024A07D423FCBC6C009FBA6C /* md5.h */, 024A07D523FCBC6C009FBA6C /* blf.h */, 024A07D623FCBC6C009FBA6C /* arc4.h */, 024A07D723FCBC6C009FBA6C /* chachapoly.h */, 024A07D823FCBC6C009FBA6C /* sha1.c */, 024A07D923FCBC6C009FBA6C /* sk.h */, 024A07DA23FCBC6C009FBA6C /* castsb.h */, 024A07DB23FCBC6C009FBA6C /* rmd160.h */, 024A07DC23FCBC6C009FBA6C /* idgen.h */, 024A07DD23FCBC6C009FBA6C /* cmac.c */, 024A07DE23FCBC6C009FBA6C /* gmac.h */, 024A07DF23FCBC6C009FBA6C /* sha2.h */, 024A07E023FCBC6C009FBA6C /* hmac.h */, 024A07E123FCBC6C009FBA6C /* aes.h */, 024A07E223FCBC6C009FBA6C /* cast.h */, 024A07E323FCBC6C009FBA6C /* michael.h */, 024A07E423FCBC6C009FBA6C /* ecb_enc.c */, 024A07E523FCBC6C009FBA6C /* cryptodev.h */, 024A07E623FCBC6C009FBA6C /* rijndael.h */, 024A07E723FCBC6C009FBA6C /* chacha_private.h */, 024A07E823FCBC6C009FBA6C /* sha1.h */, 024A07E923FCBC6C009FBA6C /* chachapoly.c */, 024A07EA23FCBC6C009FBA6C /* md5.c */, 024A07EB23FCBC6C009FBA6C /* arc4.c */, 024A07EC23FCBC6C009FBA6C /* blf.c */, 024A07ED23FCBC6C009FBA6C /* poly1305.c */, 024A07EE23FCBC6C009FBA6C /* spr.h */, 024A07EF23FCBC6C009FBA6C /* podd.h */, 024A07F023FCBC6C009FBA6C /* key_wrap.c */, 024A07F123FCBC6C009FBA6C /* cmac.h */, 024A07F223FCBC6C009FBA6C /* gmac.c */, 024A07F323FCBC6C009FBA6C /* rmd160.c */, 024A07F423FCBC6C009FBA6C /* idgen.c */, ); path = crypto; sourceTree = ""; }; 0250B31C23FD768400FF8CEA /* firmware */ = { isa = PBXGroup; children = ( A5213EBC27A0C3ED00D7EAB1 /* iwm-8000C-36 */, A5213EBE27A0C3ED00D7EAB1 /* iwm-8265-36 */, A5213EBB27A0C3EC00D7EAB1 /* iwm-9000-46 */, A5213EBD27A0C3ED00D7EAB1 /* iwm-9260-46 */, F8C4BF822420FAEB007F410E /* iwm-3160-17 */, F8C4BF8A2420FAEC007F410E /* iwm-3168-29 */, F8C4BF8F2420FAED007F410E /* iwm-7260-17 */, F8C4BF8C2420FAED007F410E /* iwm-7265-17 */, F8F884F6279128C400545F2C /* iwlwifi-QuZ-a0-jf-b0-68.ucode */, F8F884F22791286E00545F2C /* iwlwifi-Qu-b0-jf-b0-68.ucode */, F8F884F32791289200545F2C /* iwlwifi-Qu-c0-hr-b0-68.ucode */, F8F884F42791289C00545F2C /* iwlwifi-Qu-c0-jf-b0-68.ucode */, F8F884F02791284800545F2C /* iwlwifi-cc-a0-68.ucode */, F8F884F12791285A00545F2C /* iwlwifi-Qu-b0-hr-b0-68.ucode */, F8F884F5279128B300545F2C /* iwlwifi-QuZ-a0-hr-b0-68.ucode */, F8F884FC2791296C00545F2C /* iwlwifi-ty-a0-gf-a0-68.ucode */, F8E3806526D533D400568FEB /* iwlwifi-ty-a0-gf-a0.pnvm */, F8F884F7279128DD00545F2C /* iwlwifi-so-a0-gf-a0-68.ucode */, F837C9252724732B00B2C499 /* iwlwifi-so-a0-gf-a0.pnvm */, F8F884FA2791294B00545F2C /* iwlwifi-so-a0-hr-b0-68.ucode */, F8F884FB2791295D00545F2C /* iwlwifi-so-a0-jf-b0-68.ucode */, F8F884F92791293C00545F2C /* iwlwifi-so-a0-gf4-a0-68.ucode */, F8A763892766B95F004606BE /* iwlwifi-so-a0-gf4-a0.pnvm */, 17FD7F3E255E4EB300611406 /* iwn-105 */, 17FD7F39255E4EB200611406 /* iwn-135 */, 17FD7F3B255E4EB200611406 /* iwn-1000 */, 17FD7F42255E4EB300611406 /* iwn-2000 */, 17FD7F40255E4EB300611406 /* iwn-2030 */, 17FD7F44255E4EB300611406 /* iwn-4965 */, 17FD7F3C255E4EB200611406 /* iwn-5000 */, 17FD7F41255E4EB300611406 /* iwn-5150 */, 17FD7F3D255E4EB300611406 /* iwn-6000 */, 17FD7F38255E4EB200611406 /* iwn-6005 */, 17FD7F3A255E4EB200611406 /* iwn-6030 */, 17FD7F3F255E4EB300611406 /* iwn-6050 */, ); path = firmware; sourceTree = ""; }; 17FD7F0B255E496000611406 /* hal_iwn */ = { isa = PBXGroup; children = ( 17FD7F0C255E4A0900611406 /* if_iwnvar.h */, 17FD7F0D255E4AB000611406 /* if_iwnreg.h */, 17FD7F0E255E4AC800611406 /* ItlIwn.cpp */, 17FD7F0F255E4AC800611406 /* ItlIwn.hpp */, ); path = hal_iwn; sourceTree = ""; }; 5088ECBB252884870068A63D /* Frameworks */ = { isa = PBXGroup; children = ( 5088ECBC252884870068A63D /* libkmod.a */, ); name = Frameworks; sourceTree = ""; }; F8585CC32500EA6F00485C5A /* ClientKit */ = { isa = PBXGroup; children = ( F8D257762495DEFC00872E4F /* Common.h */, F8D257772495DEFC00872E4F /* IoctlId.h */, ); path = ClientKit; sourceTree = ""; }; F89B6B7D25021674000F77FF /* Airport */ = { isa = PBXGroup; children = ( F84AD8812A497DB200DC8DED /* CCDataPipe.h */, F84AD8852A497DB200DC8DED /* CCLogPipe.h */, F84AD8822A497DB200DC8DED /* CCLogStream.h */, F84AD87D2A497DB200DC8DED /* CCPipe.h */, F84AD8802A497DB200DC8DED /* CCStream.h */, F84AD87F2A497DB200DC8DED /* IO80211InfraInterface.h */, F84AD87C2A497DB200DC8DED /* IO80211InfraProtocol.h */, F84AD87A2A497DB200DC8DED /* IO80211WorkQueue.h */, F84AD8842A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h */, F84AD87E2A497DB200DC8DED /* IOSkywalkLogicalLink.h */, F84AD87B2A497DB200DC8DED /* IOSkywalkNetworkPacket.h */, F84AD8832A497DB200DC8DED /* IOSkywalkPacketBufferPool.h */, F89B6B8325021A79000F77FF /* apple_private_spi.h */, F8F7EA35252D834500520FD4 /* IO80211Controller.h */, F89F35F12A49867F00061876 /* IO80211ControllerV2.h */, F8F7EA38252D834500520FD4 /* IO80211Interface.h */, F8F7EA36252D834500520FD4 /* IO80211P2PInterface.h */, F8F7EA37252D834500520FD4 /* IO80211SkywalkInterface.h */, F89B6BD025021E66000F77FF /* IOSkywalkEthernetInterface.h */, F8A2A68B2A305B9E002ABDDB /* IOSkywalkNetworkInterface.h */, F8A2A68C2A305BAC002ABDDB /* IOSkywalkInterface.h */, F8F7EA34252D834500520FD4 /* IO80211VirtualInterface.h */, F8F7EA39252D834500520FD4 /* IO80211WorkLoop.h */, F89B6BC525021DEC000F77FF /* apple80211_ioctl.h */, F89B6BC425021DEC000F77FF /* apple80211_var.h */, F89B6BC325021DEC000F77FF /* apple80211_wps.h */, F89B6B8525021AF1000F77FF /* Apple80211.h */, F89B6C2225027609000F77FF /* debug.h */, ); path = Airport; sourceTree = ""; }; F89B6BBA25021C9C000F77FF /* AirportItlwm */ = { isa = PBXGroup; children = ( F89B6BBB25021C9C000F77FF /* AirportItlwm.hpp */, F89B6BBD25021C9C000F77FF /* AirportItlwm.cpp */, F89B6BDC25022F8C000F77FF /* AirportSTAIOCTL.cpp */, F89B6BDE25022FB5000F77FF /* AirportVirtualIOCTL.cpp */, F89B6BE025022FC7000F77FF /* AirportAWDL.cpp */, F8CA44A125091AF60036119A /* AirportItlwmInterface.cpp */, F8CA44A225091AF60036119A /* AirportItlwmInterface.hpp */, F89B6BBF25021C9C000F77FF /* Info.plist */, F883EC1F266F43F200EA018C /* AirportItlwm-Monterey-Info.plist */, F8A028202A4A7DDC00C6DE90 /* AirportItlwmV2.cpp */, F8A028212A4A7DDC00C6DE90 /* AirportItlwmV2.hpp */, F8A0282D2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.cpp */, F8A0282E2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.hpp */, F8A028702A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.cpp */, F8A028712A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.hpp */, F8A0287D2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.cpp */, F8A0287E2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.hpp */, ); path = AirportItlwm; sourceTree = ""; }; F8AF3A2D24F9F246008911C1 /* hal_iwx */ = { isa = PBXGroup; children = ( F8D6CD6C2442F20C00D2A454 /* if_iwxreg.h */, F8D6CD6D2442F20C00D2A454 /* if_iwxvar.h */, F8D6CD622442E8F200D2A454 /* ItlIwx.hpp */, F8D6CD642442E8F200D2A454 /* ItlIwx.cpp */, ); path = hal_iwx; sourceTree = ""; }; F8AF3A2E24F9F25E008911C1 /* hal_iwm */ = { isa = PBXGroup; children = ( 024A088923FCBE38009FBA6C /* if_iwmreg.h */, 024A088A23FCBE38009FBA6C /* if_iwmvar.h */, 024A08BC23FCD0A9009FBA6C /* itlhdr.h */, 024A08BF23FCD4E2009FBA6C /* utils.cpp */, 024A08BD23FCD314009FBA6C /* fw.cpp */, 024A08C123FCD999009FBA6C /* io.cpp */, 024A08C323FCDC14009FBA6C /* rx.cpp */, 024A08C523FCDC3B009FBA6C /* tx.cpp */, 024A08C723FCE2ED009FBA6C /* hw.cpp */, 024A08C923FCE537009FBA6C /* phy.cpp */, 024A08CB23FCE5CA009FBA6C /* mac80211.cpp */, 024A08CD23FCE67F009FBA6C /* nvm.cpp */, 024A08CF23FCEE88009FBA6C /* ctxt.cpp */, 024A08D123FCF395009FBA6C /* led.cpp */, 024A08D323FCF3E6009FBA6C /* power.cpp */, 024A08D523FCF4D7009FBA6C /* scan.cpp */, F837C91C2724577F00B2C499 /* coex.cpp */, F8AF3A2F24F9F35B008911C1 /* ItlIwm.cpp */, F8AF3A3024F9F35B008911C1 /* ItlIwm.hpp */, A5DD111326D93B5F00BA01EF /* rs.cpp */, A5DD111426D93B5F00BA01EF /* rs.h */, ); path = hal_iwm; sourceTree = ""; }; F8B8F1622493C28B0059FAA8 /* include */ = { isa = PBXGroup; children = ( F89B6B7D25021674000F77FF /* Airport */, F8585CC32500EA6F00485C5A /* ClientKit */, F8D364FC24F93EE20029340B /* HAL */, F8EE4D1A241786B0002FA666 /* FwData.h */, 5076FA7F24CC71E40011B2BB /* FwBinary.cpp */, ); path = include; sourceTree = ""; }; F8C2EC2E24080319007A9422 /* net80211 */ = { isa = PBXGroup; children = ( F8C2EC2F24080319007A9422 /* ieee80211_proto.c */, F8C2EC3024080319007A9422 /* _string.c */, F8C2EC3124080319007A9422 /* ieee80211_amrr.h */, F8C2EC3224080319007A9422 /* ieee80211_ioctl.c */, F8C2EC3324080319007A9422 /* ieee80211.c */, F8C2EC3424080319007A9422 /* ieee80211_rssadapt.c */, F8C2EC3524080319007A9422 /* ieee80211_input.c */, F8C2EC3624080319007A9422 /* ieee80211_node.h */, F8C2EC3724080319007A9422 /* timeout.c */, F8C2EC3824080319007A9422 /* ieee80211_regdomain.h */, F8C2EC3924080319007A9422 /* ieee80211_mira.c */, F8C2EC3A24080319007A9422 /* ieee80211_crypto.h */, F8C2EC3B24080319007A9422 /* ieee80211_crypto_bip.c */, F8C2EC3C24080319007A9422 /* ieee80211_crypto_tkip.c */, F8C2EC3D24080319007A9422 /* ieee80211_crypto_ccmp.c */, F8C2EC462408031A007A9422 /* ieee80211_crypto_wep.c */, F8C2EC3E24080319007A9422 /* ieee80211_pae_input.c */, F8C2EC3F24080319007A9422 /* ieee80211_radiotap.h */, F8C2EC4024080319007A9422 /* ieee80211_amrr.c */, F8C2EC4124080319007A9422 /* ieee80211_proto.h */, F8C2EC422408031A007A9422 /* ieee80211_rssadapt.h */, F8C2EC432408031A007A9422 /* ieee80211.h */, F8C2EC442408031A007A9422 /* ieee80211_priv.h */, F8C2EC452408031A007A9422 /* ieee80211_ioctl.h */, F8C2EC472408031A007A9422 /* ieee80211_output.c */, F8C2EC482408031A007A9422 /* ieee80211_crypto.c */, F8C2EC492408031A007A9422 /* CTimeout.cpp */, F8C2EC4A2408031A007A9422 /* ieee80211_mira.h */, F8C2EC4B2408031A007A9422 /* ieee80211_regdomain.c */, F8C2EC4C2408031A007A9422 /* ieee80211_node.c */, F8C2EC4D2408031A007A9422 /* ieee80211_pae_output.c */, F8C2EC4E2408031A007A9422 /* ieee80211_var.h */, F8C594D125FD935B0007D19C /* ieee80211_ra.c */, F8C594D225FD935B0007D19C /* ieee80211_ra.h */, ); path = net80211; sourceTree = ""; }; F8C2EC8624080556007A9422 /* sys */ = { isa = PBXGroup; children = ( F8C2EC9B2408062D007A9422 /* pcireg.h */, F8C2EC8724080556007A9422 /* _buf.h */, F8C2EC8824080556007A9422 /* CTimeout.hpp */, F8C2EC8924080556007A9422 /* _arc4random.h */, F8C2EC8A24080556007A9422 /* endian.h */, F8C2EC8B24080556007A9422 /* _mbuf.h */, F8D257732495A33500872E4F /* _mbuf.cpp */, F8C2EC8C24080556007A9422 /* _if_ether.h */, F8C2EC8D24080556007A9422 /* tree.h */, F8C2EC8E24080556007A9422 /* _if_media.h */, F8C2EC8F24080556007A9422 /* _null.h */, F8C2EC9024080556007A9422 /* timeout.h */, F8F9EDDF240B4741009CB8E7 /* _task.h */, F8F9EDE0240B7415009CB8E7 /* _task.cpp */, F8B783AF240B9F87004C9777 /* _ifq.h */, A5FA2AE328A797B200847103 /* _ifq.cpp */, F8BEFA9124CA93E900F6D938 /* _malloc.h */, F8C7EF7B263125DE00BA87B6 /* _netstat.h */, F8BB56172647FDF500F180EC /* _clock.h */, A5A0C5222A501E2900EF9328 /* arp.h */, A5A0C5232A501E6800EF9328 /* arp.c */, ); path = sys; sourceTree = ""; }; F8D364FC24F93EE20029340B /* HAL */ = { isa = PBXGroup; children = ( F8D364F624F93AFD0029340B /* ItlHalService.cpp */, F8D364F724F93AFD0029340B /* ItlHalService.hpp */, F88CB91324FBE9130060B1A5 /* ItlDriverInfo.hpp */, F800DD9A24FBEBF000789320 /* ItlDriverController.hpp */, ); path = HAL; sourceTree = ""; }; F8D6CD4F2442E0D100D2A454 /* itl80211 */ = { isa = PBXGroup; children = ( F8F9256D240972EE0088B8D5 /* linux */, 024A07C723FCBC6C009FBA6C /* openbsd */, 024A07BA23FCBC6C009FBA6C /* compat.cpp */, 024A082123FCBC6C009FBA6C /* compat.h */, F8FA0EEB2501E7EE00B1822E /* zutil.h */, F8FA0EED2501E8C100B1822E /* zutil.c */, F8D6CD542442E0D100D2A454 /* Info.plist */, ); path = itl80211; sourceTree = ""; }; F8F9256D240972EE0088B8D5 /* linux */ = { isa = PBXGroup; children = ( F8F92573240974EE0088B8D5 /* bitfield.h */, F8F92574240974EE0088B8D5 /* kernel.h */, F8F92578240974EE0088B8D5 /* random.h */, F8F9257B240974EF0088B8D5 /* types.h */, ); path = linux; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 024A07A723FCBC3C009FBA6C /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( F8F9257F240974EF0088B8D5 /* kernel.h in Headers */, 024A084D23FCBC6C009FBA6C /* sha1.h in Headers */, 024A084B23FCBC6C009FBA6C /* rijndael.h in Headers */, 024A083923FCBC6C009FBA6C /* md5.h in Headers */, 17FD7F11255E4AC800611406 /* ItlIwn.hpp in Headers */, F8C2EC5F2408031A007A9422 /* ieee80211_radiotap.h in Headers */, 024A084023FCBC6C009FBA6C /* rmd160.h in Headers */, 024A083823FCBC6C009FBA6C /* poly1305.h in Headers */, F8C2EC9424080557007A9422 /* endian.h in Headers */, F8C2EC6A2408031A007A9422 /* ieee80211_mira.h in Headers */, 024A083F23FCBC6C009FBA6C /* castsb.h in Headers */, F8C2EC9824080557007A9422 /* _if_media.h in Headers */, F8D257782495DEFC00872E4F /* Common.h in Headers */, F8C2EC9124080557007A9422 /* _buf.h in Headers */, 024A084123FCBC6C009FBA6C /* idgen.h in Headers */, F88CB91424FBE9130060B1A5 /* ItlDriverInfo.hpp in Headers */, F8F92586240974EF0088B8D5 /* types.h in Headers */, 024A083523FCBC6C009FBA6C /* des_locl.h in Headers */, 024A088B23FCBE38009FBA6C /* if_iwmreg.h in Headers */, 17FD7F7F255E549500611406 /* if_iwnvar.h in Headers */, 024A084A23FCBC6C009FBA6C /* cryptodev.h in Headers */, F8D364FA24F93AFD0029340B /* ItlHalService.hpp in Headers */, 024A083E23FCBC6C009FBA6C /* sk.h in Headers */, F8AF3A3224F9F35B008911C1 /* ItlIwm.hpp in Headers */, 024A084323FCBC6C009FBA6C /* gmac.h in Headers */, F8C2EC9C2408062D007A9422 /* pcireg.h in Headers */, F8C2EC9624080557007A9422 /* _if_ether.h in Headers */, F8C2EC6E2408031A007A9422 /* ieee80211_var.h in Headers */, F8C2EC9924080557007A9422 /* _null.h in Headers */, F8C2EC9A24080557007A9422 /* timeout.h in Headers */, 024A084523FCBC6C009FBA6C /* hmac.h in Headers */, F8C2EC9724080557007A9422 /* tree.h in Headers */, F8C2EC512408031A007A9422 /* ieee80211_amrr.h in Headers */, 024A083723FCBC6C009FBA6C /* key_wrap.h in Headers */, F8C594D825FD935B0007D19C /* ieee80211_ra.h in Headers */, F8F92583240974EF0088B8D5 /* random.h in Headers */, F800DD9B24FBEBF000789320 /* ItlDriverController.hpp in Headers */, F8C2EC9324080557007A9422 /* _arc4random.h in Headers */, 024A084823FCBC6C009FBA6C /* michael.h in Headers */, 024A085423FCBC6C009FBA6C /* podd.h in Headers */, F8C2EC562408031A007A9422 /* ieee80211_node.h in Headers */, F8C2EC9524080557007A9422 /* _mbuf.h in Headers */, A5DD111B26D93B5F00BA01EF /* rs.h in Headers */, 024A084423FCBC6C009FBA6C /* sha2.h in Headers */, 024A088C23FCBE38009FBA6C /* if_iwmvar.h in Headers */, 024A083A23FCBC6C009FBA6C /* blf.h in Headers */, F8C2EC9224080557007A9422 /* CTimeout.hpp in Headers */, F8C2EC612408031A007A9422 /* ieee80211_proto.h in Headers */, 024A084723FCBC6C009FBA6C /* cast.h in Headers */, F8C2EC622408031A007A9422 /* ieee80211_rssadapt.h in Headers */, F8D2577A2495DEFC00872E4F /* IoctlId.h in Headers */, F8C2EC652408031A007A9422 /* ieee80211_ioctl.h in Headers */, 024A083C23FCBC6C009FBA6C /* chachapoly.h in Headers */, 024A084C23FCBC6C009FBA6C /* chacha_private.h in Headers */, 024A083B23FCBC6C009FBA6C /* arc4.h in Headers */, 024A084623FCBC6C009FBA6C /* aes.h in Headers */, F8E49A15249B923500BE6868 /* ItlNetworkUserClient.hpp in Headers */, F8C2EC632408031A007A9422 /* ieee80211.h in Headers */, 024A085623FCBC6C009FBA6C /* cmac.h in Headers */, F8F9257E240974EF0088B8D5 /* bitfield.h in Headers */, F8FA0EEC2501E7EE00B1822E /* zutil.h in Headers */, F8C2EC642408031A007A9422 /* ieee80211_priv.h in Headers */, 024A07B023FCBC3C009FBA6C /* itlwm.hpp in Headers */, F8C2EC5A2408031A007A9422 /* ieee80211_crypto.h in Headers */, F8C2EC582408031A007A9422 /* ieee80211_regdomain.h in Headers */, 024A085323FCBC6C009FBA6C /* spr.h in Headers */, 17FD7F86255E549900611406 /* if_iwnreg.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE658251CB89700435CBC /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 35CBE659251CB89700435CBC /* debug.h in Headers */, 35CBE65A251CB89700435CBC /* IOSkywalkEthernetInterface.h in Headers */, F84AD8A52A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */, F84AD8892A497DB200DC8DED /* IO80211WorkQueue.h in Headers */, 35CBE65B251CB89700435CBC /* apple80211_ioctl.h in Headers */, F84AD8B32A497DB200DC8DED /* CCStream.h in Headers */, F8F7EA45252D834600520FD4 /* IO80211P2PInterface.h in Headers */, F8F7EA51252D834600520FD4 /* IO80211WorkLoop.h in Headers */, F84AD8BA2A497DB200DC8DED /* CCDataPipe.h in Headers */, F84AD8C12A497DB200DC8DED /* CCLogStream.h in Headers */, F89F35F52A49867F00061876 /* IO80211ControllerV2.h in Headers */, 35CBE661251CB89700435CBC /* apple80211_var.h in Headers */, 35CBE664251CB89700435CBC /* AirportItlwmInterface.hpp in Headers */, F84AD8CF2A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */, F8F7EA4D252D834600520FD4 /* IO80211Interface.h in Headers */, F84AD8AC2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */, F8F7EA49252D834600520FD4 /* IO80211SkywalkInterface.h in Headers */, 35CBE666251CB89700435CBC /* AirportItlwm.hpp in Headers */, A5DD111F26D93B5F00BA01EF /* rs.h in Headers */, F8F7EA3D252D834600520FD4 /* IO80211VirtualInterface.h in Headers */, F84AD89E2A497DB200DC8DED /* CCPipe.h in Headers */, F84AD8D62A497DB200DC8DED /* CCLogPipe.h in Headers */, F8F7EA41252D834600520FD4 /* IO80211Controller.h in Headers */, F84AD8C82A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */, F84AD8972A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */, F8C594DC25FD935B0007D19C /* ieee80211_ra.h in Headers */, F84AD8902A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */, 35CBE66F251CB89700435CBC /* apple80211_wps.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE6C2251CB8BF00435CBC /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 35CBE6C3251CB8BF00435CBC /* debug.h in Headers */, 35CBE6C4251CB8BF00435CBC /* IOSkywalkEthernetInterface.h in Headers */, F84AD8A32A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */, F84AD8872A497DB200DC8DED /* IO80211WorkQueue.h in Headers */, 35CBE6C5251CB8BF00435CBC /* apple80211_ioctl.h in Headers */, F84AD8B12A497DB200DC8DED /* CCStream.h in Headers */, F8F7EA43252D834600520FD4 /* IO80211P2PInterface.h in Headers */, F8F7EA4F252D834600520FD4 /* IO80211WorkLoop.h in Headers */, F84AD8B82A497DB200DC8DED /* CCDataPipe.h in Headers */, F84AD8BF2A497DB200DC8DED /* CCLogStream.h in Headers */, F89F35F32A49867F00061876 /* IO80211ControllerV2.h in Headers */, 35CBE6CB251CB8BF00435CBC /* apple80211_var.h in Headers */, 35CBE6CE251CB8BF00435CBC /* AirportItlwmInterface.hpp in Headers */, F84AD8CD2A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */, F8F7EA4B252D834600520FD4 /* IO80211Interface.h in Headers */, F84AD8AA2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */, F8F7EA47252D834600520FD4 /* IO80211SkywalkInterface.h in Headers */, 35CBE6D0251CB8BF00435CBC /* AirportItlwm.hpp in Headers */, A5DD111D26D93B5F00BA01EF /* rs.h in Headers */, F8F7EA3B252D834600520FD4 /* IO80211VirtualInterface.h in Headers */, F84AD89C2A497DB200DC8DED /* CCPipe.h in Headers */, F84AD8D42A497DB200DC8DED /* CCLogPipe.h in Headers */, F8F7EA3F252D834600520FD4 /* IO80211Controller.h in Headers */, F84AD8C62A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */, F84AD8952A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */, F8C594DA25FD935B0007D19C /* ieee80211_ra.h in Headers */, F84AD88E2A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */, 35CBE6D9251CB8BF00435CBC /* apple80211_wps.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE72D251CB8CA00435CBC /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 35CBE72E251CB8CA00435CBC /* debug.h in Headers */, 35CBE72F251CB8CA00435CBC /* IOSkywalkEthernetInterface.h in Headers */, F84AD8A22A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */, F84AD8862A497DB200DC8DED /* IO80211WorkQueue.h in Headers */, 35CBE730251CB8CA00435CBC /* apple80211_ioctl.h in Headers */, F84AD8B02A497DB200DC8DED /* CCStream.h in Headers */, F8F7EA42252D834600520FD4 /* IO80211P2PInterface.h in Headers */, F8F7EA4E252D834600520FD4 /* IO80211WorkLoop.h in Headers */, F84AD8B72A497DB200DC8DED /* CCDataPipe.h in Headers */, F84AD8BE2A497DB200DC8DED /* CCLogStream.h in Headers */, F89F35F22A49867F00061876 /* IO80211ControllerV2.h in Headers */, 35CBE736251CB8CA00435CBC /* apple80211_var.h in Headers */, 35CBE739251CB8CA00435CBC /* AirportItlwmInterface.hpp in Headers */, F84AD8CC2A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */, F8F7EA4A252D834600520FD4 /* IO80211Interface.h in Headers */, F84AD8A92A497DB200DC8DED /* IO80211InfraInterface.h in Headers */, F8F7EA46252D834600520FD4 /* IO80211SkywalkInterface.h in Headers */, 35CBE73B251CB8CA00435CBC /* AirportItlwm.hpp in Headers */, A5DD111C26D93B5F00BA01EF /* rs.h in Headers */, F8F7EA3A252D834600520FD4 /* IO80211VirtualInterface.h in Headers */, F84AD89B2A497DB200DC8DED /* CCPipe.h in Headers */, F84AD8D32A497DB200DC8DED /* CCLogPipe.h in Headers */, F8F7EA3E252D834600520FD4 /* IO80211Controller.h in Headers */, F84AD8C52A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */, F84AD8942A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */, F8C594D925FD935B0007D19C /* ieee80211_ra.h in Headers */, F84AD88D2A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */, 35CBE744251CB8CA00435CBC /* apple80211_wps.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; F897ECB9266EFF93005EE8F7 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( F84AD8BB2A497DB200DC8DED /* CCDataPipe.h in Headers */, F897ECBA266EFF93005EE8F7 /* debug.h in Headers */, F897ECBB266EFF93005EE8F7 /* IOSkywalkEthernetInterface.h in Headers */, F84AD8982A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */, F84AD8A62A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */, F84AD8912A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */, F897ECBC266EFF93005EE8F7 /* apple80211_ioctl.h in Headers */, F84AD8D72A497DB200DC8DED /* CCLogPipe.h in Headers */, F897ECBD266EFF93005EE8F7 /* IO80211P2PInterface.h in Headers */, F84AD89F2A497DB200DC8DED /* CCPipe.h in Headers */, F897ECBE266EFF93005EE8F7 /* IO80211WorkLoop.h in Headers */, F897ECBF266EFF93005EE8F7 /* apple80211_var.h in Headers */, A5DD112026D93B5F00BA01EF /* rs.h in Headers */, F84AD8C92A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */, F84AD8D02A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */, F897ECC0266EFF93005EE8F7 /* AirportItlwmInterface.hpp in Headers */, F897ECC1266EFF93005EE8F7 /* IO80211Interface.h in Headers */, F84AD88A2A497DB200DC8DED /* IO80211WorkQueue.h in Headers */, F897ECC2266EFF93005EE8F7 /* (null) in Headers */, F84AD8AD2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */, F897ECC3266EFF93005EE8F7 /* IO80211SkywalkInterface.h in Headers */, F84AD8C22A497DB200DC8DED /* CCLogStream.h in Headers */, F897ECC4266EFF93005EE8F7 /* AirportItlwm.hpp in Headers */, F89F35F62A49867F00061876 /* IO80211ControllerV2.h in Headers */, F897ECC5266EFF93005EE8F7 /* IO80211VirtualInterface.h in Headers */, F897ECC6266EFF93005EE8F7 /* IO80211Controller.h in Headers */, F897ECC7266EFF93005EE8F7 /* (null) in Headers */, F897ECC8266EFF93005EE8F7 /* ieee80211_ra.h in Headers */, F84AD8B42A497DB200DC8DED /* CCStream.h in Headers */, F897ECC9266EFF93005EE8F7 /* apple80211_wps.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; F89B6BB425021C9C000F77FF /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( F89B6C2325027609000F77FF /* debug.h in Headers */, F89B6BD725021E66000F77FF /* IOSkywalkEthernetInterface.h in Headers */, F84AD8A42A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */, F84AD8882A497DB200DC8DED /* IO80211WorkQueue.h in Headers */, F89B6BCB25021DED000F77FF /* apple80211_ioctl.h in Headers */, F84AD8B22A497DB200DC8DED /* CCStream.h in Headers */, F8F7EA44252D834600520FD4 /* IO80211P2PInterface.h in Headers */, F8F7EA50252D834600520FD4 /* IO80211WorkLoop.h in Headers */, F84AD8B92A497DB200DC8DED /* CCDataPipe.h in Headers */, F84AD8C02A497DB200DC8DED /* CCLogStream.h in Headers */, F89F35F42A49867F00061876 /* IO80211ControllerV2.h in Headers */, F89B6BC925021DED000F77FF /* apple80211_var.h in Headers */, F8CA44A425091AF60036119A /* AirportItlwmInterface.hpp in Headers */, F84AD8CE2A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */, F8F7EA4C252D834600520FD4 /* IO80211Interface.h in Headers */, F84AD8AB2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */, F8F7EA48252D834600520FD4 /* IO80211SkywalkInterface.h in Headers */, F89B6BBC25021C9C000F77FF /* AirportItlwm.hpp in Headers */, A5DD111E26D93B5F00BA01EF /* rs.h in Headers */, F8F7EA3C252D834600520FD4 /* IO80211VirtualInterface.h in Headers */, F84AD89D2A497DB200DC8DED /* CCPipe.h in Headers */, F84AD8D52A497DB200DC8DED /* CCLogPipe.h in Headers */, F8F7EA40252D834600520FD4 /* IO80211Controller.h in Headers */, F84AD8C72A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */, F84AD8962A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */, F8C594DB25FD935B0007D19C /* ieee80211_ra.h in Headers */, F84AD88F2A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */, F89B6BC725021DED000F77FF /* apple80211_wps.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; F8AE64F8285471560085B4CF /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( F84AD8BC2A497DB200DC8DED /* CCDataPipe.h in Headers */, F8AE64F9285471560085B4CF /* debug.h in Headers */, F8AE64FA285471560085B4CF /* IOSkywalkEthernetInterface.h in Headers */, F84AD8992A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */, F84AD8A72A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */, F84AD8922A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */, F8AE64FB285471560085B4CF /* apple80211_ioctl.h in Headers */, F84AD8D82A497DB200DC8DED /* CCLogPipe.h in Headers */, F8AE64FC285471560085B4CF /* IO80211P2PInterface.h in Headers */, F84AD8A02A497DB200DC8DED /* CCPipe.h in Headers */, F8AE64FD285471560085B4CF /* IO80211WorkLoop.h in Headers */, F8AE64FE285471560085B4CF /* apple80211_var.h in Headers */, F84AD8CA2A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */, F84AD8D12A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */, F8AE64FF285471560085B4CF /* AirportItlwmInterface.hpp in Headers */, F8AE6500285471560085B4CF /* IO80211Interface.h in Headers */, F84AD88B2A497DB200DC8DED /* IO80211WorkQueue.h in Headers */, F8AE6501285471560085B4CF /* (null) in Headers */, F84AD8AE2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */, F8AE6502285471560085B4CF /* IO80211SkywalkInterface.h in Headers */, F84AD8C32A497DB200DC8DED /* CCLogStream.h in Headers */, F8AE6503285471560085B4CF /* AirportItlwm.hpp in Headers */, F89F35F72A49867F00061876 /* IO80211ControllerV2.h in Headers */, F8AE6504285471560085B4CF /* IO80211VirtualInterface.h in Headers */, F8AE6505285471560085B4CF /* IO80211Controller.h in Headers */, F8AE6506285471560085B4CF /* (null) in Headers */, F8AE6507285471560085B4CF /* ieee80211_ra.h in Headers */, F84AD8B52A497DB200DC8DED /* CCStream.h in Headers */, F8AE6508285471560085B4CF /* apple80211_wps.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; F8B210AA2A2EC2680043ECBD /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( F84AD8BD2A497DB200DC8DED /* CCDataPipe.h in Headers */, F8B210AB2A2EC2680043ECBD /* debug.h in Headers */, F8B210AC2A2EC2680043ECBD /* IOSkywalkEthernetInterface.h in Headers */, F84AD89A2A497DB200DC8DED /* IO80211InfraProtocol.h in Headers */, F84AD8A82A497DB200DC8DED /* IOSkywalkLogicalLink.h in Headers */, F8A028302A4A7E0500C6DE90 /* AirportItlwmEthernetInterface.hpp in Headers */, F84AD8932A497DB200DC8DED /* IOSkywalkNetworkPacket.h in Headers */, F8B210AD2A2EC2680043ECBD /* apple80211_ioctl.h in Headers */, F84AD8D92A497DB200DC8DED /* CCLogPipe.h in Headers */, F8B210AE2A2EC2680043ECBD /* IO80211P2PInterface.h in Headers */, F84AD8A12A497DB200DC8DED /* CCPipe.h in Headers */, F8B210AF2A2EC2680043ECBD /* IO80211WorkLoop.h in Headers */, F8B210B02A2EC2680043ECBD /* apple80211_var.h in Headers */, F84AD8CB2A497DB200DC8DED /* IOSkywalkPacketBufferPool.h in Headers */, F84AD8D22A497DB200DC8DED /* IOSkywalkLegacyEthernetInterface.h in Headers */, F8B210B12A2EC2680043ECBD /* AirportItlwmInterface.hpp in Headers */, F8B210B22A2EC2680043ECBD /* IO80211Interface.h in Headers */, F84AD88C2A497DB200DC8DED /* IO80211WorkQueue.h in Headers */, F8B210B32A2EC2680043ECBD /* (null) in Headers */, F84AD8AF2A497DB200DC8DED /* IO80211InfraInterface.h in Headers */, F8B210B42A2EC2680043ECBD /* IO80211SkywalkInterface.h in Headers */, F84AD8C42A497DB200DC8DED /* CCLogStream.h in Headers */, F8A028732A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.hpp in Headers */, F8B210B52A2EC2680043ECBD /* AirportItlwm.hpp in Headers */, F89F35F82A49867F00061876 /* IO80211ControllerV2.h in Headers */, F8A028802A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.hpp in Headers */, F8B210B62A2EC2680043ECBD /* IO80211VirtualInterface.h in Headers */, F8B210B72A2EC2680043ECBD /* IO80211Controller.h in Headers */, F8B210B82A2EC2680043ECBD /* (null) in Headers */, F8A028232A4A7DDC00C6DE90 /* AirportItlwmV2.hpp in Headers */, F8B210B92A2EC2680043ECBD /* ieee80211_ra.h in Headers */, F84AD8B62A497DB200DC8DED /* CCStream.h in Headers */, F8B210BA2A2EC2680043ECBD /* apple80211_wps.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; F8D94C832B9ABFE20081A3C4 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( F8D94C842B9ABFE20081A3C4 /* CCDataPipe.h in Headers */, F8D94C852B9ABFE20081A3C4 /* debug.h in Headers */, F8D94C862B9ABFE20081A3C4 /* IOSkywalkEthernetInterface.h in Headers */, F8D94C872B9ABFE20081A3C4 /* IO80211InfraProtocol.h in Headers */, F8D94C882B9ABFE20081A3C4 /* IOSkywalkLogicalLink.h in Headers */, F8D94C892B9ABFE20081A3C4 /* AirportItlwmEthernetInterface.hpp in Headers */, F8D94C8A2B9ABFE20081A3C4 /* IOSkywalkNetworkPacket.h in Headers */, F8D94C8B2B9ABFE20081A3C4 /* apple80211_ioctl.h in Headers */, F8D94C8C2B9ABFE20081A3C4 /* CCLogPipe.h in Headers */, F8D94C8D2B9ABFE20081A3C4 /* IO80211P2PInterface.h in Headers */, F8D94C8E2B9ABFE20081A3C4 /* CCPipe.h in Headers */, F8D94C8F2B9ABFE20081A3C4 /* IO80211WorkLoop.h in Headers */, F8D94C902B9ABFE20081A3C4 /* apple80211_var.h in Headers */, F8D94C912B9ABFE20081A3C4 /* IOSkywalkPacketBufferPool.h in Headers */, F8D94C922B9ABFE20081A3C4 /* IOSkywalkLegacyEthernetInterface.h in Headers */, F8D94C932B9ABFE20081A3C4 /* AirportItlwmInterface.hpp in Headers */, F8D94C942B9ABFE20081A3C4 /* IO80211Interface.h in Headers */, F8D94C952B9ABFE20081A3C4 /* IO80211WorkQueue.h in Headers */, F8D94C962B9ABFE20081A3C4 /* (null) in Headers */, F8D94C972B9ABFE20081A3C4 /* IO80211InfraInterface.h in Headers */, F8D94C982B9ABFE20081A3C4 /* IO80211SkywalkInterface.h in Headers */, F8D94C992B9ABFE20081A3C4 /* CCLogStream.h in Headers */, F8D94C9A2B9ABFE20081A3C4 /* AirportItlwmSkywalkInterface.hpp in Headers */, F8D94C9B2B9ABFE20081A3C4 /* AirportItlwm.hpp in Headers */, F8D94C9C2B9ABFE20081A3C4 /* IO80211ControllerV2.h in Headers */, F8D94C9D2B9ABFE20081A3C4 /* IOPCIEDeviceWrapper.hpp in Headers */, F8D94C9E2B9ABFE20081A3C4 /* IO80211VirtualInterface.h in Headers */, F8D94C9F2B9ABFE20081A3C4 /* IO80211Controller.h in Headers */, F8D94CA02B9ABFE20081A3C4 /* (null) in Headers */, F8D94CA12B9ABFE20081A3C4 /* AirportItlwmV2.hpp in Headers */, F8D94CA22B9ABFE20081A3C4 /* ieee80211_ra.h in Headers */, F8D94CA32B9ABFE20081A3C4 /* CCStream.h in Headers */, F8D94CA42B9ABFE20081A3C4 /* apple80211_wps.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 024A07AB23FCBC3C009FBA6C /* itlwm */ = { isa = PBXNativeTarget; buildConfigurationList = 024A07B623FCBC3C009FBA6C /* Build configuration list for PBXNativeTarget "itlwm" */; buildPhases = ( 024A07A723FCBC3C009FBA6C /* Headers */, 024A07A823FCBC3C009FBA6C /* Sources */, 024A07A923FCBC3C009FBA6C /* Frameworks */, 024A07AA23FCBC3C009FBA6C /* Resources */, ); buildRules = ( ); dependencies = ( 5066D63E252880A700EE6F38 /* PBXTargetDependency */, ); name = itlwm; productName = itlwm; productReference = 024A07AC23FCBC3C009FBA6C /* itlwm.kext */; productType = "com.apple.product-type.kernel-extension"; }; 35CBE655251CB89700435CBC /* AirportItlwm-Big Sur */ = { isa = PBXNativeTarget; buildConfigurationList = 35CBE6B7251CB89700435CBC /* Build configuration list for PBXNativeTarget "AirportItlwm-Big Sur" */; buildPhases = ( 35CBE658251CB89700435CBC /* Headers */, 35CBE670251CB89700435CBC /* Sources */, 35CBE6B5251CB89700435CBC /* Frameworks */, 35CBE6B6251CB89700435CBC /* Resources */, ); buildRules = ( ); dependencies = ( 5066D6462528814900EE6F38 /* PBXTargetDependency */, ); name = "AirportItlwm-Big Sur"; productName = AirportItlwm; productReference = 35CBE6BA251CB89700435CBC /* AirportItlwm.kext */; productType = "com.apple.product-type.kernel-extension"; }; 35CBE6BF251CB8BF00435CBC /* AirportItlwm-Mojave */ = { isa = PBXNativeTarget; buildConfigurationList = 35CBE721251CB8BF00435CBC /* Build configuration list for PBXNativeTarget "AirportItlwm-Mojave" */; buildPhases = ( 35CBE6C2251CB8BF00435CBC /* Headers */, 35CBE6DA251CB8BF00435CBC /* Sources */, 35CBE71F251CB8BF00435CBC /* Frameworks */, 35CBE720251CB8BF00435CBC /* Resources */, ); buildRules = ( ); dependencies = ( 5066D6422528814000EE6F38 /* PBXTargetDependency */, ); name = "AirportItlwm-Mojave"; productName = AirportItlwm; productReference = 35CBE724251CB8BF00435CBC /* AirportItlwm.kext */; productType = "com.apple.product-type.kernel-extension"; }; 35CBE72A251CB8CA00435CBC /* AirportItlwm-High Sierra */ = { isa = PBXNativeTarget; buildConfigurationList = 35CBE78C251CB8CA00435CBC /* Build configuration list for PBXNativeTarget "AirportItlwm-High Sierra" */; buildPhases = ( 35CBE72D251CB8CA00435CBC /* Headers */, 35CBE745251CB8CA00435CBC /* Sources */, 35CBE78A251CB8CA00435CBC /* Frameworks */, 35CBE78B251CB8CA00435CBC /* Resources */, ); buildRules = ( ); dependencies = ( 5066D640252880AD00EE6F38 /* PBXTargetDependency */, ); name = "AirportItlwm-High Sierra"; productName = AirportItlwm; productReference = 35CBE78F251CB8CA00435CBC /* AirportItlwm.kext */; productType = "com.apple.product-type.kernel-extension"; }; F897ECB6266EFF93005EE8F7 /* AirportItlwm-Monterey */ = { isa = PBXNativeTarget; buildConfigurationList = F897ED15266EFF93005EE8F7 /* Build configuration list for PBXNativeTarget "AirportItlwm-Monterey" */; buildPhases = ( F897ECB9266EFF93005EE8F7 /* Headers */, F897ECCA266EFF93005EE8F7 /* Sources */, F897ED12266EFF93005EE8F7 /* Frameworks */, F897ED14266EFF93005EE8F7 /* Resources */, ); buildRules = ( ); dependencies = ( F897ECB7266EFF93005EE8F7 /* PBXTargetDependency */, ); name = "AirportItlwm-Monterey"; productName = AirportItlwm; productReference = F897ED18266EFF93005EE8F7 /* AirportItlwm.kext */; productType = "com.apple.product-type.kernel-extension"; }; F89B6BB825021C9C000F77FF /* AirportItlwm-Catalina */ = { isa = PBXNativeTarget; buildConfigurationList = F89B6BC025021C9C000F77FF /* Build configuration list for PBXNativeTarget "AirportItlwm-Catalina" */; buildPhases = ( F89B6BB425021C9C000F77FF /* Headers */, F89B6BB525021C9C000F77FF /* Sources */, F89B6BB625021C9C000F77FF /* Frameworks */, F89B6BB725021C9C000F77FF /* Resources */, ); buildRules = ( ); dependencies = ( 5066D6442528814400EE6F38 /* PBXTargetDependency */, ); name = "AirportItlwm-Catalina"; productName = AirportItlwm; productReference = F89B6BB925021C9C000F77FF /* AirportItlwm.kext */; productType = "com.apple.product-type.kernel-extension"; }; F8AE64F5285471560085B4CF /* AirportItlwm-Ventura */ = { isa = PBXNativeTarget; buildConfigurationList = F8AE6555285471560085B4CF /* Build configuration list for PBXNativeTarget "AirportItlwm-Ventura" */; buildPhases = ( F8AE64F8285471560085B4CF /* Headers */, F8AE6509285471560085B4CF /* Sources */, F8AE6552285471560085B4CF /* Frameworks */, F8AE6554285471560085B4CF /* Resources */, ); buildRules = ( ); dependencies = ( F8AE64F6285471560085B4CF /* PBXTargetDependency */, ); name = "AirportItlwm-Ventura"; productName = AirportItlwm; productReference = F8AE6558285471560085B4CF /* AirportItlwm.kext */; productType = "com.apple.product-type.kernel-extension"; }; F8B210A72A2EC2680043ECBD /* AirportItlwm-Sonoma14.0 */ = { isa = PBXNativeTarget; buildConfigurationList = F8B211072A2EC2680043ECBD /* Build configuration list for PBXNativeTarget "AirportItlwm-Sonoma14.0" */; buildPhases = ( F8B210AA2A2EC2680043ECBD /* Headers */, F8B210BB2A2EC2680043ECBD /* Sources */, F8B211042A2EC2680043ECBD /* Frameworks */, F8B211062A2EC2680043ECBD /* Resources */, ); buildRules = ( ); dependencies = ( F8B210A82A2EC2680043ECBD /* PBXTargetDependency */, ); name = "AirportItlwm-Sonoma14.0"; productName = AirportItlwm; productReference = F8B2110A2A2EC2680043ECBD /* AirportItlwm.kext */; productType = "com.apple.product-type.kernel-extension"; }; F8D94C802B9ABFE20081A3C4 /* AirportItlwm-Sonoma14.4 */ = { isa = PBXNativeTarget; buildConfigurationList = F8D94CF22B9ABFE20081A3C4 /* Build configuration list for PBXNativeTarget "AirportItlwm-Sonoma14.4" */; buildPhases = ( F8D94C832B9ABFE20081A3C4 /* Headers */, F8D94CA52B9ABFE20081A3C4 /* Sources */, F8D94CEF2B9ABFE20081A3C4 /* Frameworks */, F8D94CF12B9ABFE20081A3C4 /* Resources */, ); buildRules = ( ); dependencies = ( F8D94C812B9ABFE20081A3C4 /* PBXTargetDependency */, ); name = "AirportItlwm-Sonoma14.4"; productName = AirportItlwm; productReference = F8D94CF52B9ABFE20081A3C4 /* AirportItlwm.kext */; productType = "com.apple.product-type.kernel-extension"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 024A07A323FCBC3C009FBA6C /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1110; ORGANIZATIONNAME = "钟先耀"; TargetAttributes = { 024A07AB23FCBC3C009FBA6C = { CreatedOnToolsVersion = 11.1; ProvisioningStyle = Manual; }; 35CBE655251CB89700435CBC = { ProvisioningStyle = Manual; }; 35CBE6BF251CB8BF00435CBC = { ProvisioningStyle = Manual; }; 35CBE72A251CB8CA00435CBC = { ProvisioningStyle = Manual; }; 5066D63825287F7900EE6F38 = { CreatedOnToolsVersion = 12.0; ProvisioningStyle = Manual; }; F897ECB6266EFF93005EE8F7 = { ProvisioningStyle = Manual; }; F89B6BB825021C9C000F77FF = { CreatedOnToolsVersion = 11.6; ProvisioningStyle = Manual; }; F8AE64F5285471560085B4CF = { ProvisioningStyle = Manual; }; F8B210A72A2EC2680043ECBD = { ProvisioningStyle = Manual; }; F8D94C802B9ABFE20081A3C4 = { ProvisioningStyle = Manual; }; }; }; buildConfigurationList = 024A07A623FCBC3C009FBA6C /* Build configuration list for PBXProject "itlwm" */; compatibilityVersion = "Xcode 8.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 024A07A223FCBC3C009FBA6C; productRefGroup = 024A07AD23FCBC3C009FBA6C /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 024A07AB23FCBC3C009FBA6C /* itlwm */, 35CBE72A251CB8CA00435CBC /* AirportItlwm-High Sierra */, 35CBE6BF251CB8BF00435CBC /* AirportItlwm-Mojave */, F89B6BB825021C9C000F77FF /* AirportItlwm-Catalina */, 35CBE655251CB89700435CBC /* AirportItlwm-Big Sur */, F897ECB6266EFF93005EE8F7 /* AirportItlwm-Monterey */, F8AE64F5285471560085B4CF /* AirportItlwm-Ventura */, F8B210A72A2EC2680043ECBD /* AirportItlwm-Sonoma14.0 */, F8D94C802B9ABFE20081A3C4 /* AirportItlwm-Sonoma14.4 */, 5066D63825287F7900EE6F38 /* fw_gen */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 024A07AA23FCBC3C009FBA6C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE6B6251CB89700435CBC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE720251CB8BF00435CBC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE78B251CB8CA00435CBC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; F897ED14266EFF93005EE8F7 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; F89B6BB725021C9C000F77FF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; F8AE6554285471560085B4CF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; F8B211062A2EC2680043ECBD /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; F8D94CF12B9ABFE20081A3C4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 5066D63C25287F8E00EE6F38 /* Generate Firmware */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); name = "Generate Firmware"; outputFileListPaths = ( ); outputPaths = ( "$(PROJECT_DIR)/include/FwBinary.cpp", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "scripts/fw_gen.sh -P \"${PROJECT_DIR}/itlwm/firmware/\"\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 024A07A823FCBC3C009FBA6C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( F8A4307325062CE300EA545E /* zutil.c in Sources */, F8294FE424FCBF5100239253 /* FwBinary.cpp in Sources */, F8ED134424FBB5B70068C831 /* ItlIwx.cpp in Sources */, F8C772922443439A00A1B8A0 /* compat.cpp in Sources */, 024A085223FCBC6C009FBA6C /* poly1305.c in Sources */, 024A083023FCBC6C009FBA6C /* sha2.c in Sources */, 024A085023FCBC6C009FBA6C /* arc4.c in Sources */, 024A082F23FCBC6C009FBA6C /* hmac.c in Sources */, F8C2EC5D2408031A007A9422 /* ieee80211_crypto_ccmp.c in Sources */, F8C2EC552408031A007A9422 /* ieee80211_input.c in Sources */, F8C2EC662408031A007A9422 /* ieee80211_crypto_wep.c in Sources */, F8C2EC692408031A007A9422 /* CTimeout.cpp in Sources */, F8C2EC682408031A007A9422 /* ieee80211_crypto.c in Sources */, F8C2EC602408031A007A9422 /* ieee80211_amrr.c in Sources */, F8C2EC6B2408031A007A9422 /* ieee80211_regdomain.c in Sources */, F8C2EC5B2408031A007A9422 /* ieee80211_crypto_bip.c in Sources */, F8C2EC572408031A007A9422 /* timeout.c in Sources */, F837C91D2724577F00B2C499 /* coex.cpp in Sources */, F8AF3A3124F9F35B008911C1 /* ItlIwm.cpp in Sources */, F88D2B3D2414E64000BBE700 /* sha1-pbkdf2.c in Sources */, 024A08D623FCF4D7009FBA6C /* scan.cpp in Sources */, A5FA2AE428A797B200847103 /* _ifq.cpp in Sources */, F8D364F824F93AFD0029340B /* ItlHalService.cpp in Sources */, F8C2EC6C2408031A007A9422 /* ieee80211_node.c in Sources */, 024A08C623FCDC3B009FBA6C /* tx.cpp in Sources */, 024A083423FCBC6C009FBA6C /* cast.c in Sources */, 024A08CA23FCE537009FBA6C /* phy.cpp in Sources */, F8C2EC502408031A007A9422 /* _string.c in Sources */, 024A082E23FCBC6C009FBA6C /* aes.c in Sources */, F8C2EC4F2408031A007A9422 /* ieee80211_proto.c in Sources */, 024A07B223FCBC3C009FBA6C /* itlwm.cpp in Sources */, 024A084923FCBC6C009FBA6C /* ecb_enc.c in Sources */, 024A084F23FCBC6C009FBA6C /* md5.c in Sources */, 024A083623FCBC6C009FBA6C /* michael.c in Sources */, F8C2EC672408031A007A9422 /* ieee80211_output.c in Sources */, 024A08D423FCF3E6009FBA6C /* power.cpp in Sources */, F8D257742495A33500872E4F /* _mbuf.cpp in Sources */, 024A08C823FCE2ED009FBA6C /* hw.cpp in Sources */, 024A08CE23FCE67F009FBA6C /* nvm.cpp in Sources */, 024A083D23FCBC6C009FBA6C /* sha1.c in Sources */, 17FD7F10255E4AC800611406 /* ItlIwn.cpp in Sources */, A5DD111526D93B5F00BA01EF /* rs.cpp in Sources */, 024A085923FCBC6C009FBA6C /* idgen.c in Sources */, F8C2EC522408031A007A9422 /* ieee80211_ioctl.c in Sources */, F8C594D325FD935B0007D19C /* ieee80211_ra.c in Sources */, 024A085823FCBC6C009FBA6C /* rmd160.c in Sources */, 024A084223FCBC6C009FBA6C /* cmac.c in Sources */, F8C2EC532408031A007A9422 /* ieee80211.c in Sources */, 024A084E23FCBC6C009FBA6C /* chachapoly.c in Sources */, F8F9EDE1240B7415009CB8E7 /* _task.cpp in Sources */, 024A085523FCBC6C009FBA6C /* key_wrap.c in Sources */, F8E49A14249B923500BE6868 /* ItlNetworkUserClient.cpp in Sources */, F8C2EC6D2408031A007A9422 /* ieee80211_pae_output.c in Sources */, F8C2EC5E2408031A007A9422 /* ieee80211_pae_input.c in Sources */, 024A08BE23FCD314009FBA6C /* fw.cpp in Sources */, 024A08CC23FCE5CA009FBA6C /* mac80211.cpp in Sources */, 024A083123FCBC6C009FBA6C /* rijndael.c in Sources */, 024A085723FCBC6C009FBA6C /* gmac.c in Sources */, F8C2EC592408031A007A9422 /* ieee80211_mira.c in Sources */, 024A083223FCBC6C009FBA6C /* ecb3_enc.c in Sources */, A5A0C5242A501E6800EF9328 /* arp.c in Sources */, 024A08D023FCEE88009FBA6C /* ctxt.cpp in Sources */, F8D76362244F21BB00DEA040 /* pm.cpp in Sources */, 024A08C023FCD4E2009FBA6C /* utils.cpp in Sources */, 024A08D223FCF395009FBA6C /* led.cpp in Sources */, F8C2EC542408031A007A9422 /* ieee80211_rssadapt.c in Sources */, 024A08C223FCD999009FBA6C /* io.cpp in Sources */, 024A083323FCBC6C009FBA6C /* set_key.c in Sources */, 024A08C423FCDC14009FBA6C /* rx.cpp in Sources */, F8C2EC5C2408031A007A9422 /* ieee80211_crypto_tkip.c in Sources */, 024A085123FCBC6C009FBA6C /* blf.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE670251CB89700435CBC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 35CBE671251CB89700435CBC /* _mbuf.cpp in Sources */, F8C594D725FD935B0007D19C /* ieee80211_ra.c in Sources */, 35CBE672251CB89700435CBC /* _task.cpp in Sources */, 35CBE673251CB89700435CBC /* FwBinary.cpp in Sources */, F837C9212724577F00B2C499 /* coex.cpp in Sources */, 35CBE675251CB89700435CBC /* ieee80211_proto.c in Sources */, 35CBE676251CB89700435CBC /* AirportItlwmInterface.cpp in Sources */, 35CBE677251CB89700435CBC /* _string.c in Sources */, 35CBE678251CB89700435CBC /* ieee80211_ioctl.c in Sources */, 35CBE679251CB89700435CBC /* ieee80211.c in Sources */, 35CBE67A251CB89700435CBC /* ieee80211_rssadapt.c in Sources */, 35CBE67B251CB89700435CBC /* ieee80211_input.c in Sources */, 35CBE67C251CB89700435CBC /* timeout.c in Sources */, 35CBE67D251CB89700435CBC /* ieee80211_mira.c in Sources */, 35CBE67E251CB89700435CBC /* ieee80211_crypto_bip.c in Sources */, 35CBE67F251CB89700435CBC /* ieee80211_crypto_tkip.c in Sources */, 35CBE680251CB89700435CBC /* ieee80211_crypto_ccmp.c in Sources */, 35CBE681251CB89700435CBC /* ieee80211_crypto_wep.c in Sources */, 35CBE682251CB89700435CBC /* ieee80211_pae_input.c in Sources */, 35CBE683251CB89700435CBC /* ieee80211_amrr.c in Sources */, 35CBE684251CB89700435CBC /* ieee80211_output.c in Sources */, 35CBE685251CB89700435CBC /* ieee80211_crypto.c in Sources */, 35CBE686251CB89700435CBC /* CTimeout.cpp in Sources */, 35CBE687251CB89700435CBC /* ieee80211_regdomain.c in Sources */, 35CBE688251CB89700435CBC /* ieee80211_node.c in Sources */, 35CBE689251CB89700435CBC /* ieee80211_pae_output.c in Sources */, 35CBE68A251CB89700435CBC /* sha1-pbkdf2.c in Sources */, 35CBE68B251CB89700435CBC /* aes.c in Sources */, 35CBE68C251CB89700435CBC /* hmac.c in Sources */, 35CBE68D251CB89700435CBC /* sha2.c in Sources */, 35CBE68E251CB89700435CBC /* rijndael.c in Sources */, 35CBE68F251CB89700435CBC /* ecb3_enc.c in Sources */, 35CBE690251CB89700435CBC /* set_key.c in Sources */, A5A0C5282A501E6800EF9328 /* arp.c in Sources */, 35CBE691251CB89700435CBC /* cast.c in Sources */, 35CBE692251CB89700435CBC /* michael.c in Sources */, 35CBE693251CB89700435CBC /* sha1.c in Sources */, 35CBE694251CB89700435CBC /* cmac.c in Sources */, 35CBE695251CB89700435CBC /* ecb_enc.c in Sources */, 35CBE696251CB89700435CBC /* chachapoly.c in Sources */, 35CBE697251CB89700435CBC /* md5.c in Sources */, 35CBE698251CB89700435CBC /* arc4.c in Sources */, 35CBE699251CB89700435CBC /* blf.c in Sources */, A5DD111926D93B5F00BA01EF /* rs.cpp in Sources */, 35CBE69A251CB89700435CBC /* poly1305.c in Sources */, 35CBE69B251CB89700435CBC /* key_wrap.c in Sources */, 35CBE69C251CB89700435CBC /* gmac.c in Sources */, 35CBE69D251CB89700435CBC /* rmd160.c in Sources */, 35CBE69E251CB89700435CBC /* idgen.c in Sources */, 35CBE69F251CB89700435CBC /* compat.cpp in Sources */, A5FA2AE828A797B200847103 /* _ifq.cpp in Sources */, 35CBE6A0251CB89700435CBC /* zutil.c in Sources */, 35CBE6A1251CB89700435CBC /* ItlHalService.cpp in Sources */, 35CBE6A2251CB89700435CBC /* ItlIwx.cpp in Sources */, 35CBE6A3251CB89700435CBC /* utils.cpp in Sources */, 35CBE6A4251CB89700435CBC /* fw.cpp in Sources */, 35CBE6A5251CB89700435CBC /* io.cpp in Sources */, 35CBE6A6251CB89700435CBC /* rx.cpp in Sources */, 35CBE6A7251CB89700435CBC /* tx.cpp in Sources */, 35CBE6A8251CB89700435CBC /* hw.cpp in Sources */, 17FD7F78255E547200611406 /* ItlIwn.cpp in Sources */, 35CBE6A9251CB89700435CBC /* phy.cpp in Sources */, 35CBE6AA251CB89700435CBC /* mac80211.cpp in Sources */, 35CBE6AB251CB89700435CBC /* nvm.cpp in Sources */, 35CBE6AC251CB89700435CBC /* ctxt.cpp in Sources */, 35CBE6AD251CB89700435CBC /* led.cpp in Sources */, 35CBE6AE251CB89700435CBC /* power.cpp in Sources */, 35CBE6AF251CB89700435CBC /* scan.cpp in Sources */, 35CBE6B0251CB89700435CBC /* ItlIwm.cpp in Sources */, 35CBE6B1251CB89700435CBC /* AirportSTAIOCTL.cpp in Sources */, 35CBE6B2251CB89700435CBC /* AirportItlwm.cpp in Sources */, 35CBE6B3251CB89700435CBC /* AirportVirtualIOCTL.cpp in Sources */, 35CBE6B4251CB89700435CBC /* AirportAWDL.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE6DA251CB8BF00435CBC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 35CBE6DB251CB8BF00435CBC /* _mbuf.cpp in Sources */, F8C594D525FD935B0007D19C /* ieee80211_ra.c in Sources */, 35CBE6DC251CB8BF00435CBC /* _task.cpp in Sources */, 35CBE6DD251CB8BF00435CBC /* FwBinary.cpp in Sources */, F837C91F2724577F00B2C499 /* coex.cpp in Sources */, 35CBE6DF251CB8BF00435CBC /* ieee80211_proto.c in Sources */, 35CBE6E0251CB8BF00435CBC /* AirportItlwmInterface.cpp in Sources */, 35CBE6E1251CB8BF00435CBC /* _string.c in Sources */, 35CBE6E2251CB8BF00435CBC /* ieee80211_ioctl.c in Sources */, 35CBE6E3251CB8BF00435CBC /* ieee80211.c in Sources */, 35CBE6E4251CB8BF00435CBC /* ieee80211_rssadapt.c in Sources */, 35CBE6E5251CB8BF00435CBC /* ieee80211_input.c in Sources */, 35CBE6E6251CB8BF00435CBC /* timeout.c in Sources */, 35CBE6E7251CB8BF00435CBC /* ieee80211_mira.c in Sources */, 35CBE6E8251CB8BF00435CBC /* ieee80211_crypto_bip.c in Sources */, 35CBE6E9251CB8BF00435CBC /* ieee80211_crypto_tkip.c in Sources */, 35CBE6EA251CB8BF00435CBC /* ieee80211_crypto_ccmp.c in Sources */, 35CBE6EB251CB8BF00435CBC /* ieee80211_crypto_wep.c in Sources */, 35CBE6EC251CB8BF00435CBC /* ieee80211_pae_input.c in Sources */, 35CBE6ED251CB8BF00435CBC /* ieee80211_amrr.c in Sources */, 35CBE6EE251CB8BF00435CBC /* ieee80211_output.c in Sources */, 35CBE6EF251CB8BF00435CBC /* ieee80211_crypto.c in Sources */, 35CBE6F0251CB8BF00435CBC /* CTimeout.cpp in Sources */, 35CBE6F1251CB8BF00435CBC /* ieee80211_regdomain.c in Sources */, 35CBE6F2251CB8BF00435CBC /* ieee80211_node.c in Sources */, 35CBE6F3251CB8BF00435CBC /* ieee80211_pae_output.c in Sources */, 35CBE6F4251CB8BF00435CBC /* sha1-pbkdf2.c in Sources */, 35CBE6F5251CB8BF00435CBC /* aes.c in Sources */, 35CBE6F6251CB8BF00435CBC /* hmac.c in Sources */, 35CBE6F7251CB8BF00435CBC /* sha2.c in Sources */, 35CBE6F8251CB8BF00435CBC /* rijndael.c in Sources */, 35CBE6F9251CB8BF00435CBC /* ecb3_enc.c in Sources */, 35CBE6FA251CB8BF00435CBC /* set_key.c in Sources */, A5A0C5262A501E6800EF9328 /* arp.c in Sources */, 35CBE6FB251CB8BF00435CBC /* cast.c in Sources */, 35CBE6FC251CB8BF00435CBC /* michael.c in Sources */, 35CBE6FD251CB8BF00435CBC /* sha1.c in Sources */, 35CBE6FE251CB8BF00435CBC /* cmac.c in Sources */, 35CBE6FF251CB8BF00435CBC /* ecb_enc.c in Sources */, 35CBE700251CB8BF00435CBC /* chachapoly.c in Sources */, 35CBE701251CB8BF00435CBC /* md5.c in Sources */, 35CBE702251CB8BF00435CBC /* arc4.c in Sources */, 35CBE703251CB8BF00435CBC /* blf.c in Sources */, A5DD111726D93B5F00BA01EF /* rs.cpp in Sources */, 35CBE704251CB8BF00435CBC /* poly1305.c in Sources */, 35CBE705251CB8BF00435CBC /* key_wrap.c in Sources */, 35CBE706251CB8BF00435CBC /* gmac.c in Sources */, 35CBE707251CB8BF00435CBC /* rmd160.c in Sources */, 35CBE708251CB8BF00435CBC /* idgen.c in Sources */, 35CBE709251CB8BF00435CBC /* compat.cpp in Sources */, A5FA2AE628A797B200847103 /* _ifq.cpp in Sources */, 35CBE70A251CB8BF00435CBC /* zutil.c in Sources */, 35CBE70B251CB8BF00435CBC /* ItlHalService.cpp in Sources */, 35CBE70C251CB8BF00435CBC /* ItlIwx.cpp in Sources */, 35CBE70D251CB8BF00435CBC /* utils.cpp in Sources */, 35CBE70E251CB8BF00435CBC /* fw.cpp in Sources */, 35CBE70F251CB8BF00435CBC /* io.cpp in Sources */, 35CBE710251CB8BF00435CBC /* rx.cpp in Sources */, 35CBE711251CB8BF00435CBC /* tx.cpp in Sources */, 35CBE712251CB8BF00435CBC /* hw.cpp in Sources */, 17FD7F6A255E547100611406 /* ItlIwn.cpp in Sources */, 35CBE713251CB8BF00435CBC /* phy.cpp in Sources */, 35CBE714251CB8BF00435CBC /* mac80211.cpp in Sources */, 35CBE715251CB8BF00435CBC /* nvm.cpp in Sources */, 35CBE716251CB8BF00435CBC /* ctxt.cpp in Sources */, 35CBE717251CB8BF00435CBC /* led.cpp in Sources */, 35CBE718251CB8BF00435CBC /* power.cpp in Sources */, 35CBE719251CB8BF00435CBC /* scan.cpp in Sources */, 35CBE71A251CB8BF00435CBC /* ItlIwm.cpp in Sources */, 35CBE71B251CB8BF00435CBC /* AirportSTAIOCTL.cpp in Sources */, 35CBE71C251CB8BF00435CBC /* AirportItlwm.cpp in Sources */, 35CBE71D251CB8BF00435CBC /* AirportVirtualIOCTL.cpp in Sources */, 35CBE71E251CB8BF00435CBC /* AirportAWDL.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 35CBE745251CB8CA00435CBC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 35CBE746251CB8CA00435CBC /* _mbuf.cpp in Sources */, F8C594D425FD935B0007D19C /* ieee80211_ra.c in Sources */, 35CBE747251CB8CA00435CBC /* _task.cpp in Sources */, 35CBE748251CB8CA00435CBC /* FwBinary.cpp in Sources */, F837C91E2724577F00B2C499 /* coex.cpp in Sources */, 35CBE74A251CB8CA00435CBC /* ieee80211_proto.c in Sources */, 35CBE74B251CB8CA00435CBC /* AirportItlwmInterface.cpp in Sources */, 35CBE74C251CB8CA00435CBC /* _string.c in Sources */, 35CBE74D251CB8CA00435CBC /* ieee80211_ioctl.c in Sources */, 35CBE74E251CB8CA00435CBC /* ieee80211.c in Sources */, 35CBE74F251CB8CA00435CBC /* ieee80211_rssadapt.c in Sources */, 35CBE750251CB8CA00435CBC /* ieee80211_input.c in Sources */, 35CBE751251CB8CA00435CBC /* timeout.c in Sources */, 35CBE752251CB8CA00435CBC /* ieee80211_mira.c in Sources */, 35CBE753251CB8CA00435CBC /* ieee80211_crypto_bip.c in Sources */, 35CBE754251CB8CA00435CBC /* ieee80211_crypto_tkip.c in Sources */, 35CBE755251CB8CA00435CBC /* ieee80211_crypto_ccmp.c in Sources */, 35CBE756251CB8CA00435CBC /* ieee80211_crypto_wep.c in Sources */, 35CBE757251CB8CA00435CBC /* ieee80211_pae_input.c in Sources */, 35CBE758251CB8CA00435CBC /* ieee80211_amrr.c in Sources */, 35CBE759251CB8CA00435CBC /* ieee80211_output.c in Sources */, 35CBE75A251CB8CA00435CBC /* ieee80211_crypto.c in Sources */, 35CBE75B251CB8CA00435CBC /* CTimeout.cpp in Sources */, 35CBE75C251CB8CA00435CBC /* ieee80211_regdomain.c in Sources */, 35CBE75D251CB8CA00435CBC /* ieee80211_node.c in Sources */, 35CBE75E251CB8CA00435CBC /* ieee80211_pae_output.c in Sources */, 35CBE75F251CB8CA00435CBC /* sha1-pbkdf2.c in Sources */, 35CBE760251CB8CA00435CBC /* aes.c in Sources */, 35CBE761251CB8CA00435CBC /* hmac.c in Sources */, 35CBE762251CB8CA00435CBC /* sha2.c in Sources */, 35CBE763251CB8CA00435CBC /* rijndael.c in Sources */, 35CBE764251CB8CA00435CBC /* ecb3_enc.c in Sources */, 35CBE765251CB8CA00435CBC /* set_key.c in Sources */, A5A0C5252A501E6800EF9328 /* arp.c in Sources */, 35CBE766251CB8CA00435CBC /* cast.c in Sources */, 35CBE767251CB8CA00435CBC /* michael.c in Sources */, 35CBE768251CB8CA00435CBC /* sha1.c in Sources */, 35CBE769251CB8CA00435CBC /* cmac.c in Sources */, 35CBE76A251CB8CA00435CBC /* ecb_enc.c in Sources */, 35CBE76B251CB8CA00435CBC /* chachapoly.c in Sources */, 35CBE76C251CB8CA00435CBC /* md5.c in Sources */, 35CBE76D251CB8CA00435CBC /* arc4.c in Sources */, 35CBE76E251CB8CA00435CBC /* blf.c in Sources */, A5DD111626D93B5F00BA01EF /* rs.cpp in Sources */, 35CBE76F251CB8CA00435CBC /* poly1305.c in Sources */, 35CBE770251CB8CA00435CBC /* key_wrap.c in Sources */, 35CBE771251CB8CA00435CBC /* gmac.c in Sources */, 35CBE772251CB8CA00435CBC /* rmd160.c in Sources */, 35CBE773251CB8CA00435CBC /* idgen.c in Sources */, 35CBE774251CB8CA00435CBC /* compat.cpp in Sources */, A5FA2AE528A797B200847103 /* _ifq.cpp in Sources */, 35CBE775251CB8CA00435CBC /* zutil.c in Sources */, 35CBE776251CB8CA00435CBC /* ItlHalService.cpp in Sources */, 35CBE777251CB8CA00435CBC /* ItlIwx.cpp in Sources */, 35CBE778251CB8CA00435CBC /* utils.cpp in Sources */, 35CBE779251CB8CA00435CBC /* fw.cpp in Sources */, 35CBE77A251CB8CA00435CBC /* io.cpp in Sources */, 35CBE77B251CB8CA00435CBC /* rx.cpp in Sources */, 35CBE77C251CB8CA00435CBC /* tx.cpp in Sources */, 35CBE77D251CB8CA00435CBC /* hw.cpp in Sources */, 17FD7F63255E547100611406 /* ItlIwn.cpp in Sources */, 35CBE77E251CB8CA00435CBC /* phy.cpp in Sources */, 35CBE77F251CB8CA00435CBC /* mac80211.cpp in Sources */, 35CBE780251CB8CA00435CBC /* nvm.cpp in Sources */, 35CBE781251CB8CA00435CBC /* ctxt.cpp in Sources */, 35CBE782251CB8CA00435CBC /* led.cpp in Sources */, 35CBE783251CB8CA00435CBC /* power.cpp in Sources */, 35CBE784251CB8CA00435CBC /* scan.cpp in Sources */, 35CBE785251CB8CA00435CBC /* ItlIwm.cpp in Sources */, 35CBE786251CB8CA00435CBC /* AirportSTAIOCTL.cpp in Sources */, 35CBE787251CB8CA00435CBC /* AirportItlwm.cpp in Sources */, 35CBE788251CB8CA00435CBC /* AirportVirtualIOCTL.cpp in Sources */, 35CBE789251CB8CA00435CBC /* AirportAWDL.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; F897ECCA266EFF93005EE8F7 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( F897ECCB266EFF93005EE8F7 /* _mbuf.cpp in Sources */, F897ECCC266EFF93005EE8F7 /* ieee80211_ra.c in Sources */, F897ECCD266EFF93005EE8F7 /* _task.cpp in Sources */, F897ECCE266EFF93005EE8F7 /* FwBinary.cpp in Sources */, F897ECD0266EFF93005EE8F7 /* ieee80211_proto.c in Sources */, F897ECD1266EFF93005EE8F7 /* AirportItlwmInterface.cpp in Sources */, F897ECD2266EFF93005EE8F7 /* _string.c in Sources */, F897ECD3266EFF93005EE8F7 /* ieee80211_ioctl.c in Sources */, F897ECD4266EFF93005EE8F7 /* ieee80211.c in Sources */, F897ECD5266EFF93005EE8F7 /* ieee80211_rssadapt.c in Sources */, F897ECD6266EFF93005EE8F7 /* ieee80211_input.c in Sources */, F897ECD7266EFF93005EE8F7 /* timeout.c in Sources */, F897ECD8266EFF93005EE8F7 /* ieee80211_mira.c in Sources */, F897ECD9266EFF93005EE8F7 /* ieee80211_crypto_bip.c in Sources */, F897ECDA266EFF93005EE8F7 /* ieee80211_crypto_tkip.c in Sources */, F897ECDB266EFF93005EE8F7 /* ieee80211_crypto_ccmp.c in Sources */, F897ECDC266EFF93005EE8F7 /* ieee80211_crypto_wep.c in Sources */, F897ECDD266EFF93005EE8F7 /* ieee80211_pae_input.c in Sources */, F897ECDE266EFF93005EE8F7 /* ieee80211_amrr.c in Sources */, F897ECDF266EFF93005EE8F7 /* ieee80211_output.c in Sources */, F897ECE0266EFF93005EE8F7 /* ieee80211_crypto.c in Sources */, F897ECE1266EFF93005EE8F7 /* CTimeout.cpp in Sources */, F897ECE2266EFF93005EE8F7 /* ieee80211_regdomain.c in Sources */, F897ECE3266EFF93005EE8F7 /* ieee80211_node.c in Sources */, F897ECE4266EFF93005EE8F7 /* ieee80211_pae_output.c in Sources */, F897ECE5266EFF93005EE8F7 /* sha1-pbkdf2.c in Sources */, F897ECE6266EFF93005EE8F7 /* aes.c in Sources */, F897ECE7266EFF93005EE8F7 /* hmac.c in Sources */, F897ECE8266EFF93005EE8F7 /* sha2.c in Sources */, F897ECE9266EFF93005EE8F7 /* rijndael.c in Sources */, F897ECEA266EFF93005EE8F7 /* ecb3_enc.c in Sources */, F897ECEB266EFF93005EE8F7 /* set_key.c in Sources */, F897ECEC266EFF93005EE8F7 /* cast.c in Sources */, F897ECED266EFF93005EE8F7 /* michael.c in Sources */, F897ECEE266EFF93005EE8F7 /* sha1.c in Sources */, A5DD111A26D93B5F00BA01EF /* rs.cpp in Sources */, F897ECEF266EFF93005EE8F7 /* cmac.c in Sources */, F897ECF0266EFF93005EE8F7 /* ecb_enc.c in Sources */, F897ECF1266EFF93005EE8F7 /* chachapoly.c in Sources */, F897ECF2266EFF93005EE8F7 /* (null) in Sources */, F897ECF3266EFF93005EE8F7 /* md5.c in Sources */, F897ECF4266EFF93005EE8F7 /* arc4.c in Sources */, F897ECF5266EFF93005EE8F7 /* blf.c in Sources */, A5FA2AE928A797B200847103 /* _ifq.cpp in Sources */, F897ECF6266EFF93005EE8F7 /* poly1305.c in Sources */, F897ECF7266EFF93005EE8F7 /* key_wrap.c in Sources */, F897ECF8266EFF93005EE8F7 /* gmac.c in Sources */, F897ECF9266EFF93005EE8F7 /* rmd160.c in Sources */, F897ECFA266EFF93005EE8F7 /* idgen.c in Sources */, F897ECFB266EFF93005EE8F7 /* compat.cpp in Sources */, F897ECFC266EFF93005EE8F7 /* zutil.c in Sources */, F897ECFD266EFF93005EE8F7 /* ItlHalService.cpp in Sources */, F897ECFE266EFF93005EE8F7 /* ItlIwx.cpp in Sources */, F897ECFF266EFF93005EE8F7 /* utils.cpp in Sources */, F897ED00266EFF93005EE8F7 /* fw.cpp in Sources */, F897ED01266EFF93005EE8F7 /* io.cpp in Sources */, F897ED02266EFF93005EE8F7 /* rx.cpp in Sources */, F837C9222724577F00B2C499 /* coex.cpp in Sources */, F897ED03266EFF93005EE8F7 /* tx.cpp in Sources */, F897ED04266EFF93005EE8F7 /* hw.cpp in Sources */, F897ED05266EFF93005EE8F7 /* ItlIwn.cpp in Sources */, F897ED06266EFF93005EE8F7 /* phy.cpp in Sources */, F897ED07266EFF93005EE8F7 /* mac80211.cpp in Sources */, F897ED08266EFF93005EE8F7 /* nvm.cpp in Sources */, F897ED09266EFF93005EE8F7 /* ctxt.cpp in Sources */, F897ED0A266EFF93005EE8F7 /* led.cpp in Sources */, F897ED0B266EFF93005EE8F7 /* power.cpp in Sources */, F897ED0C266EFF93005EE8F7 /* scan.cpp in Sources */, A5A0C5292A501E6800EF9328 /* arp.c in Sources */, F897ED0D266EFF93005EE8F7 /* ItlIwm.cpp in Sources */, F897ED0E266EFF93005EE8F7 /* AirportSTAIOCTL.cpp in Sources */, F897ED0F266EFF93005EE8F7 /* AirportItlwm.cpp in Sources */, F897ED10266EFF93005EE8F7 /* AirportVirtualIOCTL.cpp in Sources */, F897ED11266EFF93005EE8F7 /* AirportAWDL.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; F89B6BB525021C9C000F77FF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( F89B6C20250232DC000F77FF /* _mbuf.cpp in Sources */, F8C594D625FD935B0007D19C /* ieee80211_ra.c in Sources */, F89B6C21250232DC000F77FF /* _task.cpp in Sources */, F89B6BF3250231E3000F77FF /* FwBinary.cpp in Sources */, F837C9202724577F00B2C499 /* coex.cpp in Sources */, F89B6BF5250231E3000F77FF /* ieee80211_proto.c in Sources */, F8CA44A325091AF60036119A /* AirportItlwmInterface.cpp in Sources */, F89B6BF6250231E3000F77FF /* _string.c in Sources */, F89B6BF7250231E3000F77FF /* ieee80211_ioctl.c in Sources */, F89B6BF8250231E3000F77FF /* ieee80211.c in Sources */, F89B6BF9250231E3000F77FF /* ieee80211_rssadapt.c in Sources */, F89B6BFA250231E3000F77FF /* ieee80211_input.c in Sources */, F89B6BFB250231E3000F77FF /* timeout.c in Sources */, F89B6BFC250231E3000F77FF /* ieee80211_mira.c in Sources */, F89B6BFD250231E3000F77FF /* ieee80211_crypto_bip.c in Sources */, F89B6BFE250231E3000F77FF /* ieee80211_crypto_tkip.c in Sources */, F89B6BFF250231E3000F77FF /* ieee80211_crypto_ccmp.c in Sources */, F89B6C00250231E3000F77FF /* ieee80211_crypto_wep.c in Sources */, F89B6C01250231E3000F77FF /* ieee80211_pae_input.c in Sources */, F89B6C02250231E3000F77FF /* ieee80211_amrr.c in Sources */, F89B6C03250231E3000F77FF /* ieee80211_output.c in Sources */, F89B6C04250231E3000F77FF /* ieee80211_crypto.c in Sources */, F89B6C05250231E3000F77FF /* CTimeout.cpp in Sources */, F89B6C06250231E3000F77FF /* ieee80211_regdomain.c in Sources */, F89B6C07250231E4000F77FF /* ieee80211_node.c in Sources */, F89B6C08250231E4000F77FF /* ieee80211_pae_output.c in Sources */, F89B6C09250231E4000F77FF /* sha1-pbkdf2.c in Sources */, F89B6C0A250231E4000F77FF /* aes.c in Sources */, F89B6C0B250231E4000F77FF /* hmac.c in Sources */, F89B6C0C250231E4000F77FF /* sha2.c in Sources */, F89B6C0D250231E4000F77FF /* rijndael.c in Sources */, F89B6C0E250231E4000F77FF /* ecb3_enc.c in Sources */, F89B6C0F250231E4000F77FF /* set_key.c in Sources */, A5A0C5272A501E6800EF9328 /* arp.c in Sources */, F89B6C10250231E4000F77FF /* cast.c in Sources */, F89B6C11250231E4000F77FF /* michael.c in Sources */, F89B6C12250231E4000F77FF /* sha1.c in Sources */, F89B6C13250231E4000F77FF /* cmac.c in Sources */, F89B6C14250231E4000F77FF /* ecb_enc.c in Sources */, F89B6C15250231E4000F77FF /* chachapoly.c in Sources */, F89B6C16250231E4000F77FF /* md5.c in Sources */, F89B6C17250231E4000F77FF /* arc4.c in Sources */, F89B6C18250231E4000F77FF /* blf.c in Sources */, A5DD111826D93B5F00BA01EF /* rs.cpp in Sources */, F89B6C19250231E4000F77FF /* poly1305.c in Sources */, F89B6C1A250231E4000F77FF /* key_wrap.c in Sources */, F89B6C1B250231E4000F77FF /* gmac.c in Sources */, F89B6C1C250231E4000F77FF /* rmd160.c in Sources */, F89B6C1D250231E4000F77FF /* idgen.c in Sources */, F89B6C1E250231E4000F77FF /* compat.cpp in Sources */, A5FA2AE728A797B200847103 /* _ifq.cpp in Sources */, F89B6C1F250231E4000F77FF /* zutil.c in Sources */, F89B6BF12502316A000F77FF /* ItlHalService.cpp in Sources */, F89B6BF025023162000F77FF /* ItlIwx.cpp in Sources */, F89B6BE22502315B000F77FF /* utils.cpp in Sources */, F89B6BE32502315B000F77FF /* fw.cpp in Sources */, F89B6BE42502315B000F77FF /* io.cpp in Sources */, F89B6BE52502315B000F77FF /* rx.cpp in Sources */, F89B6BE62502315B000F77FF /* tx.cpp in Sources */, F89B6BE72502315B000F77FF /* hw.cpp in Sources */, 17FD7F71255E547200611406 /* ItlIwn.cpp in Sources */, F89B6BE82502315B000F77FF /* phy.cpp in Sources */, F89B6BE92502315B000F77FF /* mac80211.cpp in Sources */, F89B6BEA2502315B000F77FF /* nvm.cpp in Sources */, F89B6BEB2502315B000F77FF /* ctxt.cpp in Sources */, F89B6BEC2502315B000F77FF /* led.cpp in Sources */, F89B6BED2502315B000F77FF /* power.cpp in Sources */, F89B6BEE2502315B000F77FF /* scan.cpp in Sources */, F89B6BEF2502315B000F77FF /* ItlIwm.cpp in Sources */, F89B6BDD25022F8C000F77FF /* AirportSTAIOCTL.cpp in Sources */, F89B6BBE25021C9C000F77FF /* AirportItlwm.cpp in Sources */, F89B6BDF25022FB5000F77FF /* AirportVirtualIOCTL.cpp in Sources */, F89B6BE125022FC7000F77FF /* AirportAWDL.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; F8AE6509285471560085B4CF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( F8876A4E28B71F5400A21E42 /* rs.cpp in Sources */, F8AE650A285471560085B4CF /* _mbuf.cpp in Sources */, F8AE650B285471560085B4CF /* ieee80211_ra.c in Sources */, F8AE650C285471560085B4CF /* _task.cpp in Sources */, F8AE650D285471560085B4CF /* FwBinary.cpp in Sources */, F8AE650F285471560085B4CF /* ieee80211_proto.c in Sources */, F8AE6510285471560085B4CF /* AirportItlwmInterface.cpp in Sources */, F8AE6511285471560085B4CF /* _string.c in Sources */, F8AE6512285471560085B4CF /* ieee80211_ioctl.c in Sources */, F8AE6513285471560085B4CF /* ieee80211.c in Sources */, F8AE6514285471560085B4CF /* ieee80211_rssadapt.c in Sources */, F8AE6515285471560085B4CF /* ieee80211_input.c in Sources */, F8AE6516285471560085B4CF /* timeout.c in Sources */, F8AE6517285471560085B4CF /* ieee80211_mira.c in Sources */, F8AE6518285471560085B4CF /* ieee80211_crypto_bip.c in Sources */, F8AE6519285471560085B4CF /* ieee80211_crypto_tkip.c in Sources */, F8AE651A285471560085B4CF /* ieee80211_crypto_ccmp.c in Sources */, F8AE651B285471560085B4CF /* ieee80211_crypto_wep.c in Sources */, F8AE651C285471560085B4CF /* ieee80211_pae_input.c in Sources */, F8AE651D285471560085B4CF /* ieee80211_amrr.c in Sources */, F8AE651E285471560085B4CF /* ieee80211_output.c in Sources */, F8AE651F285471560085B4CF /* ieee80211_crypto.c in Sources */, F8AE6520285471560085B4CF /* CTimeout.cpp in Sources */, F8AE6521285471560085B4CF /* ieee80211_regdomain.c in Sources */, F8AE6522285471560085B4CF /* ieee80211_node.c in Sources */, F8AE6523285471560085B4CF /* ieee80211_pae_output.c in Sources */, F8AE6524285471560085B4CF /* sha1-pbkdf2.c in Sources */, F8AE6525285471560085B4CF /* aes.c in Sources */, F8AE6526285471560085B4CF /* hmac.c in Sources */, F8AE6527285471560085B4CF /* sha2.c in Sources */, F8AE6528285471560085B4CF /* rijndael.c in Sources */, F8AE6529285471560085B4CF /* ecb3_enc.c in Sources */, F8AE652A285471560085B4CF /* set_key.c in Sources */, F8AE652B285471560085B4CF /* cast.c in Sources */, F8AE652C285471560085B4CF /* michael.c in Sources */, F8AE652D285471560085B4CF /* sha1.c in Sources */, F8AE652E285471560085B4CF /* cmac.c in Sources */, F8AE652F285471560085B4CF /* ecb_enc.c in Sources */, F8AE6530285471560085B4CF /* chachapoly.c in Sources */, F8AE6531285471560085B4CF /* (null) in Sources */, F8AE6532285471560085B4CF /* md5.c in Sources */, F8AE6533285471560085B4CF /* arc4.c in Sources */, F8AE6534285471560085B4CF /* blf.c in Sources */, A5FA2AEA28A797B200847103 /* _ifq.cpp in Sources */, F8AE6535285471560085B4CF /* poly1305.c in Sources */, F8AE6536285471560085B4CF /* key_wrap.c in Sources */, F8AE6537285471560085B4CF /* gmac.c in Sources */, F8AE6538285471560085B4CF /* rmd160.c in Sources */, F8AE6539285471560085B4CF /* idgen.c in Sources */, F8AE653A285471560085B4CF /* compat.cpp in Sources */, F8AE653B285471560085B4CF /* zutil.c in Sources */, F8AE653C285471560085B4CF /* ItlHalService.cpp in Sources */, F8AE653D285471560085B4CF /* ItlIwx.cpp in Sources */, F8AE653E285471560085B4CF /* utils.cpp in Sources */, F8AE653F285471560085B4CF /* fw.cpp in Sources */, F8AE6540285471560085B4CF /* io.cpp in Sources */, F8AE6541285471560085B4CF /* rx.cpp in Sources */, F8AE6542285471560085B4CF /* coex.cpp in Sources */, F8AE6543285471560085B4CF /* tx.cpp in Sources */, F8AE6544285471560085B4CF /* hw.cpp in Sources */, F8AE6545285471560085B4CF /* ItlIwn.cpp in Sources */, F8AE6546285471560085B4CF /* phy.cpp in Sources */, F8AE6547285471560085B4CF /* mac80211.cpp in Sources */, F8AE6548285471560085B4CF /* nvm.cpp in Sources */, F8AE6549285471560085B4CF /* ctxt.cpp in Sources */, F8AE654A285471560085B4CF /* led.cpp in Sources */, F8AE654B285471560085B4CF /* power.cpp in Sources */, F8AE654C285471560085B4CF /* scan.cpp in Sources */, A5A0C52A2A501E6800EF9328 /* arp.c in Sources */, F8AE654D285471560085B4CF /* ItlIwm.cpp in Sources */, F8AE654E285471560085B4CF /* AirportSTAIOCTL.cpp in Sources */, F8AE654F285471560085B4CF /* AirportItlwm.cpp in Sources */, F8AE6550285471560085B4CF /* AirportVirtualIOCTL.cpp in Sources */, F8AE6551285471560085B4CF /* AirportAWDL.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; F8B210BB2A2EC2680043ECBD /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( F8F84F682ADE26F1002808DE /* rs.cpp in Sources */, F8B210BC2A2EC2680043ECBD /* _mbuf.cpp in Sources */, F8B210BD2A2EC2680043ECBD /* ieee80211_ra.c in Sources */, F8B210BE2A2EC2680043ECBD /* _task.cpp in Sources */, F8B210BF2A2EC2680043ECBD /* FwBinary.cpp in Sources */, F8B210C02A2EC2680043ECBD /* ieee80211_proto.c in Sources */, F8B210C22A2EC2680043ECBD /* _string.c in Sources */, F8B210C32A2EC2680043ECBD /* ieee80211_ioctl.c in Sources */, F8B210C42A2EC2680043ECBD /* ieee80211.c in Sources */, F8B210C52A2EC2680043ECBD /* ieee80211_rssadapt.c in Sources */, F8B210C62A2EC2680043ECBD /* ieee80211_input.c in Sources */, F8B210C72A2EC2680043ECBD /* timeout.c in Sources */, F8B210C82A2EC2680043ECBD /* ieee80211_mira.c in Sources */, F8B210C92A2EC2680043ECBD /* ieee80211_crypto_bip.c in Sources */, F8B210CA2A2EC2680043ECBD /* ieee80211_crypto_tkip.c in Sources */, F8B210CB2A2EC2680043ECBD /* ieee80211_crypto_ccmp.c in Sources */, F8B210CC2A2EC2680043ECBD /* ieee80211_crypto_wep.c in Sources */, F8B210CD2A2EC2680043ECBD /* ieee80211_pae_input.c in Sources */, F8B210CE2A2EC2680043ECBD /* ieee80211_amrr.c in Sources */, F8B210CF2A2EC2680043ECBD /* ieee80211_output.c in Sources */, F8B210D02A2EC2680043ECBD /* ieee80211_crypto.c in Sources */, F8B210D12A2EC2680043ECBD /* CTimeout.cpp in Sources */, F8B210D22A2EC2680043ECBD /* ieee80211_regdomain.c in Sources */, F8B210D32A2EC2680043ECBD /* ieee80211_node.c in Sources */, F8B210D42A2EC2680043ECBD /* ieee80211_pae_output.c in Sources */, F8B210D52A2EC2680043ECBD /* sha1-pbkdf2.c in Sources */, F8B210D62A2EC2680043ECBD /* aes.c in Sources */, F8B210D72A2EC2680043ECBD /* hmac.c in Sources */, F8B210D82A2EC2680043ECBD /* sha2.c in Sources */, F8B210D92A2EC2680043ECBD /* rijndael.c in Sources */, F8B210DA2A2EC2680043ECBD /* ecb3_enc.c in Sources */, F8B210DB2A2EC2680043ECBD /* set_key.c in Sources */, F8B210DC2A2EC2680043ECBD /* cast.c in Sources */, F8B210DD2A2EC2680043ECBD /* michael.c in Sources */, A5A0C52B2A501E6800EF9328 /* arp.c in Sources */, F8B210DE2A2EC2680043ECBD /* sha1.c in Sources */, F8B210DF2A2EC2680043ECBD /* cmac.c in Sources */, F8B210E02A2EC2680043ECBD /* ecb_enc.c in Sources */, F8B210E12A2EC2680043ECBD /* chachapoly.c in Sources */, F8A028222A4A7DDC00C6DE90 /* AirportItlwmV2.cpp in Sources */, F8B210E22A2EC2680043ECBD /* (null) in Sources */, F8B210E32A2EC2680043ECBD /* md5.c in Sources */, F8B210E42A2EC2680043ECBD /* arc4.c in Sources */, F8A0282F2A4A7E0400C6DE90 /* AirportItlwmEthernetInterface.cpp in Sources */, F8A028722A4A7FE100C6DE90 /* AirportItlwmSkywalkInterface.cpp in Sources */, F8B210E52A2EC2680043ECBD /* blf.c in Sources */, F8B210E62A2EC2680043ECBD /* _ifq.cpp in Sources */, F8B210E72A2EC2680043ECBD /* poly1305.c in Sources */, F8B210E82A2EC2680043ECBD /* key_wrap.c in Sources */, F8B210E92A2EC2680043ECBD /* gmac.c in Sources */, F8B210EA2A2EC2680043ECBD /* rmd160.c in Sources */, F8B210EB2A2EC2680043ECBD /* idgen.c in Sources */, F8B210EC2A2EC2680043ECBD /* compat.cpp in Sources */, F8B210ED2A2EC2680043ECBD /* zutil.c in Sources */, F8B210EE2A2EC2680043ECBD /* ItlHalService.cpp in Sources */, F8B210EF2A2EC2680043ECBD /* ItlIwx.cpp in Sources */, F8B210F02A2EC2680043ECBD /* utils.cpp in Sources */, F8B210F12A2EC2680043ECBD /* fw.cpp in Sources */, F8B210F22A2EC2680043ECBD /* io.cpp in Sources */, F8B210F32A2EC2680043ECBD /* rx.cpp in Sources */, F8B210F42A2EC2680043ECBD /* coex.cpp in Sources */, F8B210F52A2EC2680043ECBD /* tx.cpp in Sources */, F8B210F62A2EC2680043ECBD /* hw.cpp in Sources */, F8B210F72A2EC2680043ECBD /* ItlIwn.cpp in Sources */, F8B210F82A2EC2680043ECBD /* phy.cpp in Sources */, F8B210F92A2EC2680043ECBD /* mac80211.cpp in Sources */, F8B210FA2A2EC2680043ECBD /* nvm.cpp in Sources */, F8B210FB2A2EC2680043ECBD /* ctxt.cpp in Sources */, F8B210FC2A2EC2680043ECBD /* led.cpp in Sources */, F8B210FD2A2EC2680043ECBD /* power.cpp in Sources */, F8B210FE2A2EC2680043ECBD /* scan.cpp in Sources */, F8A0287F2A4A80EA00C6DE90 /* IOPCIEDeviceWrapper.cpp in Sources */, F8B210FF2A2EC2680043ECBD /* ItlIwm.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; F8D94CA52B9ABFE20081A3C4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( F8D94CA62B9ABFE20081A3C4 /* rs.cpp in Sources */, F8D94CA72B9ABFE20081A3C4 /* _mbuf.cpp in Sources */, F8D94CA82B9ABFE20081A3C4 /* ieee80211_ra.c in Sources */, F8D94CA92B9ABFE20081A3C4 /* _task.cpp in Sources */, F8D94CAA2B9ABFE20081A3C4 /* FwBinary.cpp in Sources */, F8D94CAB2B9ABFE20081A3C4 /* ieee80211_proto.c in Sources */, F8D94CAC2B9ABFE20081A3C4 /* _string.c in Sources */, F8D94CAD2B9ABFE20081A3C4 /* ieee80211_ioctl.c in Sources */, F8D94CAE2B9ABFE20081A3C4 /* ieee80211.c in Sources */, F8D94CAF2B9ABFE20081A3C4 /* ieee80211_rssadapt.c in Sources */, F8D94CB02B9ABFE20081A3C4 /* ieee80211_input.c in Sources */, F8D94CB12B9ABFE20081A3C4 /* timeout.c in Sources */, F8D94CB22B9ABFE20081A3C4 /* ieee80211_mira.c in Sources */, F8D94CB32B9ABFE20081A3C4 /* ieee80211_crypto_bip.c in Sources */, F8D94CB42B9ABFE20081A3C4 /* ieee80211_crypto_tkip.c in Sources */, F8D94CB52B9ABFE20081A3C4 /* ieee80211_crypto_ccmp.c in Sources */, F8D94CB62B9ABFE20081A3C4 /* ieee80211_crypto_wep.c in Sources */, F8D94CB72B9ABFE20081A3C4 /* ieee80211_pae_input.c in Sources */, F8D94CB82B9ABFE20081A3C4 /* ieee80211_amrr.c in Sources */, F8D94CB92B9ABFE20081A3C4 /* ieee80211_output.c in Sources */, F8D94CBA2B9ABFE20081A3C4 /* ieee80211_crypto.c in Sources */, F8D94CBB2B9ABFE20081A3C4 /* CTimeout.cpp in Sources */, F8D94CBC2B9ABFE20081A3C4 /* ieee80211_regdomain.c in Sources */, F8D94CBD2B9ABFE20081A3C4 /* ieee80211_node.c in Sources */, F8D94CBE2B9ABFE20081A3C4 /* ieee80211_pae_output.c in Sources */, F8D94CBF2B9ABFE20081A3C4 /* sha1-pbkdf2.c in Sources */, F8D94CC02B9ABFE20081A3C4 /* aes.c in Sources */, F8D94CC12B9ABFE20081A3C4 /* hmac.c in Sources */, F8D94CC22B9ABFE20081A3C4 /* sha2.c in Sources */, F8D94CC32B9ABFE20081A3C4 /* rijndael.c in Sources */, F8D94CC42B9ABFE20081A3C4 /* ecb3_enc.c in Sources */, F8D94CC52B9ABFE20081A3C4 /* set_key.c in Sources */, F8D94CC62B9ABFE20081A3C4 /* cast.c in Sources */, F8D94CC72B9ABFE20081A3C4 /* michael.c in Sources */, F8D94CC82B9ABFE20081A3C4 /* arp.c in Sources */, F8D94CC92B9ABFE20081A3C4 /* sha1.c in Sources */, F8D94CCA2B9ABFE20081A3C4 /* cmac.c in Sources */, F8D94CCB2B9ABFE20081A3C4 /* ecb_enc.c in Sources */, F8D94CCC2B9ABFE20081A3C4 /* chachapoly.c in Sources */, F8D94CCD2B9ABFE20081A3C4 /* AirportItlwmV2.cpp in Sources */, F8D94CCE2B9ABFE20081A3C4 /* (null) in Sources */, F8D94CCF2B9ABFE20081A3C4 /* md5.c in Sources */, F8D94CD02B9ABFE20081A3C4 /* arc4.c in Sources */, F8D94CD12B9ABFE20081A3C4 /* AirportItlwmEthernetInterface.cpp in Sources */, F8D94CD22B9ABFE20081A3C4 /* AirportItlwmSkywalkInterface.cpp in Sources */, F8D94CD32B9ABFE20081A3C4 /* blf.c in Sources */, F8D94CD42B9ABFE20081A3C4 /* _ifq.cpp in Sources */, F8D94CD52B9ABFE20081A3C4 /* poly1305.c in Sources */, F8D94CD62B9ABFE20081A3C4 /* key_wrap.c in Sources */, F8D94CD72B9ABFE20081A3C4 /* gmac.c in Sources */, F8D94CD82B9ABFE20081A3C4 /* rmd160.c in Sources */, F8D94CD92B9ABFE20081A3C4 /* idgen.c in Sources */, F8D94CDA2B9ABFE20081A3C4 /* compat.cpp in Sources */, F8D94CDB2B9ABFE20081A3C4 /* zutil.c in Sources */, F8D94CDC2B9ABFE20081A3C4 /* ItlHalService.cpp in Sources */, F8D94CDD2B9ABFE20081A3C4 /* ItlIwx.cpp in Sources */, F8D94CDE2B9ABFE20081A3C4 /* utils.cpp in Sources */, F8D94CDF2B9ABFE20081A3C4 /* fw.cpp in Sources */, F8D94CE02B9ABFE20081A3C4 /* io.cpp in Sources */, F8D94CE12B9ABFE20081A3C4 /* rx.cpp in Sources */, F8D94CE22B9ABFE20081A3C4 /* coex.cpp in Sources */, F8D94CE32B9ABFE20081A3C4 /* tx.cpp in Sources */, F8D94CE42B9ABFE20081A3C4 /* hw.cpp in Sources */, F8D94CE52B9ABFE20081A3C4 /* ItlIwn.cpp in Sources */, F8D94CE62B9ABFE20081A3C4 /* phy.cpp in Sources */, F8D94CE72B9ABFE20081A3C4 /* mac80211.cpp in Sources */, F8D94CE82B9ABFE20081A3C4 /* nvm.cpp in Sources */, F8D94CE92B9ABFE20081A3C4 /* ctxt.cpp in Sources */, F8D94CEA2B9ABFE20081A3C4 /* led.cpp in Sources */, F8D94CEB2B9ABFE20081A3C4 /* power.cpp in Sources */, F8D94CEC2B9ABFE20081A3C4 /* scan.cpp in Sources */, F8D94CED2B9ABFE20081A3C4 /* IOPCIEDeviceWrapper.cpp in Sources */, F8D94CEE2B9ABFE20081A3C4 /* ItlIwm.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 5066D63E252880A700EE6F38 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5066D63825287F7900EE6F38 /* fw_gen */; targetProxy = 5066D63D252880A700EE6F38 /* PBXContainerItemProxy */; }; 5066D640252880AD00EE6F38 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5066D63825287F7900EE6F38 /* fw_gen */; targetProxy = 5066D63F252880AD00EE6F38 /* PBXContainerItemProxy */; }; 5066D6422528814000EE6F38 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5066D63825287F7900EE6F38 /* fw_gen */; targetProxy = 5066D6412528814000EE6F38 /* PBXContainerItemProxy */; }; 5066D6442528814400EE6F38 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5066D63825287F7900EE6F38 /* fw_gen */; targetProxy = 5066D6432528814400EE6F38 /* PBXContainerItemProxy */; }; 5066D6462528814900EE6F38 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5066D63825287F7900EE6F38 /* fw_gen */; targetProxy = 5066D6452528814900EE6F38 /* PBXContainerItemProxy */; }; F897ECB7266EFF93005EE8F7 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5066D63825287F7900EE6F38 /* fw_gen */; targetProxy = F897ECB8266EFF93005EE8F7 /* PBXContainerItemProxy */; }; F8AE64F6285471560085B4CF /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5066D63825287F7900EE6F38 /* fw_gen */; targetProxy = F8AE64F7285471560085B4CF /* PBXContainerItemProxy */; }; F8B210A82A2EC2680043ECBD /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5066D63825287F7900EE6F38 /* fw_gen */; targetProxy = F8B210A92A2EC2680043ECBD /* PBXContainerItemProxy */; }; F8D94C812B9ABFE20081A3C4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5066D63825287F7900EE6F38 /* fw_gen */; targetProxy = F8D94C822B9ABFE20081A3C4 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 024A07B423FCBC3C009FBA6C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = x86_64; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = c11; GCC_DYNAMIC_NO_PIC = NO; GCC_INPUT_FILETYPE = sourcecode.cpp.cpp; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", "ITLWM_VERSION=\\\"${MODULE_VERSION}\\\"", "GIT_COMMIT=\\\"${GIT_COMMIT}\\\"", IEEE80211_STA_ONLY, ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GIT_COMMIT = ""; KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; MACOSX_DEPLOYMENT_TARGET = 10.12; MODULE_VERSION = 2.4.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; OTHER_CPLUSPLUSFLAGS = ( "-Wno-deprecated-register", "$(OTHER_CFLAGS)", ); SDKROOT = macosx; }; name = Debug; }; 024A07B523FCBC3C009FBA6C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = x86_64; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = c11; GCC_INPUT_FILETYPE = sourcecode.cpp.cpp; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "ITLWM_VERSION=\\\"${MODULE_VERSION}\\\"", "GIT_COMMIT=\\\"${GIT_COMMIT}\\\"", IEEE80211_STA_ONLY, ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GIT_COMMIT = ""; KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; MACOSX_DEPLOYMENT_TARGET = 10.12; MODULE_VERSION = 2.4.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; OTHER_CPLUSPLUSFLAGS = ( "-Wno-deprecated-register", "$(OTHER_CFLAGS)", ); SDKROOT = macosx; }; name = Release; }; 024A07B723FCBC3C009FBA6C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", __PRIVATE_SPI__, ); INFOPLIST_FILE = itlwm/Info.plist; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/itl80211", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.9; MODULE_NAME = com.zxystd.itlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.itlwm; PRODUCT_NAME = "$(TARGET_NAME)"; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Debug; }; 024A07B823FCBC3C009FBA6C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { FRAMEWORK_SEARCH_PATHS = ""; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( __PRIVATE_SPI__, "$(inherited)", ); INFOPLIST_FILE = itlwm/Info.plist; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/itl80211", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.9; MODULE_NAME = com.zxystd.itlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.itlwm; PRODUCT_NAME = "$(TARGET_NAME)"; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Release; }; 35CBE6B8251CB89700435CBC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Big Sur"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", USE_APPLE_SUPPLICANT, AIRPORT, "__IO80211_TARGET=__MAC_11_0", __PRIVATE_SPI__, ); INFOPLIST_FILE = AirportItlwm/Info.plist; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Debug; }; 35CBE6B9251CB89700435CBC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Big Sur"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "__IO80211_TARGET=__MAC_11_0", USE_APPLE_SUPPLICANT, AIRPORT, __PRIVATE_SPI__, "$(inherited)", ); INFOPLIST_FILE = AirportItlwm/Info.plist; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Release; }; 35CBE722251CB8BF00435CBC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Mojave"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", USE_APPLE_SUPPLICANT, AIRPORT, "__IO80211_TARGET=__MAC_10_14", __PRIVATE_SPI__, ); INFOPLIST_FILE = AirportItlwm/Info.plist; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.14; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Debug; }; 35CBE723251CB8BF00435CBC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Mojave"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( USE_APPLE_SUPPLICANT, AIRPORT, "__IO80211_TARGET=__MAC_10_14", __PRIVATE_SPI__, "$(inherited)", ); INFOPLIST_FILE = AirportItlwm/Info.plist; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.14; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Release; }; 35CBE78D251CB8CA00435CBC /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/High Sierra"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", USE_APPLE_SUPPLICANT, AIRPORT, "__IO80211_TARGET=__MAC_10_13", __PRIVATE_SPI__, ); INFOPLIST_FILE = AirportItlwm/Info.plist; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.13; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Debug; }; 35CBE78E251CB8CA00435CBC /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/High Sierra"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "__IO80211_TARGET=__MAC_10_13", USE_APPLE_SUPPLICANT, AIRPORT, __PRIVATE_SPI__, "$(inherited)", ); INFOPLIST_FILE = AirportItlwm/Info.plist; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.13; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Release; }; 5066D63925287F7900EE6F38 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Debug; }; 5066D63A25287F7900EE6F38 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Release; }; F897ED16266EFF93005EE8F7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Monterey"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", USE_APPLE_SUPPLICANT, AIRPORT, "__IO80211_TARGET=__MAC_12_0", __PRIVATE_SPI__, ); INFOPLIST_FILE = "AirportItlwm/AirportItlwm-Monterey-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Debug; }; F897ED17266EFF93005EE8F7 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Monterey"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "__IO80211_TARGET=__MAC_12_0", USE_APPLE_SUPPLICANT, AIRPORT, __PRIVATE_SPI__, "$(inherited)", ); INFOPLIST_FILE = "AirportItlwm/AirportItlwm-Monterey-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Release; }; F89B6BC125021C9C000F77FF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Catalina"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", USE_APPLE_SUPPLICANT, AIRPORT, "__IO80211_TARGET=__MAC_10_15", __PRIVATE_SPI__, ); INFOPLIST_FILE = AirportItlwm/Info.plist; KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Debug; }; F89B6BC225021C9C000F77FF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Catalina"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( USE_APPLE_SUPPLICANT, AIRPORT, "__IO80211_TARGET=__MAC_10_15", __PRIVATE_SPI__, "$(inherited)", ); INFOPLIST_FILE = AirportItlwm/Info.plist; KERNEL_EXTENSION_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; KERNEL_FRAMEWORK_HEADERS = "$(PROJECT_DIR)/MacKernelSDK/Headers"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Release; }; F8AE6556285471560085B4CF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Ventura"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", USE_APPLE_SUPPLICANT, AIRPORT, "__IO80211_TARGET=__MAC_13_0", __PRIVATE_SPI__, ); INFOPLIST_FILE = "AirportItlwm/AirportItlwm-Monterey-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Debug; }; F8AE6557285471560085B4CF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Ventura"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "__IO80211_TARGET=__MAC_13_0", USE_APPLE_SUPPLICANT, AIRPORT, __PRIVATE_SPI__, "$(inherited)", ); INFOPLIST_FILE = "AirportItlwm/AirportItlwm-Monterey-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Release; }; F8B211082A2EC2680043ECBD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Sonoma14.0"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", AIRPORT, "__IO80211_TARGET=__MAC_14_0", __PRIVATE_SPI__, IO80211FAMILY_V2, ); INFOPLIST_FILE = "AirportItlwm/AirportItlwm-Sonoma-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Debug; }; F8B211092A2EC2680043ECBD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Sonoma14.0"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "__IO80211_TARGET=__MAC_14_0", AIRPORT, __PRIVATE_SPI__, "$(inherited)", IO80211FAMILY_V2, ); INFOPLIST_FILE = "AirportItlwm/AirportItlwm-Sonoma-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Release; }; F8D94CF32B9ABFE20081A3C4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Sonoma14.4"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", AIRPORT, "__IO80211_TARGET=__MAC_14_4", __PRIVATE_SPI__, IO80211FAMILY_V2, ); INFOPLIST_FILE = "AirportItlwm/AirportItlwm-Sonoma-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_MODULE_NAME = AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Debug; }; F8D94CF42B9ABFE20081A3C4 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)/$(CONFIGURATION)/Sonoma14.4"; CURRENT_PROJECT_VERSION = "$(MODULE_VERSION)"; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = itlwm/PrivateSPI.pch; GCC_PREPROCESSOR_DEFINITIONS = ( "__IO80211_TARGET=__MAC_14_4", AIRPORT, __PRIVATE_SPI__, "$(inherited)", IO80211FAMILY_V2, ); INFOPLIST_FILE = "AirportItlwm/AirportItlwm-Sonoma-Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(PROJECT_DIR)/itl80211", "$(inherited)", "$(PROJECT_DIR)/itl80211/openbsd", "$(PROJECT_DIR)/itl80211/linux", "$(PROJECT_DIR)/MacKernelSDK/Library/x86_64", ); MACOSX_DEPLOYMENT_TARGET = 10.15; MODULE_NAME = com.zxystd.AirportItlwm; PRODUCT_BUNDLE_IDENTIFIER = com.zxystd.AirportItlwm; PRODUCT_MODULE_NAME = AirportItlwm; PRODUCT_NAME = AirportItlwm; SYSTEM_HEADER_SEARCH_PATHS = "itl80211/openbsd itl80211 include"; WRAPPER_EXTENSION = kext; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 024A07A623FCBC3C009FBA6C /* Build configuration list for PBXProject "itlwm" */ = { isa = XCConfigurationList; buildConfigurations = ( 024A07B423FCBC3C009FBA6C /* Debug */, 024A07B523FCBC3C009FBA6C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 024A07B623FCBC3C009FBA6C /* Build configuration list for PBXNativeTarget "itlwm" */ = { isa = XCConfigurationList; buildConfigurations = ( 024A07B723FCBC3C009FBA6C /* Debug */, 024A07B823FCBC3C009FBA6C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 35CBE6B7251CB89700435CBC /* Build configuration list for PBXNativeTarget "AirportItlwm-Big Sur" */ = { isa = XCConfigurationList; buildConfigurations = ( 35CBE6B8251CB89700435CBC /* Debug */, 35CBE6B9251CB89700435CBC /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 35CBE721251CB8BF00435CBC /* Build configuration list for PBXNativeTarget "AirportItlwm-Mojave" */ = { isa = XCConfigurationList; buildConfigurations = ( 35CBE722251CB8BF00435CBC /* Debug */, 35CBE723251CB8BF00435CBC /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 35CBE78C251CB8CA00435CBC /* Build configuration list for PBXNativeTarget "AirportItlwm-High Sierra" */ = { isa = XCConfigurationList; buildConfigurations = ( 35CBE78D251CB8CA00435CBC /* Debug */, 35CBE78E251CB8CA00435CBC /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 5066D63B25287F7900EE6F38 /* Build configuration list for PBXAggregateTarget "fw_gen" */ = { isa = XCConfigurationList; buildConfigurations = ( 5066D63925287F7900EE6F38 /* Debug */, 5066D63A25287F7900EE6F38 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; F897ED15266EFF93005EE8F7 /* Build configuration list for PBXNativeTarget "AirportItlwm-Monterey" */ = { isa = XCConfigurationList; buildConfigurations = ( F897ED16266EFF93005EE8F7 /* Debug */, F897ED17266EFF93005EE8F7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; F89B6BC025021C9C000F77FF /* Build configuration list for PBXNativeTarget "AirportItlwm-Catalina" */ = { isa = XCConfigurationList; buildConfigurations = ( F89B6BC125021C9C000F77FF /* Debug */, F89B6BC225021C9C000F77FF /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; F8AE6555285471560085B4CF /* Build configuration list for PBXNativeTarget "AirportItlwm-Ventura" */ = { isa = XCConfigurationList; buildConfigurations = ( F8AE6556285471560085B4CF /* Debug */, F8AE6557285471560085B4CF /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; F8B211072A2EC2680043ECBD /* Build configuration list for PBXNativeTarget "AirportItlwm-Sonoma14.0" */ = { isa = XCConfigurationList; buildConfigurations = ( F8B211082A2EC2680043ECBD /* Debug */, F8B211092A2EC2680043ECBD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; F8D94CF22B9ABFE20081A3C4 /* Build configuration list for PBXNativeTarget "AirportItlwm-Sonoma14.4" */ = { isa = XCConfigurationList; buildConfigurations = ( F8D94CF32B9ABFE20081A3C4 /* Debug */, F8D94CF42B9ABFE20081A3C4 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 024A07A323FCBC3C009FBA6C /* Project object */; } ================================================ FILE: itlwm.xcodeproj/xcshareddata/xcschemes/AirportItlwm (all).xcscheme ================================================ ================================================ FILE: itlwm.xcodeproj/xcshareddata/xcschemes/itlwm.xcscheme ================================================ ================================================ FILE: iwlwifi-firmware-license ================================================ Copyright (c) 2006-2021, Intel Corporation. All rights reserved. Redistribution. Redistribution and use in binary form, without modification, are permitted provided that the following conditions are met: * Redistributions must reproduce the above copyright notice and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Intel Corporation nor the names of its suppliers may be used to endorse or promote products derived from this software without specific prior written permission. * No reverse engineering, decompilation, or disassembly of this software is permitted. Limited patent license. Intel Corporation grants a world-wide, royalty-free, non-exclusive license under patents it now or hereafter owns or controls to make, have made, use, import, offer to sell and sell ("Utilize") this software, but solely to the extent that any such patent is necessary to Utilize the software alone, or in combination with an operating system licensed under an approved Open Source license as listed by the Open Source Initiative at http://opensource.org/licenses. The patent license shall not apply to any other combinations which include this software. No hardware per se is licensed hereunder. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: scripts/fw_gen.sh ================================================ #!/bin/sh # fw_gen.sh # itlwm # # Created by qcwap on 2020/3/10. # Copyright © 2020 钟先耀. All rights reserved. target_file="${PROJECT_DIR}/include/FwBinary.cpp" if [ -f "$target_file" ]; then exit 0 fi while [ $# -gt 0 ]; do case $1 in -P) fw_files=$2 shift ;; esac shift done script_file="${PROJECT_DIR}/scripts/zlib_compress_fw.py" python3 "${script_file}" "${target_file}" "${fw_files}" ================================================ FILE: scripts/load.sh ================================================ sudo kextunload -b com.zxystd.itlwm sudo chown -R root:wheel ./../Build/Products/Debug/itlwm.kext sudo kextutil -v 6 ./../Build/Products/Debug/itlwm.kext ================================================ FILE: scripts/unload.sh ================================================ sudo kextunload ../Build/Products/Debug/itlwm.kext sudo kextunload -b com.zxystd.itlwm ================================================ FILE: scripts/zlib_compress_fw.py ================================================ #!/usr/bin/python # -*- coding: utf-8 -*- # zlib_compress_fw.py # # Created by qcwap on 2020/9/3. # Copyright © 2020 钟先耀. All rights reserved. import zlib import os import struct import sys copyright = ''' // itlwm // // Copyright © 2020 钟先耀. All rights reserved. #include "FwData.h" ''' def compress(data): return zlib.compress(data) def format_file_name(file_name): return file_name.replace(".", "_").replace("-", "_") def write_single_file(target_file, path, file): src_file = open(path, "rb") src_data = src_file.read() src_data = compress(src_data) src_len = len(src_data) fw_var_name = format_file_name(file) target_file.write("\nconst unsigned char ") target_file.write(fw_var_name) target_file.write("[] = {") index = 0; block = [] while True: if index + 16 >= src_len: block = src_data[index:] else: block = src_data[index:index + 16] index += 16; if len(block) < 16: if len(block): for b in block: if type(b) is str: b = ord(b) target_file.write("0x{:02X}, ".format(b)) target_file.write("\n") break target_file.write("0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, " "0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, " "0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, " "0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X},\n" .format(*struct.unpack("BBBBBBBBBBBBBBBB", block))) target_file.write("};\n") target_file.write("const long int ") target_file.write(fw_var_name) target_file.write("_size = sizeof(") target_file.write(fw_var_name) target_file.write(");\n") src_file.close() def process_files(target_file, dir): if not os.path.exists(target_file): if not os.path.exists(os.path.dirname(target_file)): os.mkdirs(os.path.dirname(target_file)) target_file_handle = open(target_file, "w") target_file_handle.write(copyright) for root, dirs, files in os.walk(dir): for file in files: path = os.path.join(root, file) write_single_file(target_file_handle, path, file) target_file_handle.write("\n") target_file_handle.write("const struct FwDesc fwList[] = {") for file in files: target_file_handle.write('{IWL_FW("') target_file_handle.write(file) target_file_handle.write('", ') fw_var_name = format_file_name(file) target_file_handle.write(fw_var_name) target_file_handle.write(", ") target_file_handle.write(fw_var_name) target_file_handle.write("_size)},\n") target_file_handle.write("};\n") target_file_handle.write("const int fwNumber = ") target_file_handle.write(str(len(files))) target_file_handle.write(";\n") target_file_handle.close() if __name__ == '__main__': process_files(sys.argv[1], sys.argv[2])